@naeil/ui 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/contracts/naeil-chrome.v1.json +12 -0
- package/dist/chunk-HSTDPY56.js +74 -0
- package/dist/chunk-OLKTEYLS.js +413 -0
- package/dist/{chunk-CE73AEJZ.js → chunk-QQQQZEPV.js} +249 -3
- package/dist/{chunk-VL7FS4QM.js → chunk-VWIUN35X.js} +4 -343
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.js +10 -8
- package/dist/components/naeil-footer.d.ts +16 -0
- package/dist/components/naeil-footer.js +76 -0
- package/dist/components/naeil-header.d.ts +23 -5
- package/dist/components/naeil-header.js +5 -2
- package/dist/components/ui/index.d.ts +2 -2
- package/dist/components/ui/index.js +6 -6
- package/dist/lib/ui-release.d.ts +1 -0
- package/dist/lib/ui-release.js +1 -0
- package/dist/naeil-header-content-BvISJ4RV.d.ts +4 -0
- package/dist/{navigation-CL10a6Eb.d.ts → navigation-CgPeL9tF.d.ts} +1 -1
- package/dist/{site-footer-B67meCDv.d.ts → site-footer-vXDa_6yr.d.ts} +4 -2
- package/dist/source/components/naeil-footer.d.ts +16 -0
- package/dist/source/components/naeil-footer.js +95 -0
- package/dist/source/components/naeil-header-account.d.ts +26 -0
- package/dist/source/components/naeil-header-account.js +67 -0
- package/dist/source/components/naeil-header.d.ts +2 -1
- package/dist/source/components/naeil-header.js +5 -0
- package/dist/source/components/ui/site-footer.d.ts +4 -2
- package/dist/source/components/ui/site-footer.js +6 -2
- package/dist/source/lib/ui-release.d.ts +6 -0
- package/dist/source/lib/ui-release.js +4 -0
- package/docs/components/README.md +2 -1
- package/docs/components/application-layout.md +8 -7
- package/docs/components/naeil-footer.md +20 -0
- package/docs/components/naeil-header.md +21 -5
- package/docs/components/navigation.md +3 -1
- package/docs/package-release.md +3 -1
- package/package.json +16 -4
- package/src/styles/components.css +35 -0
- package/dist/chunk-QSTGUEEI.js +0 -323
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
import {
|
|
4
|
+
Logo,
|
|
5
|
+
uiRelease
|
|
6
|
+
} from "../chunk-VWIUN35X.js";
|
|
7
|
+
import {
|
|
8
|
+
SiteFooter
|
|
9
|
+
} from "../chunk-HSTDPY56.js";
|
|
10
|
+
import {
|
|
11
|
+
__objRest,
|
|
12
|
+
__spreadProps,
|
|
13
|
+
__spreadValues
|
|
14
|
+
} from "../chunk-JBTDRVZ7.js";
|
|
15
|
+
|
|
16
|
+
// src/components/naeil-footer.tsx
|
|
17
|
+
import { jsx } from "react/jsx-runtime";
|
|
18
|
+
var content = {
|
|
19
|
+
en: { navigation: "Navigation", projects: "Projects", blog: "Blog", social: "Social" },
|
|
20
|
+
ko: { navigation: "\uB124\uBE44\uAC8C\uC774\uC158", projects: "\uD504\uB85C\uC81D\uD2B8", blog: "\uBE14\uB85C\uADF8", social: "\uC18C\uC15C" },
|
|
21
|
+
ja: { navigation: "\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3", projects: "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8", blog: "\u30D6\u30ED\u30B0", social: "\u30BD\u30FC\u30B7\u30E3\u30EB" }
|
|
22
|
+
};
|
|
23
|
+
var NativeLink = (props) => /* @__PURE__ */ jsx("a", __spreadValues({}, props));
|
|
24
|
+
function NaeilFooter(_a) {
|
|
25
|
+
var _b = _a, {
|
|
26
|
+
locale,
|
|
27
|
+
resolveHref = (path) => `https://naeil.dev/${locale}${path === "/" ? "" : path}`,
|
|
28
|
+
variant = "full",
|
|
29
|
+
Link = NativeLink,
|
|
30
|
+
onNavigate
|
|
31
|
+
} = _b, props = __objRest(_b, [
|
|
32
|
+
"locale",
|
|
33
|
+
"resolveHref",
|
|
34
|
+
"variant",
|
|
35
|
+
"Link",
|
|
36
|
+
"onNavigate"
|
|
37
|
+
]);
|
|
38
|
+
const copy = content[locale];
|
|
39
|
+
const home = { id: "brand", label: ".naeil", href: resolveHref("/") };
|
|
40
|
+
return /* @__PURE__ */ jsx(
|
|
41
|
+
SiteFooter,
|
|
42
|
+
__spreadProps(__spreadValues({}, props), {
|
|
43
|
+
variant,
|
|
44
|
+
Link,
|
|
45
|
+
onNavigate,
|
|
46
|
+
"data-naeil-footer": true,
|
|
47
|
+
"data-naeil-ui-version": uiRelease.version,
|
|
48
|
+
"data-naeil-ui-contract": uiRelease.contractVersion,
|
|
49
|
+
brand: /* @__PURE__ */ jsx(
|
|
50
|
+
Link,
|
|
51
|
+
{
|
|
52
|
+
href: home.href,
|
|
53
|
+
"aria-label": ".naeil",
|
|
54
|
+
"data-footer-brand": true,
|
|
55
|
+
className: "ui-focus inline-flex min-h-11 items-center",
|
|
56
|
+
onClick: (event) => onNavigate == null ? void 0 : onNavigate(event, home),
|
|
57
|
+
children: /* @__PURE__ */ jsx(Logo, { variant: "footer", size: 20, label: null })
|
|
58
|
+
}
|
|
59
|
+
),
|
|
60
|
+
description: variant === "full" ? "Tomorrow starts here." : void 0,
|
|
61
|
+
groups: [
|
|
62
|
+
{ id: "navigation", label: copy.navigation, links: [
|
|
63
|
+
{ id: "projects", label: copy.projects, href: resolveHref("/projects") },
|
|
64
|
+
{ id: "blog", label: copy.blog, href: resolveHref("/blog") }
|
|
65
|
+
] },
|
|
66
|
+
{ id: "social", label: copy.social, links: [
|
|
67
|
+
// All canonical destinations use the consumer Link, including this absolute URL.
|
|
68
|
+
{ id: "github", label: "GitHub", href: "https://github.com/naeil-dev", target: "_blank" }
|
|
69
|
+
] }
|
|
70
|
+
]
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
export {
|
|
75
|
+
NaeilFooter
|
|
76
|
+
};
|
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { a as NavigationProps,
|
|
3
|
+
import { b as NavigationLinkComponent, a as NavigationProps, c as NavigationLinkProps, N as NavigationLink } from '../navigation-CgPeL9tF.js';
|
|
4
|
+
import { N as NaeilHeaderLocale } from '../naeil-header-content-BvISJ4RV.js';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
type NaeilHeaderAccount = {
|
|
7
|
+
status: "signed-out";
|
|
8
|
+
loginHref: string;
|
|
9
|
+
} | {
|
|
10
|
+
status: "signed-in";
|
|
11
|
+
/** Consumer starts its guarded session action and owns failures/navigation. */
|
|
12
|
+
onLogout: () => void;
|
|
13
|
+
busy?: boolean;
|
|
14
|
+
displayName?: string;
|
|
15
|
+
email?: string;
|
|
16
|
+
};
|
|
17
|
+
interface NaeilHeaderAccountControlProps {
|
|
18
|
+
locale: NaeilHeaderLocale;
|
|
19
|
+
account: NaeilHeaderAccount;
|
|
20
|
+
/** The same route/save adapter used by the rest of the application header. */
|
|
21
|
+
Link?: NavigationLinkComponent;
|
|
22
|
+
}
|
|
23
|
+
/** Shared account presentation only: never reads sessions or calls an auth API. */
|
|
24
|
+
declare function NaeilHeaderAccountControl({ locale, account, Link }: NaeilHeaderAccountControlProps): react_jsx_runtime.JSX.Element;
|
|
7
25
|
|
|
8
26
|
interface NaeilHeaderProps extends Omit<NavigationProps, "brand" | "items" | "toolbar" | "mobileToolbar" | "labels"> {
|
|
9
27
|
locale: NaeilHeaderLocale;
|
|
@@ -14,7 +32,7 @@ interface NaeilHeaderProps extends Omit<NavigationProps, "brand" | "items" | "to
|
|
|
14
32
|
brandLinkProps?: Omit<NavigationLinkProps, "href" | "children">;
|
|
15
33
|
/** Omit when the application does not support changing its UI language. */
|
|
16
34
|
onLocaleChange?: (locale: NaeilHeaderLocale) => void;
|
|
17
|
-
/**
|
|
35
|
+
/** Use NaeilHeaderAccountControl for canonical UI; the app owns auth state/I/O. */
|
|
18
36
|
authSlot?: ReactNode;
|
|
19
37
|
labels?: NavigationProps["labels"];
|
|
20
38
|
projects?: NavigationLink[];
|
|
@@ -51,4 +69,4 @@ declare function NaeilHeaderLocaleControl({ locale, onLocaleChange }: {
|
|
|
51
69
|
/** One complete, opt-in branded composition shared by naeil.dev and applications. */
|
|
52
70
|
declare function NaeilHeader({ locale, resolveHref, brandHref, brandSlot, brandLinkProps, brandLinkComponent, onLocaleChange, authSlot, toolbarSlot, projects, projectsExternal, translations, showProjects, showBlog, subNav, currentProjectKey, currentProjectHref, labels, Link, currentHref, onNavigate, className, containerClassName, ...props }: NaeilHeaderProps): react_jsx_runtime.JSX.Element;
|
|
53
71
|
|
|
54
|
-
export { NaeilHeader, type NaeilHeaderLocale, NaeilHeaderLocaleControl, type NaeilHeaderProps, NaeilHeaderThemeControl };
|
|
72
|
+
export { NaeilHeader, type NaeilHeaderAccount, NaeilHeaderAccountControl, type NaeilHeaderAccountControlProps, NaeilHeaderLocale, NaeilHeaderLocaleControl, type NaeilHeaderProps, NaeilHeaderThemeControl };
|
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
"use client";
|
|
3
3
|
import {
|
|
4
4
|
NaeilHeader,
|
|
5
|
+
NaeilHeaderAccountControl,
|
|
5
6
|
NaeilHeaderLocaleControl,
|
|
6
7
|
NaeilHeaderThemeControl
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
8
|
+
} from "../chunk-OLKTEYLS.js";
|
|
9
|
+
import "../chunk-VWIUN35X.js";
|
|
10
|
+
import "../chunk-QQQQZEPV.js";
|
|
9
11
|
import "../chunk-JBTDRVZ7.js";
|
|
10
12
|
export {
|
|
11
13
|
NaeilHeader,
|
|
14
|
+
NaeilHeaderAccountControl,
|
|
12
15
|
NaeilHeaderLocaleControl,
|
|
13
16
|
NaeilHeaderThemeControl
|
|
14
17
|
};
|
|
@@ -4,8 +4,8 @@ import { Avatar as Avatar$1, Dialog as Dialog$1, DropdownMenu as DropdownMenu$1,
|
|
|
4
4
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
5
5
|
import { VariantProps } from 'class-variance-authority';
|
|
6
6
|
import { ToasterProps } from 'sonner';
|
|
7
|
-
export { d as Navigation, e as NavigationGroup, f as NavigationItem, N as NavigationLink,
|
|
8
|
-
export { a as SiteFooter, S as SiteFooterProps } from '../../site-footer-
|
|
7
|
+
export { d as Navigation, e as NavigationGroup, f as NavigationItem, N as NavigationLink, b as NavigationLinkComponent, c as NavigationLinkProps, a as NavigationProps } from '../../navigation-CgPeL9tF.js';
|
|
8
|
+
export { a as SiteFooter, S as SiteFooterProps } from '../../site-footer-vXDa_6yr.js';
|
|
9
9
|
|
|
10
10
|
declare function Avatar({ className, size, ...props }: React.ComponentProps<typeof Avatar$1.Root> & {
|
|
11
11
|
size?: "default" | "sm" | "lg";
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
|
+
SiteFooter
|
|
4
|
+
} from "../../chunk-HSTDPY56.js";
|
|
5
|
+
import {
|
|
6
|
+
Badge,
|
|
7
|
+
Button,
|
|
3
8
|
DropdownMenu,
|
|
4
9
|
DropdownMenuCheckboxItem,
|
|
5
10
|
DropdownMenuContent,
|
|
@@ -15,11 +20,6 @@ import {
|
|
|
15
20
|
DropdownMenuSubContent,
|
|
16
21
|
DropdownMenuSubTrigger,
|
|
17
22
|
DropdownMenuTrigger,
|
|
18
|
-
SiteFooter
|
|
19
|
-
} from "../../chunk-QSTGUEEI.js";
|
|
20
|
-
import {
|
|
21
|
-
Badge,
|
|
22
|
-
Button,
|
|
23
23
|
Navigation,
|
|
24
24
|
Select,
|
|
25
25
|
SelectContent,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
SelectValue,
|
|
34
34
|
badgeVariants,
|
|
35
35
|
buttonVariants
|
|
36
|
-
} from "../../chunk-
|
|
36
|
+
} from "../../chunk-QQQQZEPV.js";
|
|
37
37
|
import {
|
|
38
38
|
__objRest,
|
|
39
39
|
__spreadProps,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const uiRelease: Readonly<{version: "0.7.1"; contractVersion: "1"}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const uiRelease = Object.freeze({"version":"0.7.1","contractVersion":"1"});
|
|
@@ -45,4 +45,4 @@ interface NavigationProps extends Omit<React.ComponentPropsWithoutRef<"header">,
|
|
|
45
45
|
}
|
|
46
46
|
declare function Navigation({ brand, items, labels, Link, currentHref, toolbar, mobileToolbar, mobileFooter, containerClassName, onNavigate, className, ...props }: NavigationProps): react_jsx_runtime.JSX.Element;
|
|
47
47
|
|
|
48
|
-
export { type NavigationLink as N, type NavigationProps as a, type
|
|
48
|
+
export { type NavigationLink as N, type NavigationProps as a, type NavigationLinkComponent as b, type NavigationLinkProps as c, Navigation as d, type NavigationGroup as e, type NavigationItem as f };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import { N as NavigationLink,
|
|
3
|
+
import { N as NavigationLink, b as NavigationLinkComponent, a as NavigationProps } from './navigation-CgPeL9tF.js';
|
|
4
4
|
|
|
5
5
|
interface SiteFooterProps extends React.ComponentPropsWithoutRef<"footer"> {
|
|
6
6
|
brand?: React.ReactNode;
|
|
@@ -14,8 +14,10 @@ interface SiteFooterProps extends React.ComponentPropsWithoutRef<"footer"> {
|
|
|
14
14
|
meta?: React.ReactNode;
|
|
15
15
|
containerClassName?: string;
|
|
16
16
|
variant?: "full" | "compact";
|
|
17
|
+
/** Called for every group link, including native external anchors. Preserve modified clicks. */
|
|
18
|
+
onNavigate?: NavigationProps["onNavigate"];
|
|
17
19
|
}
|
|
18
20
|
/** Product content and translations belong to the consumer, including legal copy. */
|
|
19
|
-
declare function SiteFooter({ brand, description, groups, Link, meta, children, containerClassName, className, variant, ...props }: SiteFooterProps): react_jsx_runtime.JSX.Element;
|
|
21
|
+
declare function SiteFooter({ brand, description, groups, Link, meta, children, containerClassName, className, variant, onNavigate, ...props }: SiteFooterProps): react_jsx_runtime.JSX.Element;
|
|
20
22
|
|
|
21
23
|
export { type SiteFooterProps as S, SiteFooter as a };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { SiteFooterProps } from './ui/site-footer.js';
|
|
3
|
+
import { NaeilHeaderLocale } from './naeil-header-content.js';
|
|
4
|
+
import 'react';
|
|
5
|
+
import './ui/navigation.js';
|
|
6
|
+
|
|
7
|
+
type NaeilFooterLocale = NaeilHeaderLocale;
|
|
8
|
+
interface NaeilFooterProps extends Omit<SiteFooterProps, "brand" | "description" | "groups"> {
|
|
9
|
+
locale: NaeilFooterLocale;
|
|
10
|
+
/** Only localize/route canonical paths; default destinations use the official origin. */
|
|
11
|
+
resolveHref?: (path: string) => string;
|
|
12
|
+
}
|
|
13
|
+
/** Canonical content in full/compact density. Product legal/status copy belongs in meta. */
|
|
14
|
+
declare function NaeilFooter({ locale, resolveHref, variant, Link, onNavigate, ...props }: NaeilFooterProps): react_jsx_runtime.JSX.Element;
|
|
15
|
+
|
|
16
|
+
export { NaeilFooter, type NaeilFooterLocale, type NaeilFooterProps };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
8
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
+
var __spreadValues = (a, b) => {
|
|
10
|
+
for (var prop in b || (b = {}))
|
|
11
|
+
if (__hasOwnProp.call(b, prop))
|
|
12
|
+
__defNormalProp(a, prop, b[prop]);
|
|
13
|
+
if (__getOwnPropSymbols)
|
|
14
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
15
|
+
if (__propIsEnum.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
}
|
|
18
|
+
return a;
|
|
19
|
+
};
|
|
20
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
21
|
+
var __objRest = (source, exclude) => {
|
|
22
|
+
var target = {};
|
|
23
|
+
for (var prop in source)
|
|
24
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
25
|
+
target[prop] = source[prop];
|
|
26
|
+
if (source != null && __getOwnPropSymbols)
|
|
27
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
28
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
29
|
+
target[prop] = source[prop];
|
|
30
|
+
}
|
|
31
|
+
return target;
|
|
32
|
+
};
|
|
33
|
+
import { jsx } from "react/jsx-runtime";
|
|
34
|
+
import { Logo } from "./logo.js";
|
|
35
|
+
import { SiteFooter } from "./ui/site-footer.js";
|
|
36
|
+
import { uiRelease } from "../lib/ui-release.js";
|
|
37
|
+
const content = {
|
|
38
|
+
en: { navigation: "Navigation", projects: "Projects", blog: "Blog", social: "Social" },
|
|
39
|
+
ko: { navigation: "\uB124\uBE44\uAC8C\uC774\uC158", projects: "\uD504\uB85C\uC81D\uD2B8", blog: "\uBE14\uB85C\uADF8", social: "\uC18C\uC15C" },
|
|
40
|
+
ja: { navigation: "\u30CA\u30D3\u30B2\u30FC\u30B7\u30E7\u30F3", projects: "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8", blog: "\u30D6\u30ED\u30B0", social: "\u30BD\u30FC\u30B7\u30E3\u30EB" }
|
|
41
|
+
};
|
|
42
|
+
const NativeLink = (props) => /* @__PURE__ */ jsx("a", __spreadValues({}, props));
|
|
43
|
+
function NaeilFooter(_a) {
|
|
44
|
+
var _b = _a, {
|
|
45
|
+
locale,
|
|
46
|
+
resolveHref = (path) => `https://naeil.dev/${locale}${path === "/" ? "" : path}`,
|
|
47
|
+
variant = "full",
|
|
48
|
+
Link = NativeLink,
|
|
49
|
+
onNavigate
|
|
50
|
+
} = _b, props = __objRest(_b, [
|
|
51
|
+
"locale",
|
|
52
|
+
"resolveHref",
|
|
53
|
+
"variant",
|
|
54
|
+
"Link",
|
|
55
|
+
"onNavigate"
|
|
56
|
+
]);
|
|
57
|
+
const copy = content[locale];
|
|
58
|
+
const home = { id: "brand", label: ".naeil", href: resolveHref("/") };
|
|
59
|
+
return /* @__PURE__ */ jsx(
|
|
60
|
+
SiteFooter,
|
|
61
|
+
__spreadProps(__spreadValues({}, props), {
|
|
62
|
+
variant,
|
|
63
|
+
Link,
|
|
64
|
+
onNavigate,
|
|
65
|
+
"data-naeil-footer": true,
|
|
66
|
+
"data-naeil-ui-version": uiRelease.version,
|
|
67
|
+
"data-naeil-ui-contract": uiRelease.contractVersion,
|
|
68
|
+
brand: /* @__PURE__ */ jsx(
|
|
69
|
+
Link,
|
|
70
|
+
{
|
|
71
|
+
href: home.href,
|
|
72
|
+
"aria-label": ".naeil",
|
|
73
|
+
"data-footer-brand": true,
|
|
74
|
+
className: "ui-focus inline-flex min-h-11 items-center",
|
|
75
|
+
onClick: (event) => onNavigate == null ? void 0 : onNavigate(event, home),
|
|
76
|
+
children: /* @__PURE__ */ jsx(Logo, { variant: "footer", size: 20, label: null })
|
|
77
|
+
}
|
|
78
|
+
),
|
|
79
|
+
description: variant === "full" ? "Tomorrow starts here." : void 0,
|
|
80
|
+
groups: [
|
|
81
|
+
{ id: "navigation", label: copy.navigation, links: [
|
|
82
|
+
{ id: "projects", label: copy.projects, href: resolveHref("/projects") },
|
|
83
|
+
{ id: "blog", label: copy.blog, href: resolveHref("/blog") }
|
|
84
|
+
] },
|
|
85
|
+
{ id: "social", label: copy.social, links: [
|
|
86
|
+
// All canonical destinations use the consumer Link, including this absolute URL.
|
|
87
|
+
{ id: "github", label: "GitHub", href: "https://github.com/naeil-dev", target: "_blank" }
|
|
88
|
+
] }
|
|
89
|
+
]
|
|
90
|
+
})
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
NaeilFooter
|
|
95
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { NavigationLinkComponent } from './ui/navigation.js';
|
|
3
|
+
import { NaeilHeaderLocale } from './naeil-header-content.js';
|
|
4
|
+
import 'react';
|
|
5
|
+
|
|
6
|
+
type NaeilHeaderAccount = {
|
|
7
|
+
status: "signed-out";
|
|
8
|
+
loginHref: string;
|
|
9
|
+
} | {
|
|
10
|
+
status: "signed-in";
|
|
11
|
+
/** Consumer starts its guarded session action and owns failures/navigation. */
|
|
12
|
+
onLogout: () => void;
|
|
13
|
+
busy?: boolean;
|
|
14
|
+
displayName?: string;
|
|
15
|
+
email?: string;
|
|
16
|
+
};
|
|
17
|
+
interface NaeilHeaderAccountControlProps {
|
|
18
|
+
locale: NaeilHeaderLocale;
|
|
19
|
+
account: NaeilHeaderAccount;
|
|
20
|
+
/** The same route/save adapter used by the rest of the application header. */
|
|
21
|
+
Link?: NavigationLinkComponent;
|
|
22
|
+
}
|
|
23
|
+
/** Shared account presentation only: never reads sessions or calls an auth API. */
|
|
24
|
+
declare function NaeilHeaderAccountControl({ locale, account, Link }: NaeilHeaderAccountControlProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
|
|
26
|
+
export { type NaeilHeaderAccount, NaeilHeaderAccountControl, type NaeilHeaderAccountControlProps };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
6
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
+
var __spreadValues = (a, b) => {
|
|
8
|
+
for (var prop in b || (b = {}))
|
|
9
|
+
if (__hasOwnProp.call(b, prop))
|
|
10
|
+
__defNormalProp(a, prop, b[prop]);
|
|
11
|
+
if (__getOwnPropSymbols)
|
|
12
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
13
|
+
if (__propIsEnum.call(b, prop))
|
|
14
|
+
__defNormalProp(a, prop, b[prop]);
|
|
15
|
+
}
|
|
16
|
+
return a;
|
|
17
|
+
};
|
|
18
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
+
import { UserRound } from "lucide-react";
|
|
20
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuItem } from "./ui/dropdown-menu.js";
|
|
21
|
+
const labels = {
|
|
22
|
+
en: { menu: "Account menu", account: "Account", login: "Log in", logout: "Log out", busy: "Logging out\u2026" },
|
|
23
|
+
ko: { menu: "\uACC4\uC815 \uBA54\uB274", account: "\uACC4\uC815", login: "\uB85C\uADF8\uC778", logout: "\uB85C\uADF8\uC544\uC6C3", busy: "\uB85C\uADF8\uC544\uC6C3 \uC911\u2026" },
|
|
24
|
+
ja: { menu: "\u30A2\u30AB\u30A6\u30F3\u30C8\u30E1\u30CB\u30E5\u30FC", account: "\u30A2\u30AB\u30A6\u30F3\u30C8", login: "\u30ED\u30B0\u30A4\u30F3", logout: "\u30ED\u30B0\u30A2\u30A6\u30C8", busy: "\u30ED\u30B0\u30A2\u30A6\u30C8\u4E2D\u2026" }
|
|
25
|
+
};
|
|
26
|
+
const NativeLink = (props) => /* @__PURE__ */ jsx("a", __spreadValues({}, props));
|
|
27
|
+
function NaeilHeaderAccountControl({ locale, account, Link = NativeLink }) {
|
|
28
|
+
const text = labels[locale];
|
|
29
|
+
if (account.status === "signed-out") {
|
|
30
|
+
return /* @__PURE__ */ jsx(Link, { href: account.loginHref, className: "ui-navigation-link ui-focus naeil-header-login", "data-naeil-account-state": "signed-out", children: text.login });
|
|
31
|
+
}
|
|
32
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
33
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
34
|
+
"button",
|
|
35
|
+
{
|
|
36
|
+
type: "button",
|
|
37
|
+
className: "ui-focus naeil-header-account-trigger",
|
|
38
|
+
"data-naeil-account-trigger": true,
|
|
39
|
+
"data-naeil-account-state": "signed-in",
|
|
40
|
+
"aria-label": text.menu,
|
|
41
|
+
"aria-busy": account.busy || void 0,
|
|
42
|
+
children: /* @__PURE__ */ jsx("span", { className: "naeil-header-account-avatar", "aria-hidden": "true", children: /* @__PURE__ */ jsx(UserRound, {}) })
|
|
43
|
+
}
|
|
44
|
+
) }),
|
|
45
|
+
/* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-56 max-w-[calc(100vw-2rem)]", "data-naeil-account-menu": true, children: [
|
|
46
|
+
/* @__PURE__ */ jsxs(DropdownMenuLabel, { className: "flex min-w-0 flex-col font-normal", children: [
|
|
47
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-base font-medium", children: account.displayName || text.account }),
|
|
48
|
+
account.email && /* @__PURE__ */ jsx("span", { className: "truncate text-sm text-muted-foreground", children: account.email })
|
|
49
|
+
] }),
|
|
50
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
51
|
+
/* @__PURE__ */ jsx(
|
|
52
|
+
DropdownMenuItem,
|
|
53
|
+
{
|
|
54
|
+
className: "min-h-11",
|
|
55
|
+
disabled: account.busy,
|
|
56
|
+
onSelect: () => {
|
|
57
|
+
if (!account.busy) account.onLogout();
|
|
58
|
+
},
|
|
59
|
+
children: account.busy ? text.busy : text.logout
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
] })
|
|
63
|
+
] });
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
NaeilHeaderAccountControl
|
|
67
|
+
};
|
|
@@ -2,6 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { NavigationProps, NavigationLinkProps, NavigationLink, NavigationLinkComponent } from './ui/navigation.js';
|
|
4
4
|
import { NaeilHeaderLocale } from './naeil-header-content.js';
|
|
5
|
+
export { NaeilHeaderAccount, NaeilHeaderAccountControl, NaeilHeaderAccountControlProps } from './naeil-header-account.js';
|
|
5
6
|
|
|
6
7
|
interface NaeilHeaderProps extends Omit<NavigationProps, "brand" | "items" | "toolbar" | "mobileToolbar" | "labels"> {
|
|
7
8
|
locale: NaeilHeaderLocale;
|
|
@@ -12,7 +13,7 @@ interface NaeilHeaderProps extends Omit<NavigationProps, "brand" | "items" | "to
|
|
|
12
13
|
brandLinkProps?: Omit<NavigationLinkProps, "href" | "children">;
|
|
13
14
|
/** Omit when the application does not support changing its UI language. */
|
|
14
15
|
onLocaleChange?: (locale: NaeilHeaderLocale) => void;
|
|
15
|
-
/**
|
|
16
|
+
/** Use NaeilHeaderAccountControl for canonical UI; the app owns auth state/I/O. */
|
|
16
17
|
authSlot?: ReactNode;
|
|
17
18
|
labels?: NavigationProps["labels"];
|
|
18
19
|
projects?: NavigationLink[];
|
|
@@ -40,7 +40,9 @@ import { Button } from "./ui/button.js";
|
|
|
40
40
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select.js";
|
|
41
41
|
import { Navigation } from "./ui/navigation.js";
|
|
42
42
|
import { cn } from "../lib/utils.js";
|
|
43
|
+
import { uiRelease } from "../lib/ui-release.js";
|
|
43
44
|
import { headerContent, headerLocales, headerLocaleNames, headerProjects } from "./naeil-header-content.js";
|
|
45
|
+
import { NaeilHeaderAccountControl } from "./naeil-header-account.js";
|
|
44
46
|
const subscribe = () => () => {
|
|
45
47
|
};
|
|
46
48
|
function NaeilHeaderThemeControl({ locale }) {
|
|
@@ -159,6 +161,8 @@ function NaeilHeader(_a) {
|
|
|
159
161
|
__spreadProps(__spreadValues({}, props), {
|
|
160
162
|
"data-global-header": true,
|
|
161
163
|
"data-naeil-header": true,
|
|
164
|
+
"data-naeil-ui-version": uiRelease.version,
|
|
165
|
+
"data-naeil-ui-contract": uiRelease.contractVersion,
|
|
162
166
|
Link,
|
|
163
167
|
currentHref,
|
|
164
168
|
onNavigate,
|
|
@@ -191,6 +195,7 @@ function NaeilHeader(_a) {
|
|
|
191
195
|
}
|
|
192
196
|
export {
|
|
193
197
|
NaeilHeader,
|
|
198
|
+
NaeilHeaderAccountControl,
|
|
194
199
|
NaeilHeaderLocaleControl,
|
|
195
200
|
NaeilHeaderThemeControl
|
|
196
201
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
|
-
import { NavigationLink, NavigationLinkComponent } from './navigation.js';
|
|
3
|
+
import { NavigationLink, NavigationLinkComponent, NavigationProps } from './navigation.js';
|
|
4
4
|
|
|
5
5
|
interface SiteFooterProps extends react.ComponentPropsWithoutRef<"footer"> {
|
|
6
6
|
brand?: react.ReactNode;
|
|
@@ -14,8 +14,10 @@ interface SiteFooterProps extends react.ComponentPropsWithoutRef<"footer"> {
|
|
|
14
14
|
meta?: react.ReactNode;
|
|
15
15
|
containerClassName?: string;
|
|
16
16
|
variant?: "full" | "compact";
|
|
17
|
+
/** Called for every group link, including native external anchors. Preserve modified clicks. */
|
|
18
|
+
onNavigate?: NavigationProps["onNavigate"];
|
|
17
19
|
}
|
|
18
20
|
/** Product content and translations belong to the consumer, including legal copy. */
|
|
19
|
-
declare function SiteFooter({ brand, description, groups, Link, meta, children, containerClassName, className, variant, ...props }: SiteFooterProps): react_jsx_runtime.JSX.Element;
|
|
21
|
+
declare function SiteFooter({ brand, description, groups, Link, meta, children, containerClassName, className, variant, onNavigate, ...props }: SiteFooterProps): react_jsx_runtime.JSX.Element;
|
|
20
22
|
|
|
21
23
|
export { SiteFooter, type SiteFooterProps };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
var __defProp = Object.defineProperty;
|
|
2
3
|
var __defProps = Object.defineProperties;
|
|
3
4
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
@@ -41,7 +42,8 @@ function SiteFooter(_a) {
|
|
|
41
42
|
children,
|
|
42
43
|
containerClassName,
|
|
43
44
|
className,
|
|
44
|
-
variant = "full"
|
|
45
|
+
variant = "full",
|
|
46
|
+
onNavigate
|
|
45
47
|
} = _b, props = __objRest(_b, [
|
|
46
48
|
"brand",
|
|
47
49
|
"description",
|
|
@@ -51,7 +53,8 @@ function SiteFooter(_a) {
|
|
|
51
53
|
"children",
|
|
52
54
|
"containerClassName",
|
|
53
55
|
"className",
|
|
54
|
-
"variant"
|
|
56
|
+
"variant",
|
|
57
|
+
"onNavigate"
|
|
55
58
|
]);
|
|
56
59
|
return /* @__PURE__ */ jsx(
|
|
57
60
|
"footer",
|
|
@@ -77,6 +80,7 @@ function SiteFooter(_a) {
|
|
|
77
80
|
target: item.target,
|
|
78
81
|
rel: item.target === "_blank" ? "noopener noreferrer" : void 0,
|
|
79
82
|
className: "ui-site-footer-link ui-focus",
|
|
83
|
+
onClick: (event) => onNavigate == null ? void 0 : onNavigate(event, item),
|
|
80
84
|
children: item.label
|
|
81
85
|
},
|
|
82
86
|
item.id
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Component usage guides
|
|
2
2
|
|
|
3
|
-
These guides
|
|
3
|
+
These guides include the unpublished **@naeil/ui 0.7.0 candidate**; the last published release is 0.6.0. release identities and publication evidence are recorded in the [release record](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.6.0). [Setup, themes, fonts and shared responsibilities](common.md). Run `pnpm storybook` for the current 17 Docs pages (15 UI and 2 Brand) and choose Docs or Usage. The [hosted Storybook](https://naeil-dev.github.io/naeil-ui/) was last verified for [0.5.0 on 2026-10-15](https://github.com/naeil-dev/naeil-ui/releases/tag/v0.5.0); each subsequent deployment is recorded separately. Select chooses a value; DropdownMenu chooses an action.
|
|
4
4
|
|
|
5
5
|
Start application layouts with the [shared navigation/footer selection and frame guide](application-layout.md). It includes a starter, the 1600px frame contract and instructions to place in consumer repositories so agents reuse the shared implementation.
|
|
6
6
|
|
|
@@ -21,6 +21,7 @@ Start application layouts with the [shared navigation/footer selection and frame
|
|
|
21
21
|
| Textarea | [Textarea](./textarea.md) | UI / Textarea / Usage |
|
|
22
22
|
| Navigation | [Navigation](./navigation.md) | UI / Navigation / Usage |
|
|
23
23
|
| SiteFooter | [SiteFooter](./navigation.md) | UI / SiteFooter / Usage |
|
|
24
|
+
| NaeilFooter | [NaeilFooter](./naeil-footer.md) | Brand / NaeilHeader / ReferenceFull, ReferenceCompact |
|
|
24
25
|
| NaeilHeader | [NaeilHeader](./naeil-header.md) | Brand / NaeilHeader / Usage, JapaneseApplication |
|
|
25
26
|
|
|
26
27
|
[Field, native radio, Select and action composition](./composition.md) explains consumer state and semantic choices. [Demand decision](../design/component-demand.md) records why these two families were added.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Application frame and shared navigation/footer
|
|
2
2
|
|
|
3
|
-
This guide targets the **@naeil/ui 0.
|
|
3
|
+
This guide targets the **@naeil/ui 0.7.0 candidate**, including the width update approved on 2026-10-16. Use the matching registry release or tested local archive. See [consumer setup](../design/v2-migration.md) for CSS, Tailwind sources and fonts.
|
|
4
4
|
|
|
5
5
|
## Choose the shared composition first
|
|
6
6
|
|
|
@@ -8,7 +8,8 @@ This guide targets the **@naeil/ui 0.6.0**, including the width update approved
|
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| The actual naeil.dev brand, project catalog and controls | `NaeilHeader` from `@naeil/ui/naeil-header` |
|
|
10
10
|
| A product's own menu | `Navigation` from `@naeil/ui/ui` |
|
|
11
|
-
|
|
|
11
|
+
| Owned naeil service footer | `NaeilFooter` from `@naeil/ui/naeil-footer` |
|
|
12
|
+
| Different product footer or explicit content override | `SiteFooter` from `@naeil/ui/ui` |
|
|
12
13
|
| An existing Next/next-intl consumer | Keep its `Nav` / `Footer` adapters |
|
|
13
14
|
|
|
14
15
|
Choose one header per application frame. Supply menu data, links, route guards, authentication and supported locale state through props/slots. Local adapters are appropriate; copies of the menu, responsive sheet, controls or footer implementation are not. Extend the shared component when a reusable behavior is missing.
|
|
@@ -39,8 +40,7 @@ This keeps a centered frame from shifting when a classic scrollbar appears. The
|
|
|
39
40
|
```tsx
|
|
40
41
|
import type { ReactNode } from "react";
|
|
41
42
|
import { NaeilHeader } from "@naeil/ui/naeil-header";
|
|
42
|
-
import {
|
|
43
|
-
import { Logo } from "@naeil/ui/components/logo";
|
|
43
|
+
import { NaeilFooter } from "@naeil/ui/naeil-footer";
|
|
44
44
|
|
|
45
45
|
// Render inside the existing next-themes ThemeProvider.
|
|
46
46
|
// Connect Link/onNavigate, locale and authSlot to real application state.
|
|
@@ -51,8 +51,7 @@ export function ApplicationLayout({ children }: { children: ReactNode }) {
|
|
|
51
51
|
style={{ marginTop: "calc(var(--ui-navigation-height) + 1px)" }}>
|
|
52
52
|
{children}
|
|
53
53
|
</main>
|
|
54
|
-
<
|
|
55
|
-
brand={<Logo variant="footer" size={20} />} />
|
|
54
|
+
<NaeilFooter locale="en" variant="compact" />
|
|
56
55
|
</>;
|
|
57
56
|
}
|
|
58
57
|
|
|
@@ -88,7 +87,7 @@ Put this in the **consumer application's** `AGENTS.md` (or equivalent repository
|
|
|
88
87
|
```markdown
|
|
89
88
|
## Shared application layout
|
|
90
89
|
- Read the installed @naeil/ui/DESIGN.md and docs/components/application-layout.md before UI layout work.
|
|
91
|
-
- Use @naeil/ui/naeil-header for the canonical naeil header; use Navigation from @naeil/ui/ui for a different product menu. Use
|
|
90
|
+
- Use @naeil/ui/naeil-header for the canonical naeil header; use Navigation from @naeil/ui/ui for a different product menu. Use NaeilFooter from @naeil/ui/naeil-footer for owned service footers; SiteFooter remains the generic primitive. Keep existing Next Nav/Footer compatibility adapters when applicable.
|
|
92
91
|
- Local wrappers supply menu data, routing/guards, locale, auth and slots. Do not copy the menu, mobile sheet, controls or footer implementation. Extend the shared component for reusable missing behavior.
|
|
93
92
|
- Use ui-app-frame on main; navigation/footer own their internal frames. Keep reading/settings/short-form sections inside that frame. Apply frame overrides consistently across routes.
|
|
94
93
|
- Check the installed package version and CSS before creating a replacement for an apparently missing component.
|
|
@@ -100,3 +99,5 @@ Put this in the **consumer application's** `AGENTS.md` (or equivalent repository
|
|
|
100
99
|
For each consumer, record its installed version, layout adapter, shared imports, CSS entrypoints and intentional exceptions. In that consumer's browser CI, check that expected application routes render `[data-slot="navigation"]` and `[data-slot="site-footer"]`, and that anchors remain stable between wide lists and narrow forms. Include narrow/zoomed screens, localized labels and tall content that introduces a scrollbar. Keep table overflow local.
|
|
101
100
|
|
|
102
101
|
A blanket ban on `<header>`, `<nav>` or `<footer>` would also reject valid section landmarks and adapters. Review the root composition and its rendered output instead. This repository checks packed React/Next examples; external applications still need their own upgrades, adapter migrations and CI. Publication and deployment are separate work.
|
|
102
|
+
|
|
103
|
+
See [canonical footer content and save interception](naeil-footer.md). 0.7.0 candidate adds package/contract identity; publication and per-service operational rollout are separate.
|