@kids-reporter/routing-ui 0.1.0-alpha.5 → 0.1.0-alpha.7
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/dist/components/input.d.ts +6 -2
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +30 -9
- package/dist/components/input.js.map +1 -1
- package/dist/header/shared-components.d.ts.map +1 -1
- package/dist/header/shared-components.js +2 -1
- package/dist/header/shared-components.js.map +1 -1
- package/dist/styles.css +11 -0
- package/package.json +6 -5
- package/.prettierignore +0 -17
- package/babel.config.cjs +0 -31
- package/eslint.config.mjs +0 -56
- package/prettier.config.mjs +0 -13
- package/scripts/build.sh +0 -18
- package/src/components/button.tsx +0 -108
- package/src/components/index.tsx +0 -2
- package/src/components/input.tsx +0 -171
- package/src/constants/default-values.tsx +0 -153
- package/src/footer.tsx +0 -149
- package/src/header/desktop-header.tsx +0 -132
- package/src/header/header-context.tsx +0 -82
- package/src/header/index.tsx +0 -104
- package/src/header/is-logged-in-setter.tsx +0 -27
- package/src/header/menu/header-menu-item-group.tsx +0 -37
- package/src/header/menu/header-menu-item.tsx +0 -132
- package/src/header/menu/index.tsx +0 -205
- package/src/header/mobile-back-button-href-setter.tsx +0 -22
- package/src/header/mobile-header.tsx +0 -77
- package/src/header/post-title-setter.tsx +0 -22
- package/src/header/shared-components.tsx +0 -325
- package/src/hooks/index.ts +0 -3
- package/src/hooks/use-is-at-top.ts +0 -23
- package/src/hooks/use-media-query.ts +0 -57
- package/src/hooks/use-scroll-level.ts +0 -52
- package/src/icons/index.tsx +0 -378
- package/src/index.ts +0 -11
- package/src/styles.css +0 -354
- package/src/types/index.ts +0 -10
- package/src/utils/cn.ts +0 -41
- package/src/utils/generate-social-media-config.ts +0 -75
- package/src/utils/index.ts +0 -2
- package/tsconfig.json +0 -33
|
@@ -3,18 +3,22 @@ export type InputProps = {
|
|
|
3
3
|
value?: string;
|
|
4
4
|
onChange?: (value: string) => void;
|
|
5
5
|
onClear?: () => void;
|
|
6
|
-
showClearButton?: boolean;
|
|
7
6
|
children?: React.ReactNode;
|
|
8
7
|
inputRef?: React.RefObject<HTMLInputElement>;
|
|
8
|
+
error?: boolean;
|
|
9
|
+
errorMessage?: string;
|
|
10
|
+
mode?: 'default' | 'search';
|
|
9
11
|
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'>;
|
|
10
12
|
declare const Input: import("react").ForwardRefExoticComponent<{
|
|
11
13
|
placeholder?: string;
|
|
12
14
|
value?: string;
|
|
13
15
|
onChange?: (value: string) => void;
|
|
14
16
|
onClear?: () => void;
|
|
15
|
-
showClearButton?: boolean;
|
|
16
17
|
children?: React.ReactNode;
|
|
17
18
|
inputRef?: React.RefObject<HTMLInputElement>;
|
|
19
|
+
error?: boolean;
|
|
20
|
+
errorMessage?: string;
|
|
21
|
+
mode?: "default" | "search";
|
|
18
22
|
} & Omit<import("react").InputHTMLAttributes<HTMLInputElement>, "value" | "onChange"> & import("react").RefAttributes<HTMLInputElement>>;
|
|
19
23
|
export default Input;
|
|
20
24
|
//# sourceMappingURL=input.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/components/input.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/components/input.tsx"],"names":[],"mappings":"AA6DA,MAAM,MAAM,UAAU,GAAG;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAA;IAC5C,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;CAC5B,GAAG,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAA;AAE3E,QAAA,MAAM,KAAK;kBAXK,MAAM;YACZ,MAAM;eACH,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;cACxB,MAAM,IAAI;eACT,KAAK,CAAC,SAAS;eACf,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC;YACpC,OAAO;mBACA,MAAM;WACd,SAAS,GAAG,QAAQ;wIAyI5B,CAAA;AAED,eAAe,KAAK,CAAA"}
|
package/dist/components/input.js
CHANGED
|
@@ -35,7 +35,7 @@ const CloseIcon = ({
|
|
|
35
35
|
});
|
|
36
36
|
const inputVariants = (0, _classVarianceAuthority.cva)(
|
|
37
37
|
// Base styles
|
|
38
|
-
'
|
|
38
|
+
'px-4 py-1.5 h-11 relative flex items-center border border-transparent bg-neutral-100 prose-p1 transition-colors duration-200 hover:border-neutral-600 desktop:bg-neutral-white!', {
|
|
39
39
|
variants: {
|
|
40
40
|
state: {
|
|
41
41
|
default: 'border-transparent',
|
|
@@ -43,11 +43,21 @@ const inputVariants = (0, _classVarianceAuthority.cva)(
|
|
|
43
43
|
focus: 'border-neutral-600',
|
|
44
44
|
active: 'border-neutral-600',
|
|
45
45
|
unfocus: 'border-transparent',
|
|
46
|
-
error: 'border-
|
|
46
|
+
error: 'border-semantic-danger hover:border-semantic-danger'
|
|
47
|
+
},
|
|
48
|
+
mode: {
|
|
49
|
+
default: 'rounded-[12px] border-neutral-400',
|
|
50
|
+
search: 'rounded-full'
|
|
47
51
|
}
|
|
48
52
|
},
|
|
53
|
+
compoundVariants: [{
|
|
54
|
+
state: 'error',
|
|
55
|
+
mode: 'default',
|
|
56
|
+
className: 'border-semantic-danger'
|
|
57
|
+
}],
|
|
49
58
|
defaultVariants: {
|
|
50
|
-
state: 'default'
|
|
59
|
+
state: 'default',
|
|
60
|
+
mode: 'default'
|
|
51
61
|
}
|
|
52
62
|
});
|
|
53
63
|
const Input = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
@@ -55,11 +65,13 @@ const Input = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
55
65
|
value,
|
|
56
66
|
onChange,
|
|
57
67
|
onClear,
|
|
58
|
-
showClearButton = true,
|
|
59
68
|
className,
|
|
60
69
|
onFocus,
|
|
61
70
|
onBlur,
|
|
62
71
|
inputRef,
|
|
72
|
+
error,
|
|
73
|
+
errorMessage,
|
|
74
|
+
mode = 'default',
|
|
63
75
|
...props
|
|
64
76
|
}, ref) => {
|
|
65
77
|
const [internalValue, setInternalValue] = (0, _react.useState)('');
|
|
@@ -70,7 +82,7 @@ const Input = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
70
82
|
const hasValue = currentValue.length > 0;
|
|
71
83
|
|
|
72
84
|
// Determine current state
|
|
73
|
-
const currentState = isFocused ? 'focus' : hasValue ? isActive ? 'active' : 'unfocus' : 'default';
|
|
85
|
+
const currentState = error ? 'error' : isFocused ? 'focus' : hasValue ? isActive ? 'active' : 'unfocus' : 'default';
|
|
74
86
|
const handleChange = e => {
|
|
75
87
|
const newValue = e.target.value;
|
|
76
88
|
if (onChange) {
|
|
@@ -109,8 +121,10 @@ const Input = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
109
121
|
currentRef.current?.focus();
|
|
110
122
|
};
|
|
111
123
|
const inputClasses = (0, _cn.cn)(inputVariants({
|
|
112
|
-
state: currentState
|
|
124
|
+
state: currentState,
|
|
125
|
+
mode
|
|
113
126
|
}), className);
|
|
127
|
+
const isSearchMode = mode === 'search';
|
|
114
128
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
115
129
|
className: "gap-2 flex flex-col",
|
|
116
130
|
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
@@ -118,7 +132,7 @@ const Input = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
118
132
|
ref: ref,
|
|
119
133
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
|
|
120
134
|
className: "text-neutral-600",
|
|
121
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.SearchIconSmall, {})
|
|
135
|
+
children: isSearchMode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_icons.SearchIconSmall, {})
|
|
122
136
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
|
|
123
137
|
type: "text",
|
|
124
138
|
value: currentValue,
|
|
@@ -126,10 +140,17 @@ const Input = /*#__PURE__*/(0, _react.forwardRef)(({
|
|
|
126
140
|
onFocus: handleFocus,
|
|
127
141
|
onBlur: handleBlur,
|
|
128
142
|
placeholder: placeholder,
|
|
129
|
-
className:
|
|
143
|
+
className: (0, _cn.cn)('flex-1 flex-shrink-1 bg-transparent text-neutral-900 placeholder:prose-p1 placeholder:text-neutral-400 focus:outline-none disabled:bg-neutral-100 disabled:text-neutral-400', isSearchMode && 'ml-2 max-w-[72%]'),
|
|
144
|
+
"aria-describedby": errorMessage ? `${props.id ?? 'input'}-error` : undefined,
|
|
145
|
+
"aria-invalid": !!errorMessage,
|
|
130
146
|
ref: inputRef ?? innerInputRef,
|
|
131
147
|
...props
|
|
132
|
-
}),
|
|
148
|
+
}), errorMessage && /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
|
|
149
|
+
className: "-bottom-5 left-0 absolute prose-p3 text-semantic-danger",
|
|
150
|
+
id: `${props.id ?? 'input'}-error`,
|
|
151
|
+
role: "alert",
|
|
152
|
+
children: errorMessage
|
|
153
|
+
}), isSearchMode && hasValue && /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
|
|
133
154
|
type: "button",
|
|
134
155
|
onClick: handleClear,
|
|
135
156
|
className: "p-1/2 ml-auto flex-shrink-0 cursor-pointer rounded-full text-neutral-400 transition-colors hover:text-neutral-600 active:bg-neutral-200",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.js","names":["Object","defineProperty","exports","value","default","_classVarianceAuthority","require","_react","_icons","_cn","_jsxRuntime","CloseIcon","className","jsxs","width","height","viewBox","fill","xmlns","children","jsx","cx","cy","r","d","stroke","strokeWidth","strokeLinecap","strokeLinejoin","inputVariants","cva","variants","state","hover","focus","active","unfocus","error","defaultVariants","Input","forwardRef","placeholder","onChange","onClear","showClearButton","onFocus","onBlur","inputRef","props","ref","internalValue","setInternalValue","useState","isFocused","setIsFocused","isActive","setIsActive","innerInputRef","useRef","currentValue","undefined","hasValue","length","currentState","handleChange","e","newValue","target","handleFocus","handleBlur","handleClear","preventDefault","stopPropagation","currentRef","current","inputClasses","cn","SearchIconSmall","type","onClick","_default"],"sources":["../../src/components/input.tsx"],"sourcesContent":["'use client'\n\nimport { cva } from 'class-variance-authority'\nimport { forwardRef, useRef, useState } from 'react'\n\nimport { SearchIconSmall } from '../icons'\nimport { cn } from '../utils/cn'\n\n// Close icon component\nconst CloseIcon = ({ className }: { className?: string }) => (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <circle cx=\"10\" cy=\"10\" r=\"10\" fill=\"currentColor\" />\n <path\n d=\"M7 7l6 6M13 7l-6 6\"\n stroke=\"white\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n)\n\nconst inputVariants = cva(\n // Base styles\n 'desktop:bg-white! px-4 py-1.5 h-11 flex items-center rounded-full border border-transparent bg-neutral-100 prose-p1 transition-colors duration-200 hover:border-neutral-600',\n {\n variants: {\n state: {\n default: 'border-transparent',\n hover: 'border-neutral-600',\n focus: 'border-neutral-600',\n active: 'border-neutral-600',\n unfocus: 'border-transparent',\n error: 'border-red-600',\n },\n },\n defaultVariants: {\n state: 'default',\n },\n }\n)\n\nexport type InputProps = {\n placeholder?: string\n value?: string\n onChange?: (value: string) => void\n onClear?: () => void\n showClearButton?: boolean\n children?: React.ReactNode\n inputRef?: React.RefObject<HTMLInputElement>\n} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'>\n\nconst Input = forwardRef<HTMLInputElement, InputProps>(\n (\n {\n placeholder = '搜尋更多新聞、議題',\n value,\n onChange,\n onClear,\n showClearButton = true,\n className,\n onFocus,\n onBlur,\n inputRef,\n ...props\n },\n ref\n ) => {\n const [internalValue, setInternalValue] = useState('')\n const [isFocused, setIsFocused] = useState(false)\n const [isActive, setIsActive] = useState(false)\n const innerInputRef = useRef<HTMLInputElement>(null)\n const currentValue = value !== undefined ? value : internalValue\n const hasValue = currentValue.length > 0\n\n // Determine current state\n const currentState = isFocused\n ? 'focus'\n : hasValue\n ? isActive\n ? 'active'\n : 'unfocus'\n : 'default'\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value\n if (onChange) {\n onChange(newValue)\n } else {\n setInternalValue(newValue)\n }\n setIsActive(true)\n }\n\n const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {\n if (onFocus) {\n onFocus(e)\n }\n setIsFocused(true)\n setIsActive(true)\n }\n\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n if (onBlur) {\n onBlur(e)\n }\n setIsFocused(false)\n setIsActive(false)\n }\n\n const handleClear = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n if (onChange) {\n onChange('')\n } else {\n setInternalValue('')\n }\n if (onClear) {\n onClear()\n }\n\n const currentRef = inputRef ?? innerInputRef\n currentRef.current?.focus()\n }\n\n const inputClasses = cn(inputVariants({ state: currentState }), className)\n\n return (\n <div className=\"gap-2 flex flex-col\">\n <div className={inputClasses} ref={ref}>\n <div className=\"text-neutral-600\">\n <SearchIconSmall />\n </div>\n <input\n type=\"text\"\n value={currentValue}\n onChange={handleChange}\n onFocus={handleFocus}\n onBlur={handleBlur}\n placeholder={placeholder}\n className=\"placeholder:font-medium ml-2 max-w-[72%] flex-1 flex-shrink-1 bg-transparent text-neutral-900 placeholder:text-neutral-400 focus:outline-none\"\n ref={inputRef ?? innerInputRef}\n {...props}\n />\n\n {showClearButton && hasValue && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"p-1/2 ml-auto flex-shrink-0 cursor-pointer rounded-full text-neutral-400 transition-colors hover:text-neutral-600 active:bg-neutral-200\"\n aria-label=\"Clear input\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n )\n }\n)\n\nexport default Input\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"input.js","names":["Object","defineProperty","exports","value","default","_classVarianceAuthority","require","_react","_icons","_cn","_jsxRuntime","CloseIcon","className","jsxs","width","height","viewBox","fill","xmlns","children","jsx","cx","cy","r","d","stroke","strokeWidth","strokeLinecap","strokeLinejoin","inputVariants","cva","variants","state","hover","focus","active","unfocus","error","mode","search","compoundVariants","defaultVariants","Input","forwardRef","placeholder","onChange","onClear","onFocus","onBlur","inputRef","errorMessage","props","ref","internalValue","setInternalValue","useState","isFocused","setIsFocused","isActive","setIsActive","innerInputRef","useRef","currentValue","undefined","hasValue","length","currentState","handleChange","e","newValue","target","handleFocus","handleBlur","handleClear","preventDefault","stopPropagation","currentRef","current","inputClasses","cn","isSearchMode","SearchIconSmall","type","id","role","onClick","_default"],"sources":["../../src/components/input.tsx"],"sourcesContent":["'use client'\n\nimport { cva } from 'class-variance-authority'\nimport { forwardRef, useRef, useState } from 'react'\n\nimport { SearchIconSmall } from '../icons'\nimport { cn } from '../utils/cn'\n\n// Close icon component\nconst CloseIcon = ({ className }: { className?: string }) => (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n className={className}\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <circle cx=\"10\" cy=\"10\" r=\"10\" fill=\"currentColor\" />\n <path\n d=\"M7 7l6 6M13 7l-6 6\"\n stroke=\"white\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n)\n\nconst inputVariants = cva(\n // Base styles\n 'px-4 py-1.5 h-11 relative flex items-center border border-transparent bg-neutral-100 prose-p1 transition-colors duration-200 hover:border-neutral-600 desktop:bg-neutral-white!',\n {\n variants: {\n state: {\n default: 'border-transparent',\n hover: 'border-neutral-600',\n focus: 'border-neutral-600',\n active: 'border-neutral-600',\n unfocus: 'border-transparent',\n error: 'border-semantic-danger hover:border-semantic-danger',\n },\n mode: {\n default: 'rounded-[12px] border-neutral-400',\n search: 'rounded-full',\n },\n },\n compoundVariants: [\n {\n state: 'error',\n mode: 'default',\n className: 'border-semantic-danger',\n },\n ],\n defaultVariants: {\n state: 'default',\n mode: 'default',\n },\n }\n)\n\nexport type InputProps = {\n placeholder?: string\n value?: string\n onChange?: (value: string) => void\n onClear?: () => void\n children?: React.ReactNode\n inputRef?: React.RefObject<HTMLInputElement>\n error?: boolean\n errorMessage?: string\n mode?: 'default' | 'search'\n} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'>\n\nconst Input = forwardRef<HTMLInputElement, InputProps>(\n (\n {\n placeholder = '搜尋更多新聞、議題',\n value,\n onChange,\n onClear,\n className,\n onFocus,\n onBlur,\n inputRef,\n error,\n errorMessage,\n mode = 'default',\n ...props\n },\n ref\n ) => {\n const [internalValue, setInternalValue] = useState('')\n const [isFocused, setIsFocused] = useState(false)\n const [isActive, setIsActive] = useState(false)\n const innerInputRef = useRef<HTMLInputElement>(null)\n const currentValue = value !== undefined ? value : internalValue\n const hasValue = currentValue.length > 0\n\n // Determine current state\n const currentState = error\n ? 'error'\n : isFocused\n ? 'focus'\n : hasValue\n ? isActive\n ? 'active'\n : 'unfocus'\n : 'default'\n\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value\n if (onChange) {\n onChange(newValue)\n } else {\n setInternalValue(newValue)\n }\n setIsActive(true)\n }\n\n const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {\n if (onFocus) {\n onFocus(e)\n }\n setIsFocused(true)\n setIsActive(true)\n }\n\n const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {\n if (onBlur) {\n onBlur(e)\n }\n setIsFocused(false)\n setIsActive(false)\n }\n\n const handleClear = (e: React.MouseEvent) => {\n e.preventDefault()\n e.stopPropagation()\n\n if (onChange) {\n onChange('')\n } else {\n setInternalValue('')\n }\n if (onClear) {\n onClear()\n }\n\n const currentRef = inputRef ?? innerInputRef\n currentRef.current?.focus()\n }\n\n const inputClasses = cn(\n inputVariants({ state: currentState, mode }),\n className\n )\n\n const isSearchMode = mode === 'search'\n\n return (\n <div className=\"gap-2 flex flex-col\">\n <div className={inputClasses} ref={ref}>\n <div className=\"text-neutral-600\">\n {isSearchMode && <SearchIconSmall />}\n </div>\n <input\n type=\"text\"\n value={currentValue}\n onChange={handleChange}\n onFocus={handleFocus}\n onBlur={handleBlur}\n placeholder={placeholder}\n className={cn(\n 'flex-1 flex-shrink-1 bg-transparent text-neutral-900 placeholder:prose-p1 placeholder:text-neutral-400 focus:outline-none disabled:bg-neutral-100 disabled:text-neutral-400',\n isSearchMode && 'ml-2 max-w-[72%]'\n )}\n aria-describedby={\n errorMessage ? `${props.id ?? 'input'}-error` : undefined\n }\n aria-invalid={!!errorMessage}\n ref={inputRef ?? innerInputRef}\n {...props}\n />\n {errorMessage && (\n <p\n className=\"-bottom-5 left-0 absolute prose-p3 text-semantic-danger\"\n id={`${props.id ?? 'input'}-error`}\n role=\"alert\"\n >\n {errorMessage}\n </p>\n )}\n\n {isSearchMode && hasValue && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"p-1/2 ml-auto flex-shrink-0 cursor-pointer rounded-full text-neutral-400 transition-colors hover:text-neutral-600 active:bg-neutral-200\"\n aria-label=\"Clear input\"\n >\n <CloseIcon />\n </button>\n )}\n </div>\n </div>\n )\n }\n)\n\nexport default Input\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-components.d.ts","sourceRoot":"","sources":["../../src/header/shared-components.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AA2ExC,wBAAgB,QAAQ,CAAC,EAAE,WAAmB,EAAE,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,2CAgB1E;AAED,KAAK,uBAAuB,GACxB;IACE,IAAI,EAAE,SAAS,CAAA;IACf,YAAY,EAAE,OAAO,CAAA;IACrB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,iBAAiB,EAAE,MAAM,CAAA;CAC1B,GACD;IACE,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CAAA;AAEL,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"shared-components.d.ts","sourceRoot":"","sources":["../../src/header/shared-components.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AA2ExC,wBAAgB,QAAQ,CAAC,EAAE,WAAmB,EAAE,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,2CAgB1E;AAED,KAAK,uBAAuB,GACxB;IACE,IAAI,EAAE,SAAS,CAAA;IACf,YAAY,EAAE,OAAO,CAAA;IACrB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,iBAAiB,EAAE,MAAM,CAAA;CAC1B,GACD;IACE,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,iBAAiB,EAAE,MAAM,CAAA;CAC1B,CAAA;AAEL,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,2CAyEhE;AAED,wBAAgB,aAAa,CAAC,EAC5B,cAAsB,EACtB,IAAI,EACJ,iBAAiB,EACjB,YAAY,GACb,EAAE;IACD,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,iBAAiB,EAAE,MAAM,CAAA;IACzB,YAAY,EAAE,MAAM,CAAA;CACrB,2CAkEA;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,sBAAsB,EACtB,SAAS,GACV,EAAE;IACD,sBAAsB,EAAE,MAAM,IAAI,CAAA;IAClC,SAAS,EAAE,QAAQ,EAAE,CAAA;CACtB,2CA4BA;AAED,wBAAgB,eAAe,CAAC,EAC9B,sBAAsB,EACtB,KAAa,GACd,EAAE;IACD,sBAAsB,EAAE,MAAM,IAAI,CAAA;IAClC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,2CAYA"}
|
|
@@ -128,7 +128,8 @@ function SearchInputSection(props) {
|
|
|
128
128
|
className: "w-[99%]",
|
|
129
129
|
inputRef: ref,
|
|
130
130
|
onChange: setSearchValue,
|
|
131
|
-
value: searchValue
|
|
131
|
+
value: searchValue,
|
|
132
|
+
mode: "search"
|
|
132
133
|
})
|
|
133
134
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
134
135
|
className: searchDropdownVariants({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-components.js","names":["Object","defineProperty","exports","value","ActionButtons","BottomNavigation","HamburgerButton","LogoLink","SearchInputSection","_classVarianceAuthority","require","_react","_components","_icons","_cn","_jsxRuntime","searchFormVariants","cva","variants","mode","inline","popover","isSearchOpen","true","false","compoundVariants","class","searchDropdownVariants","isFocused","compactMode","jsx","href","className","rel","children","src","alt","loading","cn","width","height","props","ref","useRef","setIsFocused","useState","searchValue","setSearchValue","tags","searchPlaceholder","useEffect","current","focus","document","body","classList","add","remove","jsxs","onFocus","onBlur","role","method","action","undefined","Input","placeholder","name","title","inputRef","onChange","map","keyword","encodeURIComponent","hideCtaButtons","subscribeUrl","setIsSearchOpen","containerRef","buttonRef","handleClickOutside","event","containerElement","buttonElement","contains","target","addEventListener","removeEventListener","Button","variant","size","asChild","onClick","ClearIcon","SearchIcon","SettingsIcon","onHamburgerOverlayOpen","menuItems","small","reduce","acc","item","index","label","length","HamburgerIconSmall","HamburgerIcon"],"sources":["../../src/header/shared-components.tsx"],"sourcesContent":["'use client'\nimport { cva } from 'class-variance-authority'\nimport { useEffect, useRef, useState } from 'react'\n\nimport { Button, Input } from '../components'\nimport {\n ClearIcon,\n HamburgerIcon,\n HamburgerIconSmall,\n SearchIcon,\n SettingsIcon,\n} from '../icons'\nimport type { MenuItem } from '../types'\nimport { cn } from '../utils/cn'\n\nconst searchFormVariants = cva(\n 'ease-in-out h-full transition-all duration-300',\n {\n variants: {\n mode: {\n inline: 'h-11 w-full',\n popover: 'top-0 -right-4 w-66 absolute overflow-hidden opacity-0',\n },\n isSearchOpen: {\n true: '',\n false: '',\n },\n },\n compoundVariants: [\n {\n mode: 'popover',\n isSearchOpen: true,\n class: 'w-66 pointer-events-auto opacity-100',\n },\n {\n mode: 'popover',\n isSearchOpen: false,\n class: 'pointer-events-none',\n },\n ],\n }\n)\n\nconst searchDropdownVariants = cva(\n 'rounded-xl mt-2 w-66 ease-in-out h-0 p-0 z-50 bg-neutral-white opacity-0 transition-all duration-200',\n {\n variants: {\n mode: {\n inline: '',\n popover: 'top-12 -right-4 shadow-custom p-4 absolute',\n },\n isSearchOpen: {\n true: '',\n false: '',\n },\n isFocused: {\n true: '',\n false: '',\n },\n },\n compoundVariants: [\n {\n mode: 'popover',\n isSearchOpen: true,\n isFocused: true,\n class: 'p-4 h-min opacity-100',\n },\n {\n mode: 'popover',\n isSearchOpen: false,\n class: 'pointer-events-none',\n },\n {\n mode: 'inline',\n isFocused: true,\n class:\n 'translate-y-0 pt-6 mt-0 bg-neutral-transparent h-min w-full opacity-100',\n },\n {\n mode: 'inline',\n isFocused: false,\n class: '-translate-y-3 pointer-events-none w-full',\n },\n ],\n }\n)\n\nexport function LogoLink({ compactMode = false }: { compactMode?: boolean }) {\n return (\n <a href=\"/\" className=\"flex items-center\" rel=\"home\">\n <img\n src=\"/assets/images/brand-icon.svg\"\n alt=\"少年報導者 The Reporter for Kids\"\n loading=\"eager\"\n className={cn(\n 'h-5 tablet:h-6 desktop:h-8 ease-in-out w-auto transition-all duration-500',\n compactMode && 'desktop:h-[26px]'\n )}\n width={293}\n height={32}\n />\n </a>\n )\n}\n\ntype SearchInputSectionProps =\n | {\n mode: 'popover'\n isSearchOpen: boolean\n tags: string[]\n searchPlaceholder: string\n }\n | {\n mode: 'inline'\n tags: string[]\n searchPlaceholder: string\n }\n\nexport function SearchInputSection(props: SearchInputSectionProps) {\n const ref = useRef<HTMLInputElement>(null)\n const [isFocused, setIsFocused] = useState(false)\n const [searchValue, setSearchValue] = useState('')\n\n const mode = props.mode\n const isSearchOpen = mode === 'popover' && props.isSearchOpen\n const tags = props.tags\n const searchPlaceholder = props.searchPlaceholder\n\n useEffect(() => {\n if (mode === 'inline') {\n return\n }\n if (isSearchOpen) {\n ref.current?.focus()\n setIsFocused(true)\n document.body.classList.add('no-scroll')\n return\n }\n setIsFocused(false)\n document.body.classList.remove('no-scroll')\n }, [mode, isSearchOpen])\n\n return (\n <div\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n className={mode === 'inline' ? 'relative w-full' : 'h-11'}\n >\n <form\n role=\"search\"\n method=\"get\"\n action=\"/search\"\n className={searchFormVariants({\n mode,\n isSearchOpen: mode === 'popover' ? isSearchOpen : undefined,\n })}\n >\n <Input\n placeholder={searchPlaceholder}\n name=\"q\"\n title=\"Search for...\"\n aria-label=\"Search for...\"\n className=\"w-[99%]\"\n inputRef={ref}\n onChange={setSearchValue}\n value={searchValue}\n />\n </form>\n <div\n className={searchDropdownVariants({\n mode,\n isSearchOpen: mode === 'popover' ? isSearchOpen : undefined,\n isFocused,\n })}\n >\n <h3 className=\"font-bold mb-3 prose-p3 text-neutral-700\">熱門搜尋</h3>\n <div className=\"gap-2.5 flex flex-wrap\">\n {tags.map((keyword) => (\n <a\n key={keyword}\n className=\"px-3 py-1 font-bold cursor-pointer rounded-full bg-neutral-200 prose-p2 text-neutral-900 transition-colors duration-200 hover:bg-red-500 hover:text-neutral-white\"\n href={`/search?q=${encodeURIComponent(keyword)}`}\n >\n #{keyword}\n </a>\n ))}\n </div>\n </div>\n </div>\n )\n}\n\nexport function ActionButtons({\n hideCtaButtons = false,\n tags,\n searchPlaceholder,\n subscribeUrl,\n}: {\n hideCtaButtons?: boolean\n tags: string[]\n searchPlaceholder: string\n subscribeUrl: string\n}) {\n const [isSearchOpen, setIsSearchOpen] = useState(false)\n\n const containerRef = useRef<HTMLDivElement>(null)\n const buttonRef = useRef<HTMLButtonElement>(null)\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n const containerElement = containerRef.current\n const buttonElement = buttonRef.current\n if (!containerElement || !buttonElement) return\n if (\n !containerElement.contains(event.target as Node) &&\n !buttonElement.contains(event.target as Node)\n ) {\n setIsSearchOpen(false)\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n }\n }, [])\n\n return (\n <div className=\"relative flex items-center\">\n <div className=\"mr-6 relative flex items-center\" ref={containerRef}>\n {/* CTA Buttons - Base layer */}\n {!hideCtaButtons && !isSearchOpen && (\n <div className=\"gap-4 flex items-center\">\n <Button variant=\"secondary\" size={32} asChild>\n <a href=\"/about#post\">投稿</a>\n </Button>\n <Button variant=\"primary\" size={32} asChild>\n <a href={subscribeUrl} target=\"_blank\" rel=\"noopener noreferrer\">\n 訂閱\n </a>\n </Button>\n </div>\n )}\n\n <SearchInputSection\n isSearchOpen={isSearchOpen}\n mode=\"popover\"\n tags={tags}\n searchPlaceholder={searchPlaceholder}\n />\n </div>\n\n <button\n className=\"w-8 h-8 mr-4 flex cursor-pointer items-center justify-center rounded-full text-neutral-600 transition-all duration-200 hover:text-neutral-800\"\n aria-label=\"搜尋\"\n onClick={() => setIsSearchOpen(!isSearchOpen)}\n ref={buttonRef}\n >\n {isSearchOpen ? <ClearIcon /> : <SearchIcon />}\n </button>\n <button\n className=\"w-8 h-8 flex cursor-pointer items-center justify-center rounded-full text-neutral-600 transition-all duration-200 hover:text-neutral-800\"\n aria-label=\"設定\"\n >\n <SettingsIcon />\n </button>\n </div>\n )\n}\n\nexport function BottomNavigation({\n onHamburgerOverlayOpen,\n menuItems,\n}: {\n onHamburgerOverlayOpen: () => void\n menuItems: MenuItem[]\n}) {\n return (\n <div className=\"py-2 px-4 flex w-full items-center justify-between border-y border-neutral-border\">\n <HamburgerButton onHamburgerOverlayOpen={onHamburgerOverlayOpen} small />\n\n {menuItems.reduce((acc, item, index) => {\n return [\n ...acc,\n <div key={item.label} className=\"flex items-center\">\n <a\n href={item.href}\n className=\"py-1 font-bold! h-6 flex items-center prose-p1 text-neutral-900 transition-colors hover:text-red-400\"\n >\n {item.label}\n </a>\n </div>,\n ...(index < menuItems.length - 1\n ? [\n <div\n key={`separator-${index}`}\n className=\"h-4 mx-2 w-px bg-neutral-border\"\n />,\n ]\n : []),\n ]\n }, [] as React.ReactNode[])}\n </div>\n )\n}\n\nexport function HamburgerButton({\n onHamburgerOverlayOpen,\n small = false,\n}: {\n onHamburgerOverlayOpen: () => void\n small?: boolean\n}) {\n return (\n <button\n className={cn(\n 'rounded-sm ease-in-out flex cursor-pointer items-center justify-center transition-all duration-300 hover:[&>svg>path:nth-child(1)]:fill-blue-500 hover:[&>svg>path:nth-child(2)]:fill-red-500 hover:[&>svg>path:nth-child(3)]:fill-yellow-500 hover:[&>svg>rect:nth-child(1)]:fill-blue-500 hover:[&>svg>rect:nth-child(2)]:fill-red-500 hover:[&>svg>rect:nth-child(3)]:fill-yellow-500',\n small ? 'w-6 h-6' : 'w-8 h-8'\n )}\n onClick={onHamburgerOverlayOpen}\n >\n {small ? <HamburgerIconSmall /> : <HamburgerIcon />}\n </button>\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared-components.js","names":["Object","defineProperty","exports","value","ActionButtons","BottomNavigation","HamburgerButton","LogoLink","SearchInputSection","_classVarianceAuthority","require","_react","_components","_icons","_cn","_jsxRuntime","searchFormVariants","cva","variants","mode","inline","popover","isSearchOpen","true","false","compoundVariants","class","searchDropdownVariants","isFocused","compactMode","jsx","href","className","rel","children","src","alt","loading","cn","width","height","props","ref","useRef","setIsFocused","useState","searchValue","setSearchValue","tags","searchPlaceholder","useEffect","current","focus","document","body","classList","add","remove","jsxs","onFocus","onBlur","role","method","action","undefined","Input","placeholder","name","title","inputRef","onChange","map","keyword","encodeURIComponent","hideCtaButtons","subscribeUrl","setIsSearchOpen","containerRef","buttonRef","handleClickOutside","event","containerElement","buttonElement","contains","target","addEventListener","removeEventListener","Button","variant","size","asChild","onClick","ClearIcon","SearchIcon","SettingsIcon","onHamburgerOverlayOpen","menuItems","small","reduce","acc","item","index","label","length","HamburgerIconSmall","HamburgerIcon"],"sources":["../../src/header/shared-components.tsx"],"sourcesContent":["'use client'\nimport { cva } from 'class-variance-authority'\nimport { useEffect, useRef, useState } from 'react'\n\nimport { Button, Input } from '../components'\nimport {\n ClearIcon,\n HamburgerIcon,\n HamburgerIconSmall,\n SearchIcon,\n SettingsIcon,\n} from '../icons'\nimport type { MenuItem } from '../types'\nimport { cn } from '../utils/cn'\n\nconst searchFormVariants = cva(\n 'ease-in-out h-full transition-all duration-300',\n {\n variants: {\n mode: {\n inline: 'h-11 w-full',\n popover: 'top-0 -right-4 w-66 absolute overflow-hidden opacity-0',\n },\n isSearchOpen: {\n true: '',\n false: '',\n },\n },\n compoundVariants: [\n {\n mode: 'popover',\n isSearchOpen: true,\n class: 'w-66 pointer-events-auto opacity-100',\n },\n {\n mode: 'popover',\n isSearchOpen: false,\n class: 'pointer-events-none',\n },\n ],\n }\n)\n\nconst searchDropdownVariants = cva(\n 'rounded-xl mt-2 w-66 ease-in-out h-0 p-0 z-50 bg-neutral-white opacity-0 transition-all duration-200',\n {\n variants: {\n mode: {\n inline: '',\n popover: 'top-12 -right-4 shadow-custom p-4 absolute',\n },\n isSearchOpen: {\n true: '',\n false: '',\n },\n isFocused: {\n true: '',\n false: '',\n },\n },\n compoundVariants: [\n {\n mode: 'popover',\n isSearchOpen: true,\n isFocused: true,\n class: 'p-4 h-min opacity-100',\n },\n {\n mode: 'popover',\n isSearchOpen: false,\n class: 'pointer-events-none',\n },\n {\n mode: 'inline',\n isFocused: true,\n class:\n 'translate-y-0 pt-6 mt-0 bg-neutral-transparent h-min w-full opacity-100',\n },\n {\n mode: 'inline',\n isFocused: false,\n class: '-translate-y-3 pointer-events-none w-full',\n },\n ],\n }\n)\n\nexport function LogoLink({ compactMode = false }: { compactMode?: boolean }) {\n return (\n <a href=\"/\" className=\"flex items-center\" rel=\"home\">\n <img\n src=\"/assets/images/brand-icon.svg\"\n alt=\"少年報導者 The Reporter for Kids\"\n loading=\"eager\"\n className={cn(\n 'h-5 tablet:h-6 desktop:h-8 ease-in-out w-auto transition-all duration-500',\n compactMode && 'desktop:h-[26px]'\n )}\n width={293}\n height={32}\n />\n </a>\n )\n}\n\ntype SearchInputSectionProps =\n | {\n mode: 'popover'\n isSearchOpen: boolean\n tags: string[]\n searchPlaceholder: string\n }\n | {\n mode: 'inline'\n tags: string[]\n searchPlaceholder: string\n }\n\nexport function SearchInputSection(props: SearchInputSectionProps) {\n const ref = useRef<HTMLInputElement>(null)\n const [isFocused, setIsFocused] = useState(false)\n const [searchValue, setSearchValue] = useState('')\n\n const mode = props.mode\n const isSearchOpen = mode === 'popover' && props.isSearchOpen\n const tags = props.tags\n const searchPlaceholder = props.searchPlaceholder\n\n useEffect(() => {\n if (mode === 'inline') {\n return\n }\n if (isSearchOpen) {\n ref.current?.focus()\n setIsFocused(true)\n document.body.classList.add('no-scroll')\n return\n }\n setIsFocused(false)\n document.body.classList.remove('no-scroll')\n }, [mode, isSearchOpen])\n\n return (\n <div\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n className={mode === 'inline' ? 'relative w-full' : 'h-11'}\n >\n <form\n role=\"search\"\n method=\"get\"\n action=\"/search\"\n className={searchFormVariants({\n mode,\n isSearchOpen: mode === 'popover' ? isSearchOpen : undefined,\n })}\n >\n <Input\n placeholder={searchPlaceholder}\n name=\"q\"\n title=\"Search for...\"\n aria-label=\"Search for...\"\n className=\"w-[99%]\"\n inputRef={ref}\n onChange={setSearchValue}\n value={searchValue}\n mode=\"search\"\n />\n </form>\n <div\n className={searchDropdownVariants({\n mode,\n isSearchOpen: mode === 'popover' ? isSearchOpen : undefined,\n isFocused,\n })}\n >\n <h3 className=\"font-bold mb-3 prose-p3 text-neutral-700\">熱門搜尋</h3>\n <div className=\"gap-2.5 flex flex-wrap\">\n {tags.map((keyword) => (\n <a\n key={keyword}\n className=\"px-3 py-1 font-bold cursor-pointer rounded-full bg-neutral-200 prose-p2 text-neutral-900 transition-colors duration-200 hover:bg-red-500 hover:text-neutral-white\"\n href={`/search?q=${encodeURIComponent(keyword)}`}\n >\n #{keyword}\n </a>\n ))}\n </div>\n </div>\n </div>\n )\n}\n\nexport function ActionButtons({\n hideCtaButtons = false,\n tags,\n searchPlaceholder,\n subscribeUrl,\n}: {\n hideCtaButtons?: boolean\n tags: string[]\n searchPlaceholder: string\n subscribeUrl: string\n}) {\n const [isSearchOpen, setIsSearchOpen] = useState(false)\n\n const containerRef = useRef<HTMLDivElement>(null)\n const buttonRef = useRef<HTMLButtonElement>(null)\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n const containerElement = containerRef.current\n const buttonElement = buttonRef.current\n if (!containerElement || !buttonElement) return\n if (\n !containerElement.contains(event.target as Node) &&\n !buttonElement.contains(event.target as Node)\n ) {\n setIsSearchOpen(false)\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n }\n }, [])\n\n return (\n <div className=\"relative flex items-center\">\n <div className=\"mr-6 relative flex items-center\" ref={containerRef}>\n {/* CTA Buttons - Base layer */}\n {!hideCtaButtons && !isSearchOpen && (\n <div className=\"gap-4 flex items-center\">\n <Button variant=\"secondary\" size={32} asChild>\n <a href=\"/about#post\">投稿</a>\n </Button>\n <Button variant=\"primary\" size={32} asChild>\n <a href={subscribeUrl} target=\"_blank\" rel=\"noopener noreferrer\">\n 訂閱\n </a>\n </Button>\n </div>\n )}\n\n <SearchInputSection\n isSearchOpen={isSearchOpen}\n mode=\"popover\"\n tags={tags}\n searchPlaceholder={searchPlaceholder}\n />\n </div>\n\n <button\n className=\"w-8 h-8 mr-4 flex cursor-pointer items-center justify-center rounded-full text-neutral-600 transition-all duration-200 hover:text-neutral-800\"\n aria-label=\"搜尋\"\n onClick={() => setIsSearchOpen(!isSearchOpen)}\n ref={buttonRef}\n >\n {isSearchOpen ? <ClearIcon /> : <SearchIcon />}\n </button>\n <button\n className=\"w-8 h-8 flex cursor-pointer items-center justify-center rounded-full text-neutral-600 transition-all duration-200 hover:text-neutral-800\"\n aria-label=\"設定\"\n >\n <SettingsIcon />\n </button>\n </div>\n )\n}\n\nexport function BottomNavigation({\n onHamburgerOverlayOpen,\n menuItems,\n}: {\n onHamburgerOverlayOpen: () => void\n menuItems: MenuItem[]\n}) {\n return (\n <div className=\"py-2 px-4 flex w-full items-center justify-between border-y border-neutral-border\">\n <HamburgerButton onHamburgerOverlayOpen={onHamburgerOverlayOpen} small />\n\n {menuItems.reduce((acc, item, index) => {\n return [\n ...acc,\n <div key={item.label} className=\"flex items-center\">\n <a\n href={item.href}\n className=\"py-1 font-bold! h-6 flex items-center prose-p1 text-neutral-900 transition-colors hover:text-red-400\"\n >\n {item.label}\n </a>\n </div>,\n ...(index < menuItems.length - 1\n ? [\n <div\n key={`separator-${index}`}\n className=\"h-4 mx-2 w-px bg-neutral-border\"\n />,\n ]\n : []),\n ]\n }, [] as React.ReactNode[])}\n </div>\n )\n}\n\nexport function HamburgerButton({\n onHamburgerOverlayOpen,\n small = false,\n}: {\n onHamburgerOverlayOpen: () => void\n small?: boolean\n}) {\n return (\n <button\n className={cn(\n 'rounded-sm ease-in-out flex cursor-pointer items-center justify-center transition-all duration-300 hover:[&>svg>path:nth-child(1)]:fill-blue-500 hover:[&>svg>path:nth-child(2)]:fill-red-500 hover:[&>svg>path:nth-child(3)]:fill-yellow-500 hover:[&>svg>rect:nth-child(1)]:fill-blue-500 hover:[&>svg>rect:nth-child(2)]:fill-red-500 hover:[&>svg>rect:nth-child(3)]:fill-yellow-500',\n small ? 'w-6 h-6' : 'w-8 h-8'\n )}\n onClick={onHamburgerOverlayOpen}\n >\n {small ? <HamburgerIconSmall /> : <HamburgerIcon />}\n </button>\n )\n}\n"],"mappings":"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"}
|
package/dist/styles.css
CHANGED
|
@@ -44,6 +44,9 @@
|
|
|
44
44
|
--color-yellow-700: #926c10;
|
|
45
45
|
--color-yellow-800: #705207;
|
|
46
46
|
|
|
47
|
+
/* Colors - Semantic Danger */
|
|
48
|
+
--color-semantic-danger: #c7000a;
|
|
49
|
+
|
|
47
50
|
/* Typography - Font Families */
|
|
48
51
|
--font-family-noto: 'Noto Sans TC', sans-serif;
|
|
49
52
|
|
|
@@ -149,6 +152,14 @@
|
|
|
149
152
|
--paletteColor8: var(--color-neutral-white);
|
|
150
153
|
--color: var(--paletteColor3);
|
|
151
154
|
}
|
|
155
|
+
|
|
156
|
+
::selection {
|
|
157
|
+
background-color: var(--color-neutral-400);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
::-moz-selection {
|
|
161
|
+
background-color: var(--color-neutral-400);
|
|
162
|
+
}
|
|
152
163
|
}
|
|
153
164
|
|
|
154
165
|
@layer utilities {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kids-reporter/routing-ui",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.7",
|
|
5
5
|
"description": "Routing UI for Kids Reporter",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -18,15 +18,13 @@
|
|
|
18
18
|
"build": "./scripts/build.sh",
|
|
19
19
|
"lint": "eslint . --config ./eslint.config.mjs",
|
|
20
20
|
"lint:check": "eslint . --config ./eslint.config.mjs",
|
|
21
|
-
"type-check": "tsc --noEmit"
|
|
22
|
-
"postinstall": "yarn build"
|
|
21
|
+
"type-check": "tsc --noEmit"
|
|
23
22
|
},
|
|
24
23
|
"dependencies": {
|
|
25
24
|
"@radix-ui/react-slot": "^1.2.3",
|
|
26
25
|
"class-variance-authority": "^0.7.1",
|
|
27
26
|
"clsx": "^2.1.1",
|
|
28
27
|
"lodash": "^4.17.21",
|
|
29
|
-
"next": "^14.2.33",
|
|
30
28
|
"tailwind-merge": "^3.3.1"
|
|
31
29
|
},
|
|
32
30
|
"devDependencies": {
|
|
@@ -50,5 +48,8 @@
|
|
|
50
48
|
"react": "18.3.1",
|
|
51
49
|
"react-dom": "18.3.1",
|
|
52
50
|
"tailwindcss": "^4.1.14"
|
|
53
|
-
}
|
|
51
|
+
},
|
|
52
|
+
"files": [
|
|
53
|
+
"dist"
|
|
54
|
+
]
|
|
54
55
|
}
|
package/.prettierignore
DELETED
package/babel.config.cjs
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
presets: [
|
|
3
|
-
[
|
|
4
|
-
'@babel/preset-env',
|
|
5
|
-
{
|
|
6
|
-
targets: {
|
|
7
|
-
node: '18',
|
|
8
|
-
browsers: ['> 1%', 'last 2 versions', 'not dead'],
|
|
9
|
-
},
|
|
10
|
-
modules: 'commonjs', // Build CommonJS modules
|
|
11
|
-
},
|
|
12
|
-
],
|
|
13
|
-
[
|
|
14
|
-
'@babel/preset-react',
|
|
15
|
-
{
|
|
16
|
-
runtime: 'automatic',
|
|
17
|
-
development: process.env.NODE_ENV === 'development',
|
|
18
|
-
pragma: undefined, // Use automatic runtime
|
|
19
|
-
pragmaFrag: undefined, // Use automatic runtime
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
[
|
|
23
|
-
'@babel/preset-typescript',
|
|
24
|
-
{
|
|
25
|
-
isTSX: true,
|
|
26
|
-
allExtensions: true,
|
|
27
|
-
},
|
|
28
|
-
],
|
|
29
|
-
],
|
|
30
|
-
plugins: ['@babel/plugin-transform-runtime'],
|
|
31
|
-
}
|
package/eslint.config.mjs
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import globals from 'globals'
|
|
2
|
-
|
|
3
|
-
import baseConfig, {
|
|
4
|
-
javascriptConfig,
|
|
5
|
-
typescriptConfig,
|
|
6
|
-
} from '../../eslint.base.config.mjs'
|
|
7
|
-
|
|
8
|
-
export default [
|
|
9
|
-
...baseConfig,
|
|
10
|
-
// Override for routing-ui package - React/TypeScript focused
|
|
11
|
-
{
|
|
12
|
-
...typescriptConfig,
|
|
13
|
-
files: ['src/**/*.{ts,tsx}'],
|
|
14
|
-
rules: {
|
|
15
|
-
...typescriptConfig.rules,
|
|
16
|
-
},
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
...javascriptConfig,
|
|
20
|
-
files: ['src/**/*.{js,jsx}'],
|
|
21
|
-
rules: {
|
|
22
|
-
...javascriptConfig.rules,
|
|
23
|
-
// Tailwind CSS classname sorting rules
|
|
24
|
-
'no-restricted-syntax': [
|
|
25
|
-
'warn',
|
|
26
|
-
{
|
|
27
|
-
selector: 'JSXAttribute[name.name="className"]',
|
|
28
|
-
message:
|
|
29
|
-
'Tailwind CSS classes should be sorted. Use prettier-plugin-tailwindcss for automatic sorting.',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
selector: 'JSXAttribute[name.name="class"]',
|
|
33
|
-
message:
|
|
34
|
-
'CSS classes should be sorted. Consider using a class sorting tool.',
|
|
35
|
-
},
|
|
36
|
-
],
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
files: ['**/*.config.{js,mjs,cjs}'],
|
|
41
|
-
languageOptions: {
|
|
42
|
-
ecmaVersion: 2022,
|
|
43
|
-
sourceType: 'module',
|
|
44
|
-
globals: {
|
|
45
|
-
...globals.node,
|
|
46
|
-
...globals.es2022,
|
|
47
|
-
},
|
|
48
|
-
},
|
|
49
|
-
rules: {
|
|
50
|
-
'no-undef': 'error',
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
ignores: ['node_modules/**', 'dist/**', 'build/**'],
|
|
55
|
-
},
|
|
56
|
-
]
|
package/prettier.config.mjs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */
|
|
2
|
-
export default {
|
|
3
|
-
printWidth: 80,
|
|
4
|
-
tabWidth: 2,
|
|
5
|
-
semi: false,
|
|
6
|
-
singleQuote: true,
|
|
7
|
-
trailingComma: 'es5',
|
|
8
|
-
bracketSpacing: true,
|
|
9
|
-
arrowParens: 'always',
|
|
10
|
-
plugins: ['prettier-plugin-tailwindcss'],
|
|
11
|
-
tailwindStylesheet: './src/styles.css',
|
|
12
|
-
tailwindFunctions: ['clsx', 'cn', 'cva'],
|
|
13
|
-
}
|
package/scripts/build.sh
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
set -e
|
|
4
|
-
|
|
5
|
-
echo "Cleaning dist directory..."
|
|
6
|
-
rm -rf ./dist
|
|
7
|
-
mkdir -p ./dist
|
|
8
|
-
|
|
9
|
-
echo "Building CJS version..."
|
|
10
|
-
npx babel src --out-dir dist --extensions ".ts,.tsx" --source-maps
|
|
11
|
-
|
|
12
|
-
echo "Copying CSS file..."
|
|
13
|
-
cp ./src/styles.css ./dist/styles.css
|
|
14
|
-
|
|
15
|
-
echo "Generating TypeScript declarations..."
|
|
16
|
-
npx tsc --emitDeclarationOnly --declaration --declarationMap --outDir dist
|
|
17
|
-
|
|
18
|
-
echo "Build completed successfully!"
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { Slot } from '@radix-ui/react-slot'
|
|
4
|
-
import { cva, type VariantProps } from 'class-variance-authority'
|
|
5
|
-
import React from 'react'
|
|
6
|
-
|
|
7
|
-
import { cn } from '../utils/cn'
|
|
8
|
-
|
|
9
|
-
const buttonVariants = cva(
|
|
10
|
-
// Base styles
|
|
11
|
-
'font-noto gap-2.5 font-bold inline-flex cursor-pointer items-center justify-center rounded-full transition-colors duration-200',
|
|
12
|
-
{
|
|
13
|
-
variants: {
|
|
14
|
-
variant: {
|
|
15
|
-
primary: [
|
|
16
|
-
'text-white border-0 bg-red-400',
|
|
17
|
-
'hover:bg-red-500',
|
|
18
|
-
'active:bg-red-600',
|
|
19
|
-
'disabled:text-white disabled:cursor-default disabled:bg-neutral-400',
|
|
20
|
-
],
|
|
21
|
-
secondary: [
|
|
22
|
-
'bg-white text-gray-900 border-2 border-red-400',
|
|
23
|
-
'hover:text-white hover:border-red-500 hover:bg-red-500',
|
|
24
|
-
'active:text-white active:border-red-600 active:bg-red-600',
|
|
25
|
-
'disabled:bg-white disabled:cursor-default disabled:border-neutral-400 disabled:text-neutral-400',
|
|
26
|
-
],
|
|
27
|
-
},
|
|
28
|
-
size: {
|
|
29
|
-
44: 'h-11 px-5 py-2 text-base', // 44px height, 16px font size
|
|
30
|
-
36: 'h-9 px-4 py-2 text-sm', // 36px height, 14px font size
|
|
31
|
-
32: 'h-8 px-3 py-1 text-sm', // 32px height, 14px font size
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
defaultVariants: {
|
|
35
|
-
variant: 'primary',
|
|
36
|
-
size: 44,
|
|
37
|
-
},
|
|
38
|
-
}
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
// Loading spinner icon component
|
|
42
|
-
const LoadingSpinner = ({ size = 20 }: { size?: number }) => (
|
|
43
|
-
<svg
|
|
44
|
-
width={size}
|
|
45
|
-
height={size}
|
|
46
|
-
viewBox="0 0 25 24"
|
|
47
|
-
fill="none"
|
|
48
|
-
className="animate-spin"
|
|
49
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
50
|
-
>
|
|
51
|
-
<path
|
|
52
|
-
opacity="0.5"
|
|
53
|
-
d="M12.5 2C10.5222 2 8.58879 2.58649 6.9443 3.6853C5.29981 4.78412 4.01809 6.3459 3.26121 8.17317C2.50433 10.0004 2.3063 12.0111 2.69215 13.9509C3.078 15.8907 4.03041 17.6725 5.42894 19.0711C6.82746 20.4696 8.60929 21.422 10.5491 21.8079C12.4889 22.1937 14.4996 21.9957 16.3268 21.2388C18.1541 20.4819 19.7159 19.2002 20.8147 17.5557C21.9135 15.9112 22.5 13.9778 22.5 12C22.5 10.6868 22.2413 9.38642 21.7388 8.17317C21.2363 6.95991 20.4997 5.85752 19.5711 4.92893C18.6425 4.00035 17.5401 3.26375 16.3268 2.7612C15.1136 2.25866 13.8132 2 12.5 2ZM12.5 20C10.9178 20 9.37104 19.5308 8.05544 18.6518C6.73985 17.7727 5.71447 16.5233 5.10897 15.0615C4.50347 13.5997 4.34504 11.9911 4.65372 10.4393C4.9624 8.88743 5.72433 7.46197 6.84315 6.34315C7.96197 5.22433 9.38743 4.4624 10.9393 4.15372C12.4911 3.84504 14.0997 4.00346 15.5615 4.60896C17.0233 5.21447 18.2727 6.23984 19.1518 7.55544C20.0308 8.87103 20.5 10.4177 20.5 12C20.5 14.1217 19.6572 16.1566 18.1569 17.6569C16.6566 19.1571 14.6217 20 12.5 20Z"
|
|
54
|
-
fill="currentColor"
|
|
55
|
-
/>
|
|
56
|
-
<path
|
|
57
|
-
d="M20.5 12H22.5C22.5 10.6868 22.2413 9.38642 21.7388 8.17317C21.2362 6.95991 20.4997 5.85752 19.5711 4.92893C18.6425 4.00035 17.5401 3.26375 16.3268 2.7612C15.1136 2.25866 13.8132 2 12.5 2V4C14.6217 4 16.6566 4.84285 18.1569 6.34315C19.6571 7.84344 20.5 9.87827 20.5 12Z"
|
|
58
|
-
fill="currentColor"
|
|
59
|
-
/>
|
|
60
|
-
</svg>
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
export type ButtonProps = {
|
|
64
|
-
isLoading?: boolean
|
|
65
|
-
disabled?: boolean
|
|
66
|
-
asChild?: boolean
|
|
67
|
-
children: React.ReactNode
|
|
68
|
-
} & VariantProps<typeof buttonVariants> &
|
|
69
|
-
React.ButtonHTMLAttributes<HTMLButtonElement>
|
|
70
|
-
|
|
71
|
-
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
72
|
-
(
|
|
73
|
-
{
|
|
74
|
-
isLoading = false,
|
|
75
|
-
disabled = false,
|
|
76
|
-
asChild = false,
|
|
77
|
-
size,
|
|
78
|
-
variant,
|
|
79
|
-
className,
|
|
80
|
-
children,
|
|
81
|
-
...props
|
|
82
|
-
},
|
|
83
|
-
ref
|
|
84
|
-
) => {
|
|
85
|
-
const isDisabled = disabled || isLoading
|
|
86
|
-
|
|
87
|
-
const buttonClasses = cn(buttonVariants({ variant, size }), className)
|
|
88
|
-
|
|
89
|
-
const Comp = asChild ? Slot : 'button'
|
|
90
|
-
|
|
91
|
-
return (
|
|
92
|
-
<Comp
|
|
93
|
-
ref={ref}
|
|
94
|
-
className={buttonClasses}
|
|
95
|
-
disabled={isDisabled}
|
|
96
|
-
{...props}
|
|
97
|
-
>
|
|
98
|
-
{isLoading ? (
|
|
99
|
-
<LoadingSpinner size={size === 32 ? 16 : size === 36 ? 18 : 20} />
|
|
100
|
-
) : (
|
|
101
|
-
children
|
|
102
|
-
)}
|
|
103
|
-
</Comp>
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
export default Button
|
package/src/components/index.tsx
DELETED