@orangesk/orange-design-system 2.0.0-beta.16 → 2.0.0-beta.17
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/build/components/Accordion/style.css +2 -0
- package/build/components/Accordion/style.css.map +1 -0
- package/build/components/Alert/style.css +2 -0
- package/build/components/Alert/style.css.map +1 -0
- package/build/components/AnchorNavigation/style.css +2 -0
- package/build/components/AnchorNavigation/style.css.map +1 -0
- package/build/components/Bar/style.css +2 -0
- package/build/components/Bar/style.css.map +1 -0
- package/build/components/BlockAction/style.css +2 -0
- package/build/components/BlockAction/style.css.map +1 -0
- package/build/components/BodyBanner/style.css +2 -0
- package/build/components/BodyBanner/style.css.map +1 -0
- package/build/components/Breadcrumbs/style.css +2 -0
- package/build/components/Breadcrumbs/style.css.map +1 -0
- package/build/components/Button/style.css +2 -0
- package/build/components/Button/style.css.map +1 -0
- package/build/components/Buttons/style.css +2 -0
- package/build/components/Buttons/style.css.map +1 -0
- package/build/components/Card/style.css +2 -0
- package/build/components/Card/style.css.map +1 -0
- package/build/components/Carousel/style.css +2 -0
- package/build/components/Carousel/style.css.map +1 -0
- package/build/components/CarouselHero/style.css +2 -0
- package/build/components/CarouselHero/style.css.map +1 -0
- package/build/components/CarouselPromotions/style.css +2 -0
- package/build/components/CarouselPromotions/style.css.map +1 -0
- package/build/components/CartTable/style.css +2 -0
- package/build/components/CartTable/style.css.map +1 -0
- package/build/components/Code/style.css +2 -0
- package/build/components/Code/style.css.map +1 -0
- package/build/components/Container/style.css +2 -0
- package/build/components/Container/style.css.map +1 -0
- package/build/components/Controls/style.css +2 -0
- package/build/components/Controls/style.css.map +1 -0
- package/build/components/Cover/style.css +2 -0
- package/build/components/Cover/style.css.map +1 -0
- package/build/components/Divider/style.css +2 -0
- package/build/components/Divider/style.css.map +1 -0
- package/build/components/DocumentationSidebar/style.css +2 -0
- package/build/components/DocumentationSidebar/style.css.map +1 -0
- package/build/components/Dropdown/style.css +2 -0
- package/build/components/Dropdown/style.css.map +1 -0
- package/build/components/Expander/style.css +2 -0
- package/build/components/Expander/style.css.map +1 -0
- package/build/components/FeatureAccordion/style.css +2 -0
- package/build/components/FeatureAccordion/style.css.map +1 -0
- package/build/components/Footer/style.css +2 -0
- package/build/components/Footer/style.css.map +1 -0
- package/build/components/Gauge/style.css +2 -0
- package/build/components/Gauge/style.css.map +1 -0
- package/build/components/Grid/style.css +2 -0
- package/build/components/Grid/style.css.map +1 -0
- package/build/components/Hero/style.css +2 -0
- package/build/components/Hero/style.css.map +1 -0
- package/build/components/Icon/style.css +2 -0
- package/build/components/Icon/style.css.map +1 -0
- package/build/components/IconList/style.css +2 -0
- package/build/components/IconList/style.css.map +1 -0
- package/build/components/Image/style.css +2 -0
- package/build/components/Image/style.css.map +1 -0
- package/build/components/Link/style.css +2 -0
- package/build/components/Link/style.css.map +1 -0
- package/build/components/List/style.css +2 -0
- package/build/components/List/style.css.map +1 -0
- package/build/components/Loader/style.css +2 -0
- package/build/components/Loader/style.css.map +1 -0
- package/build/components/Megamenu/style.css +2 -0
- package/build/components/Megamenu/style.css.map +1 -0
- package/build/components/Modal/style.css +2 -0
- package/build/components/Modal/style.css.map +1 -0
- package/build/components/Pagination/style.css +2 -0
- package/build/components/Pagination/style.css.map +1 -0
- package/build/components/Pill/style.css +2 -0
- package/build/components/Pill/style.css.map +1 -0
- package/build/components/Preview/style.css +2 -0
- package/build/components/Preview/style.css.map +1 -0
- package/build/components/Progress/style.css +2 -0
- package/build/components/Progress/style.css.map +1 -0
- package/build/components/PromoBanner/style.css +2 -0
- package/build/components/PromoBanner/style.css.map +1 -0
- package/build/components/PromotionCard/style.css +2 -0
- package/build/components/PromotionCard/style.css.map +1 -0
- package/build/components/Section/style.css +2 -0
- package/build/components/Section/style.css.map +1 -0
- package/build/components/Skeleton/style.css +2 -0
- package/build/components/Skeleton/style.css.map +1 -0
- package/build/components/SkipLink/style.css +2 -0
- package/build/components/SkipLink/style.css.map +1 -0
- package/build/components/Stepbar/style.css +2 -0
- package/build/components/Stepbar/style.css.map +1 -0
- package/build/components/Sticker/style.css +2 -0
- package/build/components/Sticker/style.css.map +1 -0
- package/build/components/Table/style.css +2 -0
- package/build/components/Table/style.css.map +1 -0
- package/build/components/Tabs/style.css +2 -0
- package/build/components/Tabs/style.css.map +1 -0
- package/build/components/Tag/style.css +2 -0
- package/build/components/Tag/style.css.map +1 -0
- package/build/components/Testimonial/style.css +2 -0
- package/build/components/Testimonial/style.css.map +1 -0
- package/build/components/Tile/style.css +2 -0
- package/build/components/Tile/style.css.map +1 -0
- package/build/components/Tooltip/style.css +2 -0
- package/build/components/Tooltip/style.css.map +1 -0
- package/build/components/index.js +1 -1
- package/build/components/index.js.map +1 -1
- package/build/components/tsconfig.tsbuildinfo +1 -1
- package/build/components/types/index.d.ts +1 -1
- package/build/components/types/src/components/DocumentationSidebar/DocumentationSidebar.d.ts +1 -0
- package/build/components/types/src/components/Link/Link.d.ts +1 -1
- package/build/lib/{before-components.css → base.css} +1 -1
- package/build/lib/base.css.map +1 -0
- package/build/lib/components.css +1 -1
- package/build/lib/components.css.map +1 -1
- package/build/lib/style.css +1 -1
- package/build/lib/style.css.map +1 -1
- package/build/lib/tsconfig.tsbuildinfo +1 -1
- package/build/lib/utilities.css +2 -0
- package/build/lib/utilities.css.map +1 -0
- package/build/search-index.json +406 -0
- package/package.json +8 -6
- package/src/components/Code/styles/style.scss +6 -5
- package/src/components/DocumentationSidebar/DocumentationSidebar.tsx +188 -2
- package/src/components/DocumentationSidebar/styles/style.scss +73 -0
- package/src/components/FeatureAccordion/tests/FeatureAccordion.conformance.test.js +1 -0
- package/src/components/Forms/Field/tests/Autocomplete.Field.conformance.test.js +1 -1
- package/src/components/Forms/Field/tests/Checkbox.Field.conformance.test.js +1 -0
- package/src/components/Forms/Field/tests/File.Field.conformance.test.js +1 -0
- package/src/components/Forms/Field/tests/Group.Field.conformance.test.js +1 -0
- package/src/components/Forms/Field/tests/Radio.Field.conformance.test.js +1 -0
- package/src/components/Forms/Field/tests/Rangeslider.Field.test.js +1 -0
- package/src/components/Forms/Field/tests/Select.Field.conformance.test.js +1 -0
- package/src/components/Forms/Field/tests/Text.Field.conformance.test.js +1 -0
- package/src/components/Forms/Field/tests/Textarea.Field.conformance.test.js +1 -0
- package/src/components/Link/Link.tsx +2 -2
- package/src/components/Link/styles/mixins.scss +1 -1
- package/src/components/Link/styles/style.scss +0 -7
- package/src/components/Table/tests/Table.conformance.test.js +5 -1
- package/src/components/Tooltip/tests/Tooltip.conformance.test.js +5 -1
- package/src/styles/base/globals.scss +1 -37
- package/src/styles/base/styleguide.scss +1 -0
- package/src/styles/export/color.js +3 -3
- package/src/styles/tokens/color-vars.scss +39 -0
- package/src/styles/tokens/color.scss +4 -4
- package/src/styles/utilities/text.scss +17 -0
- package/build/lib/after-components.css +0 -2
- package/build/lib/after-components.css.map +0 -1
- package/build/lib/before-components.css.map +0 -1
- package/src/styles/after-components.scss +0 -2
- package/src/styles/before-components.scss +0 -18
- /package/build/lib/{after-components.js → base.js} +0 -0
- /package/build/lib/{before-components.js → utilities.js} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orangesk/orange-design-system",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.17",
|
|
4
4
|
"private": false,
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.x"
|
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
],
|
|
15
15
|
"main": "build/components/index.js",
|
|
16
16
|
"scripts": {
|
|
17
|
-
"dev": "npm run build:scss-exports && next dev",
|
|
18
|
-
"build": "npm run build:scss-exports && next build && npm run sprite",
|
|
17
|
+
"dev": "npm run build:scss-exports && npm run build:search-index && next dev",
|
|
18
|
+
"build": "npm run build:scss-exports && npm run build:search-index && next build && npm run sprite",
|
|
19
19
|
"build:bundle": "npm run build:scss-exports && npx rollup -c && npm run build:megamenu && npm run build:footer",
|
|
20
20
|
"build:megamenu": "npm run build:scss-exports && npx rollup -c rollup.megamenu.config.mjs",
|
|
21
21
|
"dev:megamenu": "npm run build:scss-exports && npx rollup -c rollup.megamenu.config.mjs --watch",
|
|
22
22
|
"build:footer": "npm run build:scss-exports && npx rollup -c rollup.footer.config.mjs",
|
|
23
23
|
"dev:footer": "npm run build:scss-exports && npx rollup -c rollup.footer.config.mjs --watch",
|
|
24
24
|
"build:scss-exports": "node scripts/build-scss-exports.js",
|
|
25
|
+
"build:search-index": "node scripts/mdx-search-index.js",
|
|
25
26
|
"start": "next start",
|
|
26
27
|
"lint": "next lint",
|
|
27
28
|
"test": "jest",
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
"html-react-parser": "^5.2.7",
|
|
47
48
|
"jest-environment-jsdom": "^30.2.0",
|
|
48
49
|
"lorem-ipsum": "^2.0.8",
|
|
50
|
+
"minisearch": "7.2.0",
|
|
49
51
|
"next": "16.0.1",
|
|
50
52
|
"normalize.css": "^8.0.1",
|
|
51
53
|
"nouislider": "^15.8.1",
|
|
@@ -83,7 +85,7 @@
|
|
|
83
85
|
"@testing-library/jest-dom": "^6.9.1",
|
|
84
86
|
"@testing-library/react": "^16.3.0",
|
|
85
87
|
"@testing-library/user-event": "^14.6.1",
|
|
86
|
-
"@types/node": "^24.
|
|
88
|
+
"@types/node": "^24.10.0",
|
|
87
89
|
"@types/pretty": "^2.0.3",
|
|
88
90
|
"@types/react": "19.2.2",
|
|
89
91
|
"@types/react-dom": "19.2.2",
|
|
@@ -95,7 +97,7 @@
|
|
|
95
97
|
"eslint-plugin-unused-imports": "^4.3.0",
|
|
96
98
|
"fs-extra": "^11.3.2",
|
|
97
99
|
"glob": "^11.0.3",
|
|
98
|
-
"html-validate": "10.
|
|
100
|
+
"html-validate": "10.3.0",
|
|
99
101
|
"husky": "^9.1.7",
|
|
100
102
|
"identity-obj-proxy": "^3.0.0",
|
|
101
103
|
"jest": "30.2.0",
|
|
@@ -106,7 +108,7 @@
|
|
|
106
108
|
"rollup-plugin-copy": "^3.5.0",
|
|
107
109
|
"rollup-plugin-dts": "^6.2.3",
|
|
108
110
|
"rollup-plugin-postcss": "^4.0.2",
|
|
109
|
-
"sass": "^1.93.
|
|
111
|
+
"sass": "^1.93.3",
|
|
110
112
|
"svg-sprite": "^2.0.4",
|
|
111
113
|
"typescript": "5.9.3"
|
|
112
114
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/* Code component styles */
|
|
2
2
|
.code {
|
|
3
|
-
font-feature-settings:
|
|
3
|
+
font-feature-settings: "calt" 1;
|
|
4
4
|
text-rendering: optimizeLegibility;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
.code[class*=
|
|
8
|
-
font-family:
|
|
7
|
+
.code[class*="language-"] {
|
|
8
|
+
font-family:
|
|
9
|
+
"Monaco", "Menlo", "Ubuntu Mono", "Consolas", "source-code-pro", monospace;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
/* Inline code styles */
|
|
@@ -24,7 +25,7 @@
|
|
|
24
25
|
&.inline {
|
|
25
26
|
display: inline;
|
|
26
27
|
}
|
|
27
|
-
|
|
28
|
+
|
|
28
29
|
&.block {
|
|
29
30
|
display: block;
|
|
30
31
|
}
|
|
@@ -55,4 +56,4 @@
|
|
|
55
56
|
overflow: auto;
|
|
56
57
|
margin: 0;
|
|
57
58
|
margin-bottom: 1rem; /* mb-4 */
|
|
58
|
-
}
|
|
59
|
+
}
|
|
@@ -4,8 +4,10 @@ import React from "react";
|
|
|
4
4
|
import cx from "classnames";
|
|
5
5
|
import { usePathname } from "next/navigation";
|
|
6
6
|
import Link from "next/link";
|
|
7
|
+
import MiniSearch from "minisearch";
|
|
7
8
|
import { Image } from "../Image";
|
|
8
9
|
import { Icon } from "../Icon";
|
|
10
|
+
import { TextInput } from "../Forms/TextInput";
|
|
9
11
|
import packageJson from "../../../package.json";
|
|
10
12
|
|
|
11
13
|
export interface DocumentationSidebarItem {
|
|
@@ -13,6 +15,7 @@ export interface DocumentationSidebarItem {
|
|
|
13
15
|
href?: string;
|
|
14
16
|
target?: React.HTMLAttributeAnchorTarget;
|
|
15
17
|
items?: DocumentationSidebarItem[];
|
|
18
|
+
content?: string; // Optional: MDX content for searching
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
export interface DocumentationSidebarProps {
|
|
@@ -26,6 +29,90 @@ export interface DocumentationSidebarProps {
|
|
|
26
29
|
|
|
27
30
|
const CLASS_ROOT = "documentation-sidebar";
|
|
28
31
|
|
|
32
|
+
interface SearchResult {
|
|
33
|
+
id: string;
|
|
34
|
+
label: string;
|
|
35
|
+
href: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface IndexedItem {
|
|
39
|
+
id: string;
|
|
40
|
+
label: string;
|
|
41
|
+
href: string;
|
|
42
|
+
content: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
interface MiniSearchResult {
|
|
46
|
+
id: string;
|
|
47
|
+
label?: string;
|
|
48
|
+
href?: string;
|
|
49
|
+
score?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Flatten and index all menu items for search
|
|
53
|
+
const flattenMenuItems = (
|
|
54
|
+
items: DocumentationSidebarItem[],
|
|
55
|
+
indexedItems: IndexedItem[] = [],
|
|
56
|
+
): IndexedItem[] => {
|
|
57
|
+
items.forEach((item) => {
|
|
58
|
+
if (item.href) {
|
|
59
|
+
indexedItems.push({
|
|
60
|
+
id: item.href,
|
|
61
|
+
label: item.label,
|
|
62
|
+
href: item.href,
|
|
63
|
+
content: `${item.label} ${item.content || ""}`,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (item.items && item.items.length > 0) {
|
|
67
|
+
flattenMenuItems(item.items, indexedItems);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
return indexedItems;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Initialize MiniSearch with indexed items
|
|
74
|
+
const initializeSearch = (items: DocumentationSidebarItem[]) => {
|
|
75
|
+
const indexedItems = flattenMenuItems(items);
|
|
76
|
+
const miniSearch = new MiniSearch({
|
|
77
|
+
fields: ["label", "content"],
|
|
78
|
+
storeFields: ["id", "label", "href"],
|
|
79
|
+
});
|
|
80
|
+
miniSearch.addAll(indexedItems);
|
|
81
|
+
return miniSearch;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Merge search index from MDX files with menu items
|
|
85
|
+
const mergeSearchIndex = (
|
|
86
|
+
items: DocumentationSidebarItem[],
|
|
87
|
+
indexData: Array<{ href: string; content: string }>,
|
|
88
|
+
): DocumentationSidebarItem[] => {
|
|
89
|
+
const contentMap = new Map(
|
|
90
|
+
indexData.map((item) => [item.href, item.content]),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
const merge = (
|
|
94
|
+
items: DocumentationSidebarItem[],
|
|
95
|
+
): DocumentationSidebarItem[] => {
|
|
96
|
+
return items.map((item) => {
|
|
97
|
+
const mergedItem = { ...item };
|
|
98
|
+
|
|
99
|
+
// Add content from search index if available and not already set
|
|
100
|
+
if (item.href && !item.content && contentMap.has(item.href)) {
|
|
101
|
+
mergedItem.content = contentMap.get(item.href);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Recursively merge child items
|
|
105
|
+
if (item.items) {
|
|
106
|
+
mergedItem.items = merge(item.items);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return mergedItem;
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return merge(items);
|
|
114
|
+
};
|
|
115
|
+
|
|
29
116
|
const SidebarItem: React.FC<{
|
|
30
117
|
item: DocumentationSidebarItem;
|
|
31
118
|
pathname: string;
|
|
@@ -142,12 +229,63 @@ export const DocumentationSidebar: React.FC<DocumentationSidebarProps> = (
|
|
|
142
229
|
const { items, className, onChangeHref, children } = props;
|
|
143
230
|
|
|
144
231
|
const [isMenuOpenOnMobile, setIsMenuOpenOnMobile] = React.useState(false);
|
|
232
|
+
const [searchQuery, setSearchQuery] = React.useState("");
|
|
233
|
+
const [searchResults, setSearchResults] = React.useState<SearchResult[]>([]);
|
|
234
|
+
const [miniSearch, setMiniSearch] = React.useState<MiniSearch | null>(null);
|
|
145
235
|
const pathname = usePathname();
|
|
146
236
|
const sidebarRef = React.useRef<HTMLElement>(null);
|
|
147
237
|
|
|
238
|
+
// Initialize search on mount
|
|
239
|
+
React.useEffect(() => {
|
|
240
|
+
const search = initializeSearch(items);
|
|
241
|
+
setMiniSearch(search);
|
|
242
|
+
|
|
243
|
+
// Load additional content from search index if available
|
|
244
|
+
const loadSearchIndex = async () => {
|
|
245
|
+
try {
|
|
246
|
+
const response = await fetch("/search-index.json");
|
|
247
|
+
if (!response.ok) throw new Error("Failed to fetch search index");
|
|
248
|
+
const indexData = await response.json();
|
|
249
|
+
|
|
250
|
+
// Re-initialize search with both menu items and indexed MDX content
|
|
251
|
+
const mergedItems = mergeSearchIndex(items, indexData);
|
|
252
|
+
const updatedSearch = initializeSearch(mergedItems);
|
|
253
|
+
setMiniSearch(updatedSearch);
|
|
254
|
+
} catch (err) {
|
|
255
|
+
// Search index not found or fetch failed, continue with menu items only
|
|
256
|
+
console.debug("Search index not available, using menu items only");
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
loadSearchIndex();
|
|
261
|
+
}, [items]);
|
|
262
|
+
|
|
263
|
+
// Handle search input
|
|
264
|
+
const handleSearch = (query: string) => {
|
|
265
|
+
setSearchQuery(query);
|
|
266
|
+
if (query.trim() && miniSearch) {
|
|
267
|
+
const results = miniSearch.search(query, {
|
|
268
|
+
boost: { label: 10 },
|
|
269
|
+
fuzzy: (term) => {
|
|
270
|
+
// Allow 1 character difference for short terms, more for longer terms
|
|
271
|
+
return term.length > 3 ? 0.2 : 0.3;
|
|
272
|
+
},
|
|
273
|
+
prefix: true, // Enable prefix matching (search "text" matches "text-secondary")
|
|
274
|
+
combineWith: "AND", // Require all terms to match
|
|
275
|
+
}) as unknown as SearchResult[];
|
|
276
|
+
setSearchResults(results.slice(0, 10)); // Limit to 10 results
|
|
277
|
+
} else {
|
|
278
|
+
setSearchResults([]);
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
|
|
148
282
|
React.useEffect(() => {
|
|
149
283
|
const handleEsc = (event: KeyboardEvent) => {
|
|
150
|
-
if (event.key === "Escape")
|
|
284
|
+
if (event.key === "Escape") {
|
|
285
|
+
setIsMenuOpenOnMobile(false);
|
|
286
|
+
setSearchQuery("");
|
|
287
|
+
setSearchResults([]);
|
|
288
|
+
}
|
|
151
289
|
};
|
|
152
290
|
document.addEventListener("keydown", handleEsc);
|
|
153
291
|
return () => document.removeEventListener("keydown", handleEsc);
|
|
@@ -171,6 +309,8 @@ export const DocumentationSidebar: React.FC<DocumentationSidebarProps> = (
|
|
|
171
309
|
const handleSelect = (href: string) => {
|
|
172
310
|
onChangeHref?.(href);
|
|
173
311
|
setIsMenuOpenOnMobile(false);
|
|
312
|
+
setSearchQuery("");
|
|
313
|
+
setSearchResults([]);
|
|
174
314
|
};
|
|
175
315
|
|
|
176
316
|
const classes = cx(CLASS_ROOT, className, {
|
|
@@ -197,7 +337,53 @@ export const DocumentationSidebar: React.FC<DocumentationSidebarProps> = (
|
|
|
197
337
|
>
|
|
198
338
|
<Image src="/logo.svg" alt="logo" />
|
|
199
339
|
|
|
200
|
-
<
|
|
340
|
+
<div className={`${CLASS_ROOT}__search-container`}>
|
|
341
|
+
<TextInput
|
|
342
|
+
id="search-documentation"
|
|
343
|
+
htmlType="search"
|
|
344
|
+
placeholder="Search documentation..."
|
|
345
|
+
value={searchQuery}
|
|
346
|
+
onChange={(e) => handleSearch(e.currentTarget.value)}
|
|
347
|
+
width="fullwidth"
|
|
348
|
+
aria-label="Search documentation"
|
|
349
|
+
/>
|
|
350
|
+
{searchQuery && (
|
|
351
|
+
<button
|
|
352
|
+
type="button"
|
|
353
|
+
className={`${CLASS_ROOT}__search-clear`}
|
|
354
|
+
onClick={() => {
|
|
355
|
+
setSearchQuery("");
|
|
356
|
+
setSearchResults([]);
|
|
357
|
+
}}
|
|
358
|
+
aria-label="Clear search"
|
|
359
|
+
>
|
|
360
|
+
✕
|
|
361
|
+
</button>
|
|
362
|
+
)}
|
|
363
|
+
</div>
|
|
364
|
+
|
|
365
|
+
{searchResults.length > 0 && (
|
|
366
|
+
<div className={`${CLASS_ROOT}__search-results`}>
|
|
367
|
+
<ul className={`${CLASS_ROOT}__search-list`}>
|
|
368
|
+
{searchResults.map((result) => (
|
|
369
|
+
<li key={result.id}>
|
|
370
|
+
<Link
|
|
371
|
+
href={result.href}
|
|
372
|
+
className={`${CLASS_ROOT}__search-result-link`}
|
|
373
|
+
onClick={() => handleSelect(result.href)}
|
|
374
|
+
>
|
|
375
|
+
{result.label}
|
|
376
|
+
</Link>
|
|
377
|
+
</li>
|
|
378
|
+
))}
|
|
379
|
+
</ul>
|
|
380
|
+
</div>
|
|
381
|
+
)}
|
|
382
|
+
|
|
383
|
+
<nav
|
|
384
|
+
className={`${CLASS_ROOT}__nav`}
|
|
385
|
+
style={{ display: searchResults.length > 0 ? "none" : "block" }}
|
|
386
|
+
>
|
|
201
387
|
<ul className={`${CLASS_ROOT}__list`}>
|
|
202
388
|
{items.map((item, index) => (
|
|
203
389
|
<SidebarItem
|
|
@@ -201,6 +201,79 @@
|
|
|
201
201
|
padding-left: convert.to-rem(15px);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
// Search styles
|
|
205
|
+
&__search-container {
|
|
206
|
+
position: relative;
|
|
207
|
+
margin-bottom: 16px;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
&__search-clear {
|
|
211
|
+
position: absolute;
|
|
212
|
+
right: 8px;
|
|
213
|
+
top: 50%;
|
|
214
|
+
transform: translateY(-50%);
|
|
215
|
+
border: none;
|
|
216
|
+
background: none;
|
|
217
|
+
color: #999;
|
|
218
|
+
cursor: pointer;
|
|
219
|
+
padding: 4px 8px;
|
|
220
|
+
font-size: 1rem;
|
|
221
|
+
line-height: 1;
|
|
222
|
+
|
|
223
|
+
&:hover {
|
|
224
|
+
color: var(--color-text-default);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
&:focus-visible {
|
|
228
|
+
outline: 2px solid var(--color-border-accent);
|
|
229
|
+
outline-offset: 2px;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
&__search-results {
|
|
234
|
+
margin-bottom: 16px;
|
|
235
|
+
border: 1px solid var(--color-border-subtle);
|
|
236
|
+
border-radius: convert.to-rem(5px);
|
|
237
|
+
background: white;
|
|
238
|
+
max-height: 400px;
|
|
239
|
+
overflow-y: auto;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
&__search-list {
|
|
243
|
+
list-style: none;
|
|
244
|
+
margin: 0;
|
|
245
|
+
padding: 0;
|
|
246
|
+
|
|
247
|
+
li {
|
|
248
|
+
margin: 0;
|
|
249
|
+
padding: 0;
|
|
250
|
+
border-bottom: 1px solid var(--color-border-subtle);
|
|
251
|
+
|
|
252
|
+
&:last-child {
|
|
253
|
+
border-bottom: none;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
&__search-result-link {
|
|
259
|
+
display: block;
|
|
260
|
+
padding: 8px 12px;
|
|
261
|
+
color: #666;
|
|
262
|
+
text-decoration: none;
|
|
263
|
+
font-size: 0.9rem;
|
|
264
|
+
transition: background-color 0.2s ease;
|
|
265
|
+
|
|
266
|
+
&:hover {
|
|
267
|
+
background-color: var(--color-surface-subtle);
|
|
268
|
+
color: var(--color-text-default);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
&:focus-visible {
|
|
272
|
+
outline: 2px solid var(--color-border-accent);
|
|
273
|
+
outline-offset: -2px;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
204
277
|
// Mobile behavior - below lg breakpoint (992px)
|
|
205
278
|
@include breakpoint.get(lg, downfrom) {
|
|
206
279
|
grid-template-columns: 1fr;
|
|
@@ -18,7 +18,7 @@ export interface LinkProps {
|
|
|
18
18
|
isUnderline?: boolean;
|
|
19
19
|
/** whether the link should have normal font weight */
|
|
20
20
|
isNormal?: boolean;
|
|
21
|
-
/** when true, adds the .
|
|
21
|
+
/** when true, adds the .no-accent modifier to disable orange accent color on hover (useful for dark backgrounds) */
|
|
22
22
|
noAccent?: boolean;
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -40,7 +40,7 @@ export const Link: React.FC<LinkProps & React.HTMLAttributes<HTMLElement>> = ({
|
|
|
40
40
|
"is-light": colorScheme === "light",
|
|
41
41
|
underline: isUnderline,
|
|
42
42
|
normal: isNormal,
|
|
43
|
-
"
|
|
43
|
+
"no-accent": noAccent,
|
|
44
44
|
},
|
|
45
45
|
className,
|
|
46
46
|
);
|
|
@@ -64,7 +64,11 @@ const example = (
|
|
|
64
64
|
it("is valid html", () => {
|
|
65
65
|
const { container } = render(example);
|
|
66
66
|
expect(container).toHTMLValidate({
|
|
67
|
-
rules: {
|
|
67
|
+
rules: {
|
|
68
|
+
"attribute-boolean-style": "off",
|
|
69
|
+
"valid-id": "off",
|
|
70
|
+
"attribute-empty-style": "off",
|
|
71
|
+
},
|
|
68
72
|
});
|
|
69
73
|
});
|
|
70
74
|
|
|
@@ -34,7 +34,11 @@ const example = (
|
|
|
34
34
|
it("is valid html", () => {
|
|
35
35
|
const { container } = render(example);
|
|
36
36
|
expect(container).toHTMLValidate({
|
|
37
|
-
rules: {
|
|
37
|
+
rules: {
|
|
38
|
+
"no-inline-style": "off",
|
|
39
|
+
"attribute-boolean-style": "off",
|
|
40
|
+
"attribute-empty-style": "off",
|
|
41
|
+
},
|
|
38
42
|
});
|
|
39
43
|
});
|
|
40
44
|
|
|
@@ -1,42 +1,6 @@
|
|
|
1
1
|
@use "../tokens/base";
|
|
2
2
|
@use "../tokens/space";
|
|
3
|
-
@use "../tokens/color";
|
|
4
|
-
@use "../tokens/tag-colors";
|
|
5
|
-
|
|
6
|
-
// Consider to add more conditions for light and dark themes
|
|
7
|
-
:root,
|
|
8
|
-
:host,
|
|
9
|
-
:host(.is-light),
|
|
10
|
-
.is-light,
|
|
11
|
-
.bg-white,
|
|
12
|
-
#root.is-light,
|
|
13
|
-
#root-modals.is-light,
|
|
14
|
-
#root-tooltips.is-light,
|
|
15
|
-
#root-dropdowns.is-light {
|
|
16
|
-
@each $name, $value in color.$colors-light {
|
|
17
|
-
--color-#{$name}: #{$value};
|
|
18
|
-
}
|
|
19
|
-
@each $name, $value in tag-colors.$tag-colors-light {
|
|
20
|
-
--#{$name}: #{$value};
|
|
21
|
-
}
|
|
22
|
-
color: var(--color-text-default);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
:host(.is-dark),
|
|
26
|
-
.is-dark,
|
|
27
|
-
.bg-black,
|
|
28
|
-
#root.is-dark,
|
|
29
|
-
#root-modals.is-dark,
|
|
30
|
-
#root-tooltips.is-dark,
|
|
31
|
-
#root-dropdowns.is-dark {
|
|
32
|
-
@each $name, $value in color.$colors-dark {
|
|
33
|
-
--color-#{$name}: #{$value};
|
|
34
|
-
}
|
|
35
|
-
@each $name, $value in tag-colors.$tag-colors-dark {
|
|
36
|
-
--#{$name}: #{$value};
|
|
37
|
-
}
|
|
38
|
-
color: var(--color-text-default);
|
|
39
|
-
}
|
|
3
|
+
@use "../tokens/color-vars";
|
|
40
4
|
|
|
41
5
|
:root,
|
|
42
6
|
:host {
|
|
@@ -12,12 +12,12 @@ export const exports = {
|
|
|
12
12
|
"violet": "#a885d8",
|
|
13
13
|
"yellow": "#ffd200",
|
|
14
14
|
"gray-300": "#eeeeee",
|
|
15
|
-
"gray-400": "#
|
|
15
|
+
"gray-400": "#dddddd",
|
|
16
16
|
"gray-500": "#dddddd",
|
|
17
17
|
"gray-600": "#999",
|
|
18
18
|
"gray-700": "#666666",
|
|
19
|
-
"gray-800": "#
|
|
20
|
-
"gray-900": "#
|
|
19
|
+
"gray-800": "#666666",
|
|
20
|
+
"gray-900": "#333333",
|
|
21
21
|
"success": "rgba(34, 135, 34, 0.0784313725)",
|
|
22
22
|
"danger": "rgba(205, 60, 20, 0.0784313725)",
|
|
23
23
|
"info": "rgba(65, 112, 216, 0.0784313725)",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
@use "sass:map";
|
|
2
|
+
@use "./color";
|
|
3
|
+
@use "./tag-colors";
|
|
4
|
+
|
|
5
|
+
// Light theme CSS variables
|
|
6
|
+
:root,
|
|
7
|
+
:host,
|
|
8
|
+
:host(.is-light),
|
|
9
|
+
.is-light,
|
|
10
|
+
.bg-white,
|
|
11
|
+
#root.is-light,
|
|
12
|
+
#root-modals.is-light,
|
|
13
|
+
#root-tooltips.is-light,
|
|
14
|
+
#root-dropdowns.is-light {
|
|
15
|
+
@each $name, $value in color.$colors-light {
|
|
16
|
+
--color-#{$name}: #{$value};
|
|
17
|
+
}
|
|
18
|
+
@each $name, $value in tag-colors.$tag-colors-light {
|
|
19
|
+
--#{$name}: #{$value};
|
|
20
|
+
}
|
|
21
|
+
color: var(--color-text-default);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Dark theme CSS variables
|
|
25
|
+
:host(.is-dark),
|
|
26
|
+
.is-dark,
|
|
27
|
+
.bg-black,
|
|
28
|
+
#root.is-dark,
|
|
29
|
+
#root-modals.is-dark,
|
|
30
|
+
#root-tooltips.is-dark,
|
|
31
|
+
#root-dropdowns.is-dark {
|
|
32
|
+
@each $name, $value in color.$colors-dark {
|
|
33
|
+
--color-#{$name}: #{$value};
|
|
34
|
+
}
|
|
35
|
+
@each $name, $value in tag-colors.$tag-colors-dark {
|
|
36
|
+
--#{$name}: #{$value};
|
|
37
|
+
}
|
|
38
|
+
color: var(--color-text-default);
|
|
39
|
+
}
|