diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a8c101f5..99e3e948 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -88,7 +88,7 @@ importers:
version: 1.0.3
'@types/node':
specifier: 20.11.21
- version: 20.11.22
+ version: 20.11.21
'@types/yargs':
specifier: 17.0.32
version: 17.0.32
@@ -121,13 +121,13 @@ importers:
version: link:../packages/icons/react
geist:
specifier: 1.2.2
- version: 1.2.2(next@14.1.0)
+ version: 1.2.2(next@14.1.1-canary.80)
next:
- specifier: 14.1.0
- version: 14.1.0(react-dom@18.2.0)(react@18.2.0)
+ specifier: 14.1.1-canary.80
+ version: 14.1.1-canary.80(react-dom@18.2.0)(react@18.2.0)
next-themes:
specifier: 0.2.1
- version: 0.2.1(next@14.1.0)(react-dom@18.2.0)(react@18.2.0)
+ version: 0.2.1(next@14.1.1-canary.80)(react-dom@18.2.0)(react@18.2.0)
react:
specifier: ^18
version: 18.2.0
@@ -747,8 +747,8 @@ packages:
resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==}
dev: true
- /@next/env@14.1.0:
- resolution: {integrity: sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==}
+ /@next/env@14.1.1-canary.80:
+ resolution: {integrity: sha512-wOC/paUahuvf/AE/oe3mnvZgi1lTKdM1NUlutr9+4mGz+C+Mw4doPu628vYu7UiKtTuUxRHFgGslKC9oeTvjhw==}
dev: false
/@next/eslint-plugin-next@14.1.0:
@@ -757,8 +757,8 @@ packages:
glob: 10.3.10
dev: true
- /@next/swc-darwin-arm64@14.1.0:
- resolution: {integrity: sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==}
+ /@next/swc-darwin-arm64@14.1.1-canary.80:
+ resolution: {integrity: sha512-rRvpAq7BNzsaqqktu/NuFUt9ZkH9ZADEAFsgsFEsyUmpAjLE6d/o+GeyfiRWvvs8Lcl+NDoEta/iT4FYwEUG1g==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
@@ -766,8 +766,8 @@ packages:
dev: false
optional: true
- /@next/swc-darwin-x64@14.1.0:
- resolution: {integrity: sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==}
+ /@next/swc-darwin-x64@14.1.1-canary.80:
+ resolution: {integrity: sha512-lEC0LUr7ZIpGnsdNccFmEQ1I/YXIZBBfwmCMpFtF3DjJXSX92HK31IWbBzL9cGHUQcaq3L+Wyva8TlsNR0e80w==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
@@ -775,8 +775,8 @@ packages:
dev: false
optional: true
- /@next/swc-linux-arm64-gnu@14.1.0:
- resolution: {integrity: sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==}
+ /@next/swc-linux-arm64-gnu@14.1.1-canary.80:
+ resolution: {integrity: sha512-I+wuvjUUh9KFYXNwPwV4UWwBDXthLV6C5LCtcp0jPwDJrgdXTyMD3v+P6aJ/xOWbyv/nWOJVW9PBOVIeYL+TqA==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@@ -784,8 +784,8 @@ packages:
dev: false
optional: true
- /@next/swc-linux-arm64-musl@14.1.0:
- resolution: {integrity: sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==}
+ /@next/swc-linux-arm64-musl@14.1.1-canary.80:
+ resolution: {integrity: sha512-6WJ+Agyiidq2o5rUJOyBINmbUBL1EdXOIDF6zuNgC1REoeXdhqFf3oB1KoJatXgjlhMyltOoepgutuZWJDZ+Zg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@@ -793,8 +793,8 @@ packages:
dev: false
optional: true
- /@next/swc-linux-x64-gnu@14.1.0:
- resolution: {integrity: sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ==}
+ /@next/swc-linux-x64-gnu@14.1.1-canary.80:
+ resolution: {integrity: sha512-szjzs8GvhdxyC0fbXT0JlDMDVkAgqYQs3iN3yzF4UMhfRM9VVyBSJYiHPhTrXUatlZ8h9SlMoP5YuN0ZBSbqoA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@@ -802,8 +802,8 @@ packages:
dev: false
optional: true
- /@next/swc-linux-x64-musl@14.1.0:
- resolution: {integrity: sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg==}
+ /@next/swc-linux-x64-musl@14.1.1-canary.80:
+ resolution: {integrity: sha512-Nek2e3aKt9tjN3YdAGFetjRVtxdIBK8A9iPnVCGrYuy2ERpAwsupOk8nmMzIlp1kGxxGsLWL1vBojQwjukKWkg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@@ -811,8 +811,8 @@ packages:
dev: false
optional: true
- /@next/swc-win32-arm64-msvc@14.1.0:
- resolution: {integrity: sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==}
+ /@next/swc-win32-arm64-msvc@14.1.1-canary.80:
+ resolution: {integrity: sha512-aPnjiYjduvB5ut7juZ4g/mc9aY8MCsQESrSH5/dQVZJF5o6JzcNj+0D21J1/oeqiBOVsvn1LMjNOMU762t0gHQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
@@ -820,8 +820,8 @@ packages:
dev: false
optional: true
- /@next/swc-win32-ia32-msvc@14.1.0:
- resolution: {integrity: sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==}
+ /@next/swc-win32-ia32-msvc@14.1.1-canary.80:
+ resolution: {integrity: sha512-n0u0CofRBEx35Nn6mxS1o4o1+dseR9GhTuVqj6Zy2xIby66IjuuxKuLD49Ufg9qsj1oCAkJpsToJqmqisc4Eyg==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
@@ -829,8 +829,8 @@ packages:
dev: false
optional: true
- /@next/swc-win32-x64-msvc@14.1.0:
- resolution: {integrity: sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==}
+ /@next/swc-win32-x64-msvc@14.1.1-canary.80:
+ resolution: {integrity: sha512-eNTkUJVB2JyPxnf9iDEMEkMFPrxb1lA32Mk0H7kl7EndQ0hNmSnDbcBLji3J2jBFcTK8ok0FH5sZH3c/lxR8aw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@@ -1212,9 +1212,14 @@ packages:
- supports-color
dev: true
- /@swc/helpers@0.5.2:
- resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==}
+ /@swc/counter@0.1.3:
+ resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
+ dev: false
+
+ /@swc/helpers@0.5.5:
+ resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==}
dependencies:
+ '@swc/counter': 0.1.3
tslib: 2.6.2
dev: false
@@ -1267,10 +1272,17 @@ packages:
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
dev: true
+ /@types/node@20.11.21:
+ resolution: {integrity: sha512-/ySDLGscFPNasfqStUuWWPfL78jompfIoVzLJPVVAHBh6rpG68+pI2Gk+fNLeI8/f1yPYL4s46EleVIc20F1Ow==}
+ dependencies:
+ undici-types: 5.26.5
+ dev: false
+
/@types/node@20.11.22:
resolution: {integrity: sha512-/G+IxWxma6V3E+pqK1tSl2Fo1kl41pK1yeCyDsgkF9WlVAme4j5ISYM2zR11bgLFJGLN5sVK40T4RJNuiZbEjA==}
dependencies:
undici-types: 5.26.5
+ dev: true
/@types/prop-types@15.7.11:
resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==}
@@ -3561,12 +3573,12 @@ packages:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
dev: true
- /geist@1.2.2(next@14.1.0):
+ /geist@1.2.2(next@14.1.1-canary.80):
resolution: {integrity: sha512-uRDrxhvdnPwWJmh+K5+/5LXSKwvJzaYCl9tDXgiBi4hj7hB4K7+n/WLcvJMFs5btvyn0r9OSwCd1s6CmqAsxEw==}
peerDependencies:
next: '>=13.2.0 <15'
dependencies:
- next: 14.1.0(react-dom@18.2.0)(react@18.2.0)
+ next: 14.1.1-canary.80(react-dom@18.2.0)(react@18.2.0)
dev: false
/get-caller-file@2.0.5:
@@ -4684,20 +4696,20 @@ packages:
type-fest: 2.19.0
dev: true
- /next-themes@0.2.1(next@14.1.0)(react-dom@18.2.0)(react@18.2.0):
+ /next-themes@0.2.1(next@14.1.1-canary.80)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==}
peerDependencies:
next: '*'
react: '*'
react-dom: '*'
dependencies:
- next: 14.1.0(react-dom@18.2.0)(react@18.2.0)
+ next: 14.1.1-canary.80(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
- /next@14.1.0(react-dom@18.2.0)(react@18.2.0):
- resolution: {integrity: sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==}
+ /next@14.1.1-canary.80(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-mjAz6ssshgYAtYxH4dzvZ57P0jTgbcMHsBLx6Rc7Nlh5vL2STILlDDndd4gAubbop7K4+ZTjvaI5l+sE8BHc7g==}
engines: {node: '>=18.17.0'}
hasBin: true
peerDependencies:
@@ -4711,8 +4723,8 @@ packages:
sass:
optional: true
dependencies:
- '@next/env': 14.1.0
- '@swc/helpers': 0.5.2
+ '@next/env': 14.1.1-canary.80
+ '@swc/helpers': 0.5.5
busboy: 1.6.0
caniuse-lite: 1.0.30001591
graceful-fs: 4.2.11
@@ -4721,15 +4733,15 @@ packages:
react-dom: 18.2.0(react@18.2.0)
styled-jsx: 5.1.1(react@18.2.0)
optionalDependencies:
- '@next/swc-darwin-arm64': 14.1.0
- '@next/swc-darwin-x64': 14.1.0
- '@next/swc-linux-arm64-gnu': 14.1.0
- '@next/swc-linux-arm64-musl': 14.1.0
- '@next/swc-linux-x64-gnu': 14.1.0
- '@next/swc-linux-x64-musl': 14.1.0
- '@next/swc-win32-arm64-msvc': 14.1.0
- '@next/swc-win32-ia32-msvc': 14.1.0
- '@next/swc-win32-x64-msvc': 14.1.0
+ '@next/swc-darwin-arm64': 14.1.1-canary.80
+ '@next/swc-darwin-x64': 14.1.1-canary.80
+ '@next/swc-linux-arm64-gnu': 14.1.1-canary.80
+ '@next/swc-linux-arm64-musl': 14.1.1-canary.80
+ '@next/swc-linux-x64-gnu': 14.1.1-canary.80
+ '@next/swc-linux-x64-musl': 14.1.1-canary.80
+ '@next/swc-win32-arm64-msvc': 14.1.1-canary.80
+ '@next/swc-win32-ia32-msvc': 14.1.1-canary.80
+ '@next/swc-win32-x64-msvc': 14.1.1-canary.80
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
diff --git a/website/package.json b/website/package.json
index e41d8edc..a68e262e 100644
--- a/website/package.json
+++ b/website/package.json
@@ -14,7 +14,7 @@
"@untitled-theme/colors": "workspace:*",
"@untitled-theme/icons-react": "workspace:*",
"geist": "1.2.2",
- "next": "14.1.0",
+ "next": "14.1.1-canary.80",
"next-themes": "0.2.1",
"react": "^18",
"react-dom": "^18",
diff --git a/website/src/@modal/(.)icons/[slug]/default.tsx b/website/src/@modal/(.)icons/[slug]/default.tsx
new file mode 100644
index 00000000..6ddf1b76
--- /dev/null
+++ b/website/src/@modal/(.)icons/[slug]/default.tsx
@@ -0,0 +1,3 @@
+export default function Default() {
+ return null;
+}
diff --git a/website/src/@modal/(.)icons/[slug]/page.tsx b/website/src/@modal/(.)icons/[slug]/page.tsx
new file mode 100644
index 00000000..d5834629
--- /dev/null
+++ b/website/src/@modal/(.)icons/[slug]/page.tsx
@@ -0,0 +1,19 @@
+import {Dialog} from '@ark-ui/react';
+import {XCloseIcon} from '@untitled-theme/icons-react';
+
+export default function IconDetailsModal() {
+ return (
+
+
+
+
+ It works
+
+
+
+
+
+
+
+ );
+}
diff --git a/website/src/@modal/(.)icons/default.tsx b/website/src/@modal/(.)icons/default.tsx
new file mode 100644
index 00000000..6ddf1b76
--- /dev/null
+++ b/website/src/@modal/(.)icons/default.tsx
@@ -0,0 +1,3 @@
+export default function Default() {
+ return null;
+}
diff --git a/website/src/app/(index)/gallery.tsx b/website/src/app/(index)/gallery.tsx
deleted file mode 100644
index 05c2a02e..00000000
--- a/website/src/app/(index)/gallery.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-'use client';
-
-import {Tooltip} from '@ark-ui/react';
-import {twMerge} from 'tailwind-merge';
-import {usePageContext} from './page-context';
-import type {Icon} from './types';
-
-export function Gallery() {
- const context = usePageContext();
-
- return (
-
- {context.icons.map((item) => (
-
- ))}
-
- );
-}
-
-function GalleryItem({data}: {data: Icon}) {
- const context = usePageContext();
-
- return (
-
- context.inspect(data)}
- dangerouslySetInnerHTML={{
- __html: data.content,
- }}
- className="flex aspect-square items-center justify-center rounded border p-2 transition duration-200 hover:bg-gray-true-50 focus:shadow-outline dark:hover:bg-gray-true-800/10"
- aria-label={data.displayName}
- />
-
-
-
-
-
-
-
- {data.displayName}
-
-
-
- );
-}
diff --git a/website/src/app/(index)/icon-details.tsx b/website/src/app/(index)/icon-details.tsx
deleted file mode 100644
index 81b125c4..00000000
--- a/website/src/app/(index)/icon-details.tsx
+++ /dev/null
@@ -1,162 +0,0 @@
-'use client';
-
-import {Spinner} from '@/lib/spinner';
-import {Syntax} from '@/lib/syntax';
-import {Clipboard, Dialog, Tabs} from '@ark-ui/react';
-import {CheckIcon, Copy01Icon, XCloseIcon} from '@untitled-theme/icons-react';
-import {useCallback, useEffect, useState} from 'react';
-import {usePageContext} from './page-context';
-import {toHtmlComponent, toReactComponent, toSvelteComponent} from './utils';
-
-export function IconDetails() {
- const context = usePageContext();
- const [loading, setLoading] = useState(false);
-
- const [htmlComponent, setHtmlComponent] = useState('');
- const [reactComponent, setReactComponent] = useState('');
- const [svelteComponent, setSvelteComponent] = useState('');
-
- const parseAll = useCallback(async () => {
- if (!context.inspectionSubject) return;
-
- setLoading(true);
-
- const [h, r, s] = await Promise.all([
- toHtmlComponent(context.inspectionSubject),
- toReactComponent(context.inspectionSubject),
- toSvelteComponent(context.inspectionSubject),
- ]);
-
- setHtmlComponent(h);
- setReactComponent(r);
- setSvelteComponent(s);
-
- setLoading(false);
- }, [context.inspectionSubject]);
-
- useEffect(() => {
- parseAll();
- }, [parseAll]);
-
- useEffect(() => {
- return () => {
- setHtmlComponent('');
- setReactComponent('');
- setSvelteComponent('');
- setLoading(false);
- };
- }, []);
-
- const items = [
- {
- label: 'SVG',
- value: 'html' as const,
- content: htmlComponent,
- },
- {
- label: 'React',
- value: 'tsx' as const,
- content: reactComponent,
- },
- {
- label: 'Svelte',
- value: 'svelte' as const,
- content: svelteComponent,
- },
- ];
-
- return (
- {
- if (!open) {
- context.inspect.dismiss();
- }
- }}
- lazyMount
- unmountOnExit
- >
-
-
-
-
-
-
-
- <{context.inspectionSubject?.displayName ?? ''} />
-
-
- Copy
-
-
- }
- >
-
-
-
-
-
-
-
-
- {items.map((item) => (
-
- {item.label}
-
- ))}
-
-
- {items.map((item) => {
- return (
-
-
- {loading && }
- {!loading && (
- <>
-
- Copy
-
-
- }
- >
-
-
-
-
-
-
- {item.content}
-
- >
- )}
-
-
- );
- })}
-
-
-
-
-
-
-
-
-
- );
-}
diff --git a/website/src/app/(index)/page-context.tsx b/website/src/app/(index)/page-context.tsx
deleted file mode 100644
index ced9b7a4..00000000
--- a/website/src/app/(index)/page-context.tsx
+++ /dev/null
@@ -1,64 +0,0 @@
-'use client';
-
-import {useDebounce} from '@/lib/use-debounce';
-import {
- createContext,
- useContext,
- useEffect,
- useMemo,
- useState,
- type PropsWithChildren,
-} from 'react';
-import type {Icon} from './types';
-
-export const PageContext = createContext(undefined as unknown as UsePageReturn);
-export const usePageContext = () => useContext(PageContext);
-export const PageProvider = (props: PropsWithChildren) => {
- return {props.children};
-};
-
-interface UsePageProps {
- items?: Icon[];
-}
-
-type UsePageReturn = ReturnType;
-
-function usePage(props: UsePageProps) {
- const [searchKeyword, setSearchKeyword] = useState('');
- const debouncedKeyword = useDebounce(searchKeyword);
- const search = (keyword: string) => setSearchKeyword(keyword);
- search.stop = () => setSearchKeyword('');
-
- const icons = useMemo(() => {
- if (!props.items) return [];
-
- return props.items.filter((item) => {
- return item.displayName
- .toLowerCase()
- .replace(/ /g, '')
- .includes(debouncedKeyword.toLowerCase().replace(/ /g, ''));
- });
- }, [props.items, debouncedKeyword]);
-
- const iconsCount = icons.length;
-
- const [inspectionSubject, setInspectionSubject] = useState();
- const inspect = (subject: Icon) => setInspectionSubject(subject);
- inspect.dismiss = () => setInspectionSubject(null);
-
- useEffect(() => {
- return function reset() {
- setSearchKeyword('');
- setInspectionSubject(null);
- };
- }, []);
-
- return {
- icons,
- iconsCount,
- search,
- searchKeyword,
- inspect,
- inspectionSubject,
- };
-}
diff --git a/website/src/app/(index)/page.tsx b/website/src/app/(index)/page.tsx
deleted file mode 100644
index 50a60419..00000000
--- a/website/src/app/(index)/page.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import {Gallery} from './gallery';
-import {IconDetails} from './icon-details';
-import {PageProvider} from './page-context';
-import {Searchbar} from './searchbar';
-import {Total} from './total';
-import {getIcons} from './utils.server';
-
-export default async function Landing() {
- return (
-
-
-
-
-
-
-
-
- );
-}
diff --git a/website/src/app/(index)/searchbar.tsx b/website/src/app/(index)/searchbar.tsx
deleted file mode 100644
index 19cb84d3..00000000
--- a/website/src/app/(index)/searchbar.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-'use client';
-
-import {Presence} from '@ark-ui/react';
-import {SearchLgIcon, XCloseIcon} from '@untitled-theme/icons-react';
-import {useRef} from 'react';
-import {twMerge} from 'tailwind-merge';
-import {usePageContext} from './page-context';
-
-export function Searchbar() {
- const context = usePageContext();
- const inputRef = useRef(null);
-
- return (
-
-
{
- context.search(e.target.value);
- }}
- placeholder="Search"
- className={twMerge(
- 'h-12 w-full rounded border py-2 pl-12 outline-none focus:shadow-outline',
- context.searchKeyword ? 'pr-10' : 'pr-4',
- )}
- />
-
-
-
-
-
-
-
- );
-}
diff --git a/website/src/app/(index)/total.tsx b/website/src/app/(index)/total.tsx
deleted file mode 100644
index 9200e31a..00000000
--- a/website/src/app/(index)/total.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-'use client';
-
-import {usePageContext} from './page-context';
-
-export function Total() {
- const context = usePageContext();
-
- let s: string[] = [];
-
- if (context.iconsCount === 0) {
- s.push('No icons found');
- } else if (context.iconsCount === 1) {
- s.push('1 icon found');
- } else {
- s.push(`${context.iconsCount} icons found`);
- }
-
- if (context.searchKeyword) {
- s.push(`for '${context.searchKeyword}'`);
- }
-
- return (
-
- );
-}
diff --git a/website/src/app/(index)/types.ts b/website/src/app/(index)/types.ts
deleted file mode 100644
index deb27baf..00000000
--- a/website/src/app/(index)/types.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import type {Html} from '@/types';
-
-export interface Icon {
- displayName: string;
- content: Html;
- meta: {
- fileName: string;
- };
-}
diff --git a/website/src/app/(index)/utils.server.ts b/website/src/app/(index)/utils.server.ts
deleted file mode 100644
index 613630af..00000000
--- a/website/src/app/(index)/utils.server.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import fs from 'fs/promises';
-import {unstable_cache as cache} from 'next/cache';
-import path from 'path';
-import * as svgson from 'svgson';
-import type {Icon} from './types';
-
-export const getIcons = cache(async () => {
- const root = path.resolve(process.cwd(), '../assets/icons');
- const files = await fs.readdir(root, 'utf-8');
-
- const promises = files.map>(async (fileName) => {
- const parsedPath = path.parse(fileName);
- const displayName = dashToPascal(parsedPath.name) + 'Icon';
- const fileContent = await fs.readFile(path.join(root, fileName), 'utf-8');
-
- const parsed = await svgson.parse(fileContent, {
- transformNode(node) {
- if (node.name === 'svg') {
- node.attributes['width'] = '32';
- node.attributes['height'] = '32';
- }
-
- return node;
- },
- });
-
- const content = svgson.stringify(parsed, {
- selfClose: true,
- transformAttr(key, value, escape) {
- if (key === 'stroke') return `${key}="currentColor"`;
- if (key === 'stroke-width') return `${key}="1.5"`;
- return `${key}="${escape(value)}"`;
- },
- });
-
- return {
- displayName,
- content,
- meta: {fileName},
- };
- });
-
- return await Promise.all(promises);
-}, ['items']);
-
-function dashToPascal(value: string) {
- return value
- .split('-')
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
- .join('');
-}
diff --git a/website/src/app/(index)/utils.tsx b/website/src/app/(index)/utils.tsx
deleted file mode 100644
index 13408430..00000000
--- a/website/src/app/(index)/utils.tsx
+++ /dev/null
@@ -1,166 +0,0 @@
-import prettierEsTreePlugin from 'prettier/plugins/estree';
-import prettierHtmlPlugin from 'prettier/plugins/html';
-import prettierTsPlugin from 'prettier/plugins/typescript';
-import prettier from 'prettier/standalone';
-import * as svgson from 'svgson';
-import type {Icon} from './types';
-
-const REF = 'REF';
-const REST = 'REST';
-
-export async function toReactComponent(icon: Icon) {
- const node = await svgson.parse(icon.content, {
- camelcase: true,
- transformNode(node) {
- if (node.name === 'svg') {
- return {
- ...node,
- attributes: {
- [REF]: '',
- ...node.attributes,
- width: '24',
- height: '24',
- viewBox: '0 0 24 24',
- [REST]: '',
- },
- };
- }
-
- return node;
- },
- });
-
- const reactSvg = svgson.stringify(node, {
- selfClose: true,
- transformAttr(key, value, esc) {
- if (key === REF) {
- return 'ref={ref}';
- } else if (key === REST) {
- return '{...props}';
- } else if (key === 'stroke') {
- return `${key}="currentColor"`;
- } else if (key === 'strokeWidth') {
- return `${key}="2"`;
- } else {
- return `${key}="${esc(value)}"`;
- }
- },
- });
-
- const component = `
- import * as React from 'react';
-
- export const ${icon.displayName} = React.forwardRef>((props, ref) => {
- return ${reactSvg};
- });
-
- ${icon.displayName}.displayName = '${icon.displayName}'
-
- export default ${icon.displayName};
- `;
-
- return await prettier.format(component, {
- parser: 'typescript',
- plugins: [prettierTsPlugin, prettierEsTreePlugin],
- printWidth: 80,
- bracketSpacing: false,
- });
-}
-
-export async function toSvelteComponent(icon: Icon) {
- const node = await svgson.parse(icon.content, {
- camelcase: true,
- transformNode(node) {
- if (node.name === 'svg') {
- return {
- ...node,
- attributes: {
- [REF]: '',
- ...node.attributes,
- width: '24',
- height: '24',
- viewBox: '0 0 24 24',
- [REST]: '',
- },
- };
- }
-
- return node;
- },
- });
-
- const svelteSvg = svgson.stringify(node, {
- selfClose: true,
- transformAttr(key, value, esc) {
- if (key === REF) {
- return 'ref={ref}';
- } else if (key === REST) {
- return '{...props}';
- } else if (key === 'stroke') {
- return `${key}="currentColor"`;
- } else if (key === 'strokeWidth') {
- return `${key}="2"`;
- } else {
- return `${key}="${esc(value)}"`;
- }
- },
- });
-
- const component = `
-
-
- ${svelteSvg}
- `;
-
- return await prettier.format(component, {
- parser: 'html',
- plugins: [prettierHtmlPlugin],
- printWidth: 80,
- bracketSpacing: false,
- });
-}
-
-export async function toHtmlComponent(icon: Icon) {
- const node = await svgson.parse(icon.content, {
- camelcase: true,
- transformNode(node) {
- if (node.name === 'svg') {
- return {
- ...node,
- attributes: {
- ...node.attributes,
- width: '24',
- height: '24',
- viewBox: '0 0 24 24',
- },
- };
- }
-
- return node;
- },
- });
-
- const htmlSvg = svgson.stringify(node, {
- selfClose: false,
- transformAttr(key, value, esc) {
- if (key === 'stroke') {
- return `${key}="currentColor"`;
- } else if (key === 'strokeWidth') {
- return `${key}="2"`;
- } else {
- return `${key}="${esc(value)}"`;
- }
- },
- });
-
- return await prettier.format(htmlSvg, {
- parser: 'html',
- plugins: [prettierHtmlPlugin],
- printWidth: 80,
- bracketSpacing: false,
- });
-}
diff --git a/website/src/app/@modal/(.)icons/[slug]/modal.tsx b/website/src/app/@modal/(.)icons/[slug]/modal.tsx
new file mode 100644
index 00000000..c28f8332
--- /dev/null
+++ b/website/src/app/@modal/(.)icons/[slug]/modal.tsx
@@ -0,0 +1,32 @@
+'use client';
+
+import {Dialog} from '@ark-ui/react';
+import {XCloseIcon} from '@untitled-theme/icons-react';
+import {useRouter} from 'next/navigation';
+import {PropsWithChildren} from 'react';
+
+export function Modal({children}: PropsWithChildren) {
+ const router = useRouter();
+
+ return (
+ {
+ if (!open) router.back();
+ }}
+ >
+
+
+
+ {children}
+
+
+
+
+
+
+
+ );
+}
diff --git a/website/src/app/@modal/(.)icons/[slug]/page.tsx b/website/src/app/@modal/(.)icons/[slug]/page.tsx
new file mode 100644
index 00000000..fe91b881
--- /dev/null
+++ b/website/src/app/@modal/(.)icons/[slug]/page.tsx
@@ -0,0 +1,22 @@
+import {IconDetails} from '@/app/icon-details';
+import {getIcon} from '@/app/utils';
+import {notFound} from 'next/navigation';
+import {Modal} from './modal';
+
+interface Props {
+ params: {
+ slug: string;
+ };
+}
+
+export default async function IconDetailsModal({params}: Props) {
+ const icon = await getIcon(params.slug);
+
+ if (!icon) return notFound();
+
+ return (
+
+
+
+ );
+}
diff --git a/website/src/app/@modal/(.)icons/default.tsx b/website/src/app/@modal/(.)icons/default.tsx
new file mode 100644
index 00000000..6ddf1b76
--- /dev/null
+++ b/website/src/app/@modal/(.)icons/default.tsx
@@ -0,0 +1,3 @@
+export default function Default() {
+ return null;
+}
diff --git a/website/src/app/@modal/default.tsx b/website/src/app/@modal/default.tsx
new file mode 100644
index 00000000..6ddf1b76
--- /dev/null
+++ b/website/src/app/@modal/default.tsx
@@ -0,0 +1,3 @@
+export default function Default() {
+ return null;
+}
diff --git a/website/src/app/icon-details.tsx b/website/src/app/icon-details.tsx
new file mode 100644
index 00000000..a978ce85
--- /dev/null
+++ b/website/src/app/icon-details.tsx
@@ -0,0 +1,97 @@
+import {Clipboard, Tabs} from '@ark-ui/react';
+import {CheckIcon, Copy01Icon} from '@untitled-theme/icons-react';
+import type {Icon} from './types';
+
+interface Props {
+ data: Icon;
+}
+
+export async function IconDetails({data}: Props) {
+ const items = [
+ {
+ label: 'Html',
+ value: 'Html',
+ content: data.snippet.html,
+ },
+ {
+ label: 'React',
+ value: 'React',
+ content: data.snippet.react,
+ },
+ {
+ label: 'Svelte',
+ value: 'Svelte',
+ content: data.snippet.svelte,
+ },
+ ];
+
+ return (
+
+
+
+
+ <{data.name} />
+
+
+ Copy
+
+ }
+ >
+
+
+
+
+
+
+
+
+ {items.map((item) => (
+
+ {item.label}
+
+ ))}
+
+
+ {items.map((item) => {
+ return (
+
+
+
+ Copy
+
+
+ }
+ >
+
+
+
+
+
+
+
+
+ );
+ })}
+
+
+ );
+}
diff --git a/website/src/app/icons/[slug]/page.tsx b/website/src/app/icons/[slug]/page.tsx
new file mode 100644
index 00000000..1c3c4838
--- /dev/null
+++ b/website/src/app/icons/[slug]/page.tsx
@@ -0,0 +1,15 @@
+import {IconDetails} from '@/app/icon-details';
+import {getIcon} from '@/app/utils';
+import {notFound} from 'next/navigation';
+
+interface Props {
+ params: {
+ slug: string;
+ };
+}
+
+export default async function IconDetailsPage({params}: Props) {
+ const icon = await getIcon(params.slug);
+
+ return !icon ? notFound() : ;
+}
diff --git a/website/src/app/layout.tsx b/website/src/app/layout.tsx
index 9d41cd5d..0c8cc356 100644
--- a/website/src/app/layout.tsx
+++ b/website/src/app/layout.tsx
@@ -1,6 +1,7 @@
import {GeistMono} from 'geist/font/mono';
import {GeistSans} from 'geist/font/sans';
import type {Metadata} from 'next';
+import type {ReactNode} from 'react';
import {twMerge} from 'tailwind-merge';
import './globals.css';
import {Navbar} from './navbar';
@@ -8,20 +9,20 @@ import {Providers} from './providers';
export const metadata: Metadata = {
title: {
- default: '@untitled-theme/icons-{react|svelte}',
- template: '@untitled-theme/icons-{react|svelte} | %s',
+ default: '@untitled-theme',
+ template: '@untitled-theme | %s',
},
description: 'Untitled UI icons for React and Svelte',
metadataBase: new URL('https://untitled-theme-docs.vercel.app'),
openGraph: {
type: 'website',
- title: '@untitled-theme/icons-{react|svelte}',
+ title: '@untitled-theme',
description: 'Untitled UI icons for React and Svelte',
images: ['/opengraph.png'],
},
};
-export default function RootLayout({children}: Readonly<{children: React.ReactNode}>) {
+export default function RootLayout(props: Readonly<{modal: ReactNode; children: ReactNode}>) {
return (
- {children}
+ {props.children}
+
+ {props.modal}