From bfcab22c173779e4f19f5a6ebe6a18f3c586fa63 Mon Sep 17 00:00:00 2001 From: Tuan Phung <16448321+tuanphungcz@users.noreply.github.com> Date: Mon, 19 Oct 2026 17:57:09 +0200 Subject: [PATCH 1/2] Website: home page UI icons from useAnimations itself The search field's magnifier is searchToX: it turns into an X while the field has text, and the X clears the search (the browser's own clear button is hidden). The interaction select's chevron (chevronDown) and the hero badge's arrow (arrowRight) play while hovered or keyboard-focused. The "Clear search" label is translated into every language. --- website/src/components/HoverIcon.tsx | 59 ++++++++++++++++++++ website/src/components/SearchIcon.tsx | 63 ++++++++++++++++++++++ website/src/i18n/messages/cs/islands.ts | 3 ++ website/src/i18n/messages/de/islands.ts | 3 ++ website/src/i18n/messages/en/islands.ts | 4 ++ website/src/i18n/messages/es/islands.ts | 3 ++ website/src/i18n/messages/fr/islands.ts | 3 ++ website/src/i18n/messages/id/islands.ts | 3 ++ website/src/i18n/messages/ja/islands.ts | 3 ++ website/src/i18n/messages/ko/islands.ts | 3 ++ website/src/i18n/messages/pt-br/islands.ts | 3 ++ website/src/i18n/messages/ru/islands.ts | 3 ++ website/src/i18n/messages/tr/islands.ts | 3 ++ website/src/i18n/messages/vi/islands.ts | 3 ++ website/src/i18n/messages/zh/islands.ts | 3 ++ website/src/styles/global.css | 5 ++ website/src/views/HomePage.astro | 25 +++------ 17 files changed, 173 insertions(+), 19 deletions(-) create mode 100644 website/src/components/HoverIcon.tsx create mode 100644 website/src/components/SearchIcon.tsx diff --git a/website/src/components/HoverIcon.tsx b/website/src/components/HoverIcon.tsx new file mode 100644 index 0000000..e1e068d --- /dev/null +++ b/website/src/components/HoverIcon.tsx @@ -0,0 +1,59 @@ +import { useEffect, useState } from 'react'; +import UseAnimations from 'react-useanimations'; +import arrowRight from '../../../icons/arrowRight.json'; +import chevronDown from '../../../icons/chevronDown.json'; + +const ICONS = { arrowRight, chevronDown }; + +/** + * An icon inside Astro markup that plays while its closest link, button or label is hovered or + * keyboard-focused. The element isn't React's, so the icon is a toggle driven from its events: + * forward on enter, back on leave. + */ +export default function HoverIcon({ + icon, + size = 16, + className, +}: { + icon: keyof typeof ICONS; + size?: number; + className?: string; +}) { + const [span, setSpan] = useState(null); + const [hovered, setHovered] = useState(false); + + useEffect(() => { + const target = span?.closest('a, button, label'); + if (!target) return undefined; + // Touch devices fire pointer events on tap; only a mouse hovers. + const enter = (event: PointerEvent) => event.pointerType === 'mouse' && setHovered(true); + const leave = (event: PointerEvent) => event.pointerType === 'mouse' && setHovered(false); + const focus = (event: FocusEvent) => + (event.target as Element).matches(':focus-visible') && setHovered(true); + const blur = () => setHovered(false); + const events = [ + ['pointerenter', enter], + ['pointerleave', leave], + ['focusin', focus], + ['focusout', blur], + ] as [string, EventListener][]; + for (const [type, listener] of events) target.addEventListener(type, listener); + return () => { + for (const [type, listener] of events) target.removeEventListener(type, listener); + }; + }, [span]); + + return ( + ( + + + + )} + /> + ); +} diff --git a/website/src/components/SearchIcon.tsx b/website/src/components/SearchIcon.tsx new file mode 100644 index 0000000..7823fe3 --- /dev/null +++ b/website/src/components/SearchIcon.tsx @@ -0,0 +1,63 @@ +import { useEffect, useState } from 'react'; +import UseAnimations from 'react-useanimations'; +import searchToX from '../../../icons/searchToX.json'; +import { islands } from '../i18n/messages/en/islands'; + +const fieldOf = (button: HTMLButtonElement | null) => + button?.closest('label')?.querySelector('[data-search]'); + +/** + * The icon of the browser's search field (the input with `data-search` in the same label): a + * magnifier that turns into a clear button while the field has text. + */ +export default function SearchIcon({ + strings = islands.search, +}: { + /** The button's text in the page's language: t(locale).islands.search. */ + strings?: typeof islands.search; +}) { + const [button, setButton] = useState(null); + const [filled, setFilled] = useState(false); + + useEffect(() => { + const input = fieldOf(button); + if (!input) return undefined; + // scripts/browser.ts may have filled the field from ?q= before this island hydrated. + const sync = () => setFilled(input.value !== ''); + sync(); + input.addEventListener('input', sync); + return () => input.removeEventListener('input', sync); + }, [button]); + + // The browser script filters on the field's input event, so clearing goes through it too. + const clear = () => { + const input = fieldOf(button); + if (!input) return; + input.value = ''; + input.dispatchEvent(new Event('input', { bubbles: true })); + input.focus(); + }; + + return ( + ( + + )} + /> + ); +} diff --git a/website/src/i18n/messages/cs/islands.ts b/website/src/i18n/messages/cs/islands.ts index c152301..5ffd907 100644 --- a/website/src/i18n/messages/cs/islands.ts +++ b/website/src/i18n/messages/cs/islands.ts @@ -44,6 +44,9 @@ export const islands: Messages['islands'] = { menu: 'Menu', nav: 'Hlavní navigace', }, + search: { + clear: 'Vymazat hledání', + }, themeToggle: { toLight: 'Přepnout na světlý motiv', toDark: 'Přepnout na tmavý motiv', diff --git a/website/src/i18n/messages/de/islands.ts b/website/src/i18n/messages/de/islands.ts index da6f564..d8361f3 100644 --- a/website/src/i18n/messages/de/islands.ts +++ b/website/src/i18n/messages/de/islands.ts @@ -44,6 +44,9 @@ export const islands: Messages['islands'] = { menu: 'Menü', nav: 'Hauptnavigation', }, + search: { + clear: 'Suche löschen', + }, themeToggle: { toLight: 'Zum hellen Design wechseln', toDark: 'Zum dunklen Design wechseln', diff --git a/website/src/i18n/messages/en/islands.ts b/website/src/i18n/messages/en/islands.ts index 405a2c4..2421e02 100644 --- a/website/src/i18n/messages/en/islands.ts +++ b/website/src/i18n/messages/en/islands.ts @@ -55,6 +55,10 @@ export const islands = { menu: 'Menu', nav: 'Main', }, + /** The search field of the icon browser: its X clears the search. */ + search: { + clear: 'Clear search', + }, themeToggle: { toLight: 'Switch to light theme', toDark: 'Switch to dark theme', diff --git a/website/src/i18n/messages/es/islands.ts b/website/src/i18n/messages/es/islands.ts index 8e5f08c..855963c 100644 --- a/website/src/i18n/messages/es/islands.ts +++ b/website/src/i18n/messages/es/islands.ts @@ -45,6 +45,9 @@ export const islands: Messages['islands'] = { menu: 'Menú', nav: 'Principal', }, + search: { + clear: 'Borrar la búsqueda', + }, themeToggle: { toLight: 'Cambiar al tema claro', toDark: 'Cambiar al tema oscuro', diff --git a/website/src/i18n/messages/fr/islands.ts b/website/src/i18n/messages/fr/islands.ts index 13aeee9..06b9f53 100644 --- a/website/src/i18n/messages/fr/islands.ts +++ b/website/src/i18n/messages/fr/islands.ts @@ -44,6 +44,9 @@ export const islands: Messages['islands'] = { menu: 'Menu', nav: 'Navigation principale', }, + search: { + clear: 'Effacer la recherche', + }, themeToggle: { toLight: 'Passer au thème clair', toDark: 'Passer au thème sombre', diff --git a/website/src/i18n/messages/id/islands.ts b/website/src/i18n/messages/id/islands.ts index b31a45a..984aea5 100644 --- a/website/src/i18n/messages/id/islands.ts +++ b/website/src/i18n/messages/id/islands.ts @@ -44,6 +44,9 @@ export const islands: Messages['islands'] = { menu: 'Menu', nav: 'Utama', }, + search: { + clear: 'Hapus pencarian', + }, themeToggle: { toLight: 'Beralih ke tema terang', toDark: 'Beralih ke tema gelap', diff --git a/website/src/i18n/messages/ja/islands.ts b/website/src/i18n/messages/ja/islands.ts index 542bab2..1a4a414 100644 --- a/website/src/i18n/messages/ja/islands.ts +++ b/website/src/i18n/messages/ja/islands.ts @@ -44,6 +44,9 @@ export const islands: Messages['islands'] = { menu: 'メニュー', nav: 'メイン', }, + search: { + clear: '検索をクリア', + }, themeToggle: { toLight: 'ライトテーマに切り替える', toDark: 'ダークテーマに切り替える', diff --git a/website/src/i18n/messages/ko/islands.ts b/website/src/i18n/messages/ko/islands.ts index 39f1627..98c7e46 100644 --- a/website/src/i18n/messages/ko/islands.ts +++ b/website/src/i18n/messages/ko/islands.ts @@ -45,6 +45,9 @@ export const islands: Messages['islands'] = { menu: '메뉴', nav: '주 메뉴', }, + search: { + clear: '검색어 지우기', + }, themeToggle: { toLight: '라이트 테마로 전환', toDark: '다크 테마로 전환', diff --git a/website/src/i18n/messages/pt-br/islands.ts b/website/src/i18n/messages/pt-br/islands.ts index bcd4dcd..54f64a6 100644 --- a/website/src/i18n/messages/pt-br/islands.ts +++ b/website/src/i18n/messages/pt-br/islands.ts @@ -44,6 +44,9 @@ export const islands: Messages['islands'] = { menu: 'Menu', nav: 'Principal', }, + search: { + clear: 'Limpar a pesquisa', + }, themeToggle: { toLight: 'Mudar para o tema claro', toDark: 'Mudar para o tema escuro', diff --git a/website/src/i18n/messages/ru/islands.ts b/website/src/i18n/messages/ru/islands.ts index 3d007a5..0faa44d 100644 --- a/website/src/i18n/messages/ru/islands.ts +++ b/website/src/i18n/messages/ru/islands.ts @@ -44,6 +44,9 @@ export const islands: Messages['islands'] = { menu: 'Меню', nav: 'Основная навигация', }, + search: { + clear: 'Очистить поиск', + }, themeToggle: { toLight: 'Включить светлую тему', toDark: 'Включить тёмную тему', diff --git a/website/src/i18n/messages/tr/islands.ts b/website/src/i18n/messages/tr/islands.ts index ce12a97..b30e005 100644 --- a/website/src/i18n/messages/tr/islands.ts +++ b/website/src/i18n/messages/tr/islands.ts @@ -44,6 +44,9 @@ export const islands: Messages['islands'] = { menu: 'Menü', nav: 'Ana menü', }, + search: { + clear: 'Aramayı temizle', + }, themeToggle: { toLight: 'Açık temaya geç', toDark: 'Koyu temaya geç', diff --git a/website/src/i18n/messages/vi/islands.ts b/website/src/i18n/messages/vi/islands.ts index 2a3e170..563bfe8 100644 --- a/website/src/i18n/messages/vi/islands.ts +++ b/website/src/i18n/messages/vi/islands.ts @@ -45,6 +45,9 @@ export const islands: Messages['islands'] = { menu: 'Menu', nav: 'Điều hướng chính', }, + search: { + clear: 'Xóa tìm kiếm', + }, themeToggle: { toLight: 'Chuyển sang giao diện sáng', toDark: 'Chuyển sang giao diện tối', diff --git a/website/src/i18n/messages/zh/islands.ts b/website/src/i18n/messages/zh/islands.ts index ac3ea97..79751cd 100644 --- a/website/src/i18n/messages/zh/islands.ts +++ b/website/src/i18n/messages/zh/islands.ts @@ -45,6 +45,9 @@ export const islands: Messages['islands'] = { menu: '菜单', nav: '主导航', }, + search: { + clear: '清除搜索', + }, themeToggle: { toLight: '切换到浅色主题', toDark: '切换到深色主题', diff --git a/website/src/styles/global.css b/website/src/styles/global.css index 485cd22..73fa9dc 100644 --- a/website/src/styles/global.css +++ b/website/src/styles/global.css @@ -351,6 +351,11 @@ } } +/* The search field clears with its own animated X (components/SearchIcon.tsx), not the browser's. */ +[data-search]::-webkit-search-cancel-button { + appearance: none; +} + /* ICON BROWSER: one card per icon (components/IconCard.tsx). Plain classes instead of utility lists, which repeated 300 times on the home page. */ .icon-card { diff --git a/website/src/views/HomePage.astro b/website/src/views/HomePage.astro index 2eecaf6..2f27fcc 100644 --- a/website/src/views/HomePage.astro +++ b/website/src/views/HomePage.astro @@ -3,11 +3,13 @@ import type { Interaction } from 'react-useanimations'; import CodeBlock from '../components/CodeBlock.astro'; import ColorRow from '../components/ColorRow'; +import HoverIcon from '../components/HoverIcon'; import IconCard from '../components/IconCard'; import IconDialog, { type DialogIcon, type Templates } from '../components/IconDialog'; import IconField from '../components/IconField.astro'; import InstallCommand from '../components/InstallCommand.astro'; import InteractionDemo from '../components/InteractionDemo'; +import SearchIcon from '../components/SearchIcon'; import { alternatesOf, EN, type Locale, localize, t } from '../i18n'; import Layout from '../layouts/Layout.astro'; import { highlight } from '../lib/highlight'; @@ -244,11 +246,11 @@ const jsonLd = {
v3 {h.hero.badge(icons.length)} - → +

{h.hero.headline.start}{h.hero.headline.accent}{h.hero.headline.end} @@ -340,15 +342,7 @@ const jsonLd = {

{ From fb810ffde5945b03fcb94bb48f55dbca3b50196d Mon Sep 17 00:00:00 2001 From: Tuan Phung <16448321+tuanphungcz@users.noreply.github.com> Date: Mon, 19 Oct 2026 18:00:52 +0200 Subject: [PATCH 2/2] Website: more useAnimations icons on the home page ControlIcon (was HoverIcon) also follows a
' open state and hovers of any [data-icon-trigger] element. New icons: copy on the install command and the code blocks' copy buttons, plusToX on the FAQ questions (X while open), droplet, package, users, server and cpu on the feature cards, arrowRight on the documentation and Get started buttons (the text arrow is gone from their labels in every language). --- website/src/components/CodeBlock.astro | 5 +- website/src/components/ControlIcon.tsx | 88 +++++++++++++++++++++ website/src/components/HoverIcon.tsx | 59 -------------- website/src/components/InstallCommand.astro | 10 +-- website/src/i18n/messages/cs/home.ts | 2 +- website/src/i18n/messages/de/home.ts | 2 +- website/src/i18n/messages/en/home.ts | 2 +- website/src/i18n/messages/es/home.ts | 2 +- website/src/i18n/messages/fr/home.ts | 2 +- website/src/i18n/messages/id/home.ts | 2 +- website/src/i18n/messages/ja/home.ts | 2 +- website/src/i18n/messages/ko/home.ts | 2 +- website/src/i18n/messages/pt-br/home.ts | 2 +- website/src/i18n/messages/ru/home.ts | 2 +- website/src/i18n/messages/tr/home.ts | 2 +- website/src/i18n/messages/vi/home.ts | 2 +- website/src/i18n/messages/zh/home.ts | 2 +- website/src/views/HomePage.astro | 46 +++++++---- 18 files changed, 138 insertions(+), 96 deletions(-) create mode 100644 website/src/components/ControlIcon.tsx delete mode 100644 website/src/components/HoverIcon.tsx diff --git a/website/src/components/CodeBlock.astro b/website/src/components/CodeBlock.astro index e6c1f7c..304d9c6 100644 --- a/website/src/components/CodeBlock.astro +++ b/website/src/components/CodeBlock.astro @@ -1,6 +1,7 @@ --- import { EN, type Locale, t } from '../i18n'; import { highlight } from '../lib/highlight'; +import ControlIcon from './ControlIcon'; interface Props { code: string; @@ -25,7 +26,7 @@ const html = await highlight(code, lang); data-copy-from="[data-code]" data-track="copy" {...trackData} - class="absolute top-2 right-2 rounded-lg border border-line bg-surface px-2 py-1 text-xs text-muted opacity-0 transition group-hover/code:opacity-100 focus:opacity-100 data-[copied]:text-accent" - >{t(locale).common.copy}{t(locale).common.copy}
diff --git a/website/src/components/ControlIcon.tsx b/website/src/components/ControlIcon.tsx new file mode 100644 index 0000000..6c2f526 --- /dev/null +++ b/website/src/components/ControlIcon.tsx @@ -0,0 +1,88 @@ +import { useEffect, useState } from 'react'; +import UseAnimations from 'react-useanimations'; +import arrowRight from '../../../icons/arrowRight.json'; +import chevronDown from '../../../icons/chevronDown.json'; +import copy from '../../../icons/copy.json'; +import cpu from '../../../icons/cpu.json'; +import droplet from '../../../icons/droplet.json'; +import packageIcon from '../../../icons/package.json'; +import plusToX from '../../../icons/plusToX.json'; +import server from '../../../icons/server.json'; +import users from '../../../icons/users.json'; + +const ICONS = { + arrowRight, + chevronDown, + copy, + cpu, + droplet, + package: packageIcon, + plusToX, + server, + users, +}; + +/** + * An icon inside Astro markup, played by the element around it, which isn't React's. So the icon + * is a toggle driven from that element's events: + * - `hover`: forward while its closest link, button, label or `[data-icon-trigger]` is hovered or + * keyboard-focused, back on leave; + * - `open`: at its end state while its closest `
` is open (e.g. plus to X). + */ +export default function ControlIcon({ + icon, + on = 'hover', + size = 16, + className, +}: { + icon: keyof typeof ICONS; + on?: 'hover' | 'open'; + size?: number; + className?: string; +}) { + const [span, setSpan] = useState(null); + const [active, setActive] = useState(false); + + useEffect(() => { + if (on === 'open') { + const details = span?.closest('details'); + if (!details) return undefined; + const sync = () => setActive(details.open); + sync(); + details.addEventListener('toggle', sync); + return () => details.removeEventListener('toggle', sync); + } + const target = span?.closest('a, button, label, [data-icon-trigger]'); + if (!target) return undefined; + // Touch devices fire pointer events on tap; only a mouse hovers. + const enter = (event: PointerEvent) => event.pointerType === 'mouse' && setActive(true); + const leave = (event: PointerEvent) => event.pointerType === 'mouse' && setActive(false); + const focus = (event: FocusEvent) => + (event.target as Element).matches(':focus-visible') && setActive(true); + const blur = () => setActive(false); + const events = [ + ['pointerenter', enter], + ['pointerleave', leave], + ['focusin', focus], + ['focusout', blur], + ] as [string, EventListener][]; + for (const [type, listener] of events) target.addEventListener(type, listener); + return () => { + for (const [type, listener] of events) target.removeEventListener(type, listener); + }; + }, [span, on]); + + return ( + ( + + + + )} + /> + ); +} diff --git a/website/src/components/HoverIcon.tsx b/website/src/components/HoverIcon.tsx deleted file mode 100644 index e1e068d..0000000 --- a/website/src/components/HoverIcon.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { useEffect, useState } from 'react'; -import UseAnimations from 'react-useanimations'; -import arrowRight from '../../../icons/arrowRight.json'; -import chevronDown from '../../../icons/chevronDown.json'; - -const ICONS = { arrowRight, chevronDown }; - -/** - * An icon inside Astro markup that plays while its closest link, button or label is hovered or - * keyboard-focused. The element isn't React's, so the icon is a toggle driven from its events: - * forward on enter, back on leave. - */ -export default function HoverIcon({ - icon, - size = 16, - className, -}: { - icon: keyof typeof ICONS; - size?: number; - className?: string; -}) { - const [span, setSpan] = useState(null); - const [hovered, setHovered] = useState(false); - - useEffect(() => { - const target = span?.closest('a, button, label'); - if (!target) return undefined; - // Touch devices fire pointer events on tap; only a mouse hovers. - const enter = (event: PointerEvent) => event.pointerType === 'mouse' && setHovered(true); - const leave = (event: PointerEvent) => event.pointerType === 'mouse' && setHovered(false); - const focus = (event: FocusEvent) => - (event.target as Element).matches(':focus-visible') && setHovered(true); - const blur = () => setHovered(false); - const events = [ - ['pointerenter', enter], - ['pointerleave', leave], - ['focusin', focus], - ['focusout', blur], - ] as [string, EventListener][]; - for (const [type, listener] of events) target.addEventListener(type, listener); - return () => { - for (const [type, listener] of events) target.removeEventListener(type, listener); - }; - }, [span]); - - return ( - ( - - - - )} - /> - ); -} diff --git a/website/src/components/InstallCommand.astro b/website/src/components/InstallCommand.astro index 6fc36fb..dbb9cbe 100644 --- a/website/src/components/InstallCommand.astro +++ b/website/src/components/InstallCommand.astro @@ -1,5 +1,6 @@ --- import { EN, type Locale, t } from '../i18n'; +import ControlIcon from './ControlIcon'; interface Props { command?: string; @@ -23,9 +24,8 @@ const { command = 'npm i react-useanimations', class: className, locale = EN } = {command} - {t(locale).common.copy} + + + {t(locale).common.copy} + diff --git a/website/src/i18n/messages/cs/home.ts b/website/src/i18n/messages/cs/home.ts index 9447a11..35842b3 100644 --- a/website/src/i18n/messages/cs/home.ts +++ b/website/src/i18n/messages/cs/home.ts @@ -91,7 +91,7 @@ export const home: Messages['home'] = { title: 'Nainstalovat, importovat, hotovo.', intro: 'React komponenta bez závislostí, registr shadcn, soubory ke stažení se stálými URL a katalog, který přečtou i AI agenti.', - docs: 'Přečíst dokumentaci →', + docs: 'Přečíst dokumentaci', tablist: 'Platforma', tabs: { react: 'React', shadcn: 'shadcn', files: 'Soubory', agents: 'Agenti' }, codeText: { diff --git a/website/src/i18n/messages/de/home.ts b/website/src/i18n/messages/de/home.ts index 4040078..d914239 100644 --- a/website/src/i18n/messages/de/home.ts +++ b/website/src/i18n/messages/de/home.ts @@ -77,7 +77,7 @@ export const home: Messages['home'] = { title: 'Installieren, importieren, fertig.', intro: 'Eine React-Komponente ohne Abhängigkeiten, eine shadcn-Registry, Dateien zum Herunterladen unter stabilen URLs und ein Katalog, den KI-Agenten lesen können.', - docs: 'Zur Dokumentation →', + docs: 'Zur Dokumentation', tablist: 'Plattform', tabs: { react: 'React', shadcn: 'shadcn', files: 'Dateien', agents: 'Agenten' }, codeText: { diff --git a/website/src/i18n/messages/en/home.ts b/website/src/i18n/messages/en/home.ts index f38c867..42b394e 100644 --- a/website/src/i18n/messages/en/home.ts +++ b/website/src/i18n/messages/en/home.ts @@ -121,7 +121,7 @@ export const home = { title: 'Install, import, done.', intro: 'A React component with no dependencies, a shadcn registry, downloadable files with stable URLs, and a catalog that AI agents can read.', - docs: 'Read the documentation →', + docs: 'Read the documentation', /** Accessible name of the tab list (screen readers only). */ tablist: 'Platform', /** Tab names; React and shadcn are names and stay as they are. */ diff --git a/website/src/i18n/messages/es/home.ts b/website/src/i18n/messages/es/home.ts index 8dfbada..4204f74 100644 --- a/website/src/i18n/messages/es/home.ts +++ b/website/src/i18n/messages/es/home.ts @@ -78,7 +78,7 @@ export const home: Messages['home'] = { title: 'Instala, importa y listo.', intro: 'Un componente de React sin dependencias, un registro de shadcn, archivos descargables con URL estables y un catálogo que pueden leer los agentes de IA.', - docs: 'Leer la documentación →', + docs: 'Leer la documentación', tablist: 'Plataforma', tabs: { react: 'React', shadcn: 'shadcn', files: 'Archivos', agents: 'Agentes' }, codeText: { diff --git a/website/src/i18n/messages/fr/home.ts b/website/src/i18n/messages/fr/home.ts index df72cf1..2bb25ca 100644 --- a/website/src/i18n/messages/fr/home.ts +++ b/website/src/i18n/messages/fr/home.ts @@ -77,7 +77,7 @@ export const home: Messages['home'] = { title: 'Installer, importer, c’est tout.', intro: 'Un composant React sans dépendance, un registre shadcn, des fichiers téléchargeables aux URL stables et un catalogue lisible par les agents IA.', - docs: 'Lire la documentation →', + docs: 'Lire la documentation', tablist: 'Plateforme', tabs: { react: 'React', shadcn: 'shadcn', files: 'Fichiers', agents: 'Agents' }, codeText: { diff --git a/website/src/i18n/messages/id/home.ts b/website/src/i18n/messages/id/home.ts index 019a3b7..49d63c6 100644 --- a/website/src/i18n/messages/id/home.ts +++ b/website/src/i18n/messages/id/home.ts @@ -77,7 +77,7 @@ export const home: Messages['home'] = { title: 'Instal, import, selesai.', intro: 'Komponen React tanpa dependensi, registry shadcn, file yang bisa diunduh dengan URL tetap, dan katalog yang bisa dibaca agen AI.', - docs: 'Baca dokumentasi →', + docs: 'Baca dokumentasi', tablist: 'Platform', tabs: { react: 'React', shadcn: 'shadcn', files: 'File', agents: 'Agen AI' }, codeText: { diff --git a/website/src/i18n/messages/ja/home.ts b/website/src/i18n/messages/ja/home.ts index f51f093..e79b3ee 100644 --- a/website/src/i18n/messages/ja/home.ts +++ b/website/src/i18n/messages/ja/home.ts @@ -77,7 +77,7 @@ export const home: Messages['home'] = { title: 'インストールして、インポートするだけ。', intro: '依存関係のない React コンポーネント、shadcn レジストリ、URL が固定されたダウンロード用ファイル、そして AI エージェントが読めるカタログを用意しています。', - docs: 'ドキュメントを読む →', + docs: 'ドキュメントを読む', tablist: 'プラットフォーム', tabs: { react: 'React', shadcn: 'shadcn', files: 'ファイル', agents: 'エージェント' }, codeText: { diff --git a/website/src/i18n/messages/ko/home.ts b/website/src/i18n/messages/ko/home.ts index 6617a79..1d70cce 100644 --- a/website/src/i18n/messages/ko/home.ts +++ b/website/src/i18n/messages/ko/home.ts @@ -81,7 +81,7 @@ export const home: Messages['home'] = { title: '설치하고, 가져오면 끝.', intro: '의존성 없는 React 컴포넌트, shadcn 레지스트리, 고정 URL로 내려받는 파일, 그리고 AI 에이전트가 읽을 수 있는 카탈로그를 제공합니다.', - docs: '문서 읽기 →', + docs: '문서 읽기', tablist: '플랫폼', tabs: { react: 'React', shadcn: 'shadcn', files: '파일', agents: '에이전트' }, codeText: { diff --git a/website/src/i18n/messages/pt-br/home.ts b/website/src/i18n/messages/pt-br/home.ts index 0c5dced..7e12052 100644 --- a/website/src/i18n/messages/pt-br/home.ts +++ b/website/src/i18n/messages/pt-br/home.ts @@ -76,7 +76,7 @@ export const home: Messages['home'] = { title: 'Instale, importe, pronto.', intro: 'Um componente React sem dependências, um registry do shadcn, arquivos para download com URLs estáveis e um catálogo que agentes de IA conseguem ler.', - docs: 'Leia a documentação →', + docs: 'Leia a documentação', tablist: 'Plataforma', tabs: { react: 'React', shadcn: 'shadcn', files: 'Arquivos', agents: 'Agentes' }, codeText: { diff --git a/website/src/i18n/messages/ru/home.ts b/website/src/i18n/messages/ru/home.ts index 02f10d0..adbc6e8 100644 --- a/website/src/i18n/messages/ru/home.ts +++ b/website/src/i18n/messages/ru/home.ts @@ -81,7 +81,7 @@ export const home: Messages['home'] = { title: 'Установили, импортировали, готово.', intro: 'React-компонент без зависимостей, shadcn-реестр, файлы для скачивания по постоянным URL и каталог, который умеют читать ИИ-агенты.', - docs: 'Читать документацию →', + docs: 'Читать документацию', tablist: 'Платформа', tabs: { react: 'React', shadcn: 'shadcn', files: 'Файлы', agents: 'Агенты' }, codeText: { diff --git a/website/src/i18n/messages/tr/home.ts b/website/src/i18n/messages/tr/home.ts index 2408201..f74bb8e 100644 --- a/website/src/i18n/messages/tr/home.ts +++ b/website/src/i18n/messages/tr/home.ts @@ -77,7 +77,7 @@ export const home: Messages['home'] = { title: 'Kur, import et, bitti.', intro: 'Bağımlılığı olmayan bir React bileşeni, bir shadcn registry, kalıcı URL’lerden indirilebilen dosyalar ve yapay zekâ ajanlarının okuyabildiği bir katalog.', - docs: 'Dokümantasyonu okuyun →', + docs: 'Dokümantasyonu okuyun', tablist: 'Platform', tabs: { react: 'React', shadcn: 'shadcn', files: 'Dosyalar', agents: 'Ajanlar' }, codeText: { diff --git a/website/src/i18n/messages/vi/home.ts b/website/src/i18n/messages/vi/home.ts index 4fffcb7..98a66c4 100644 --- a/website/src/i18n/messages/vi/home.ts +++ b/website/src/i18n/messages/vi/home.ts @@ -77,7 +77,7 @@ export const home: Messages['home'] = { title: 'Cài, import, xong.', intro: 'Một React component không có dependency, một shadcn registry, các tệp tải về với URL cố định, và một catalog mà AI agent đọc được.', - docs: 'Đọc tài liệu →', + docs: 'Đọc tài liệu', tablist: 'Nền tảng', tabs: { react: 'React', shadcn: 'shadcn', files: 'Tệp', agents: 'Agent' }, codeText: { diff --git a/website/src/i18n/messages/zh/home.ts b/website/src/i18n/messages/zh/home.ts index 242dfa8..30b037a 100644 --- a/website/src/i18n/messages/zh/home.ts +++ b/website/src/i18n/messages/zh/home.ts @@ -75,7 +75,7 @@ export const home: Messages['home'] = { title: '安装、导入,就这么简单。', intro: '零依赖的 React 组件、shadcn 注册表、带固定网址的可下载文件,以及 AI 智能体可以读取的图标目录。', - docs: '阅读文档 →', + docs: '阅读文档', tablist: '平台', tabs: { react: 'React', shadcn: 'shadcn', files: '文件', agents: '智能体' }, codeText: { diff --git a/website/src/views/HomePage.astro b/website/src/views/HomePage.astro index 2f27fcc..ab775d4 100644 --- a/website/src/views/HomePage.astro +++ b/website/src/views/HomePage.astro @@ -3,7 +3,7 @@ import type { Interaction } from 'react-useanimations'; import CodeBlock from '../components/CodeBlock.astro'; import ColorRow from '../components/ColorRow'; -import HoverIcon from '../components/HoverIcon'; +import ControlIcon from '../components/ControlIcon'; import IconCard from '../components/IconCard'; import IconDialog, { type DialogIcon, type Templates } from '../components/IconDialog'; import IconField from '../components/IconField.astro'; @@ -250,7 +250,7 @@ const jsonLd = { > v3 {h.hero.badge(icons.length)} - +

{h.hero.headline.start}{h.hero.headline.accent}{h.hero.headline.end} @@ -364,7 +364,7 @@ const jsonLd = { {(Object.keys(INTERACTIONS) as Interaction[]).map((value) => )} - +

{ @@ -477,7 +477,7 @@ const jsonLd = { {e.docs}{e.docs}
@@ -522,8 +522,10 @@ const jsonLd = { {f.title}
-
-

{f.colors}

+
+

+ {f.colors} +

-
-

{f.tiny}

+
+

+ {f.tiny} +

8 kB

{f.tinyText}

-
-

{f.accessible}

+
+

+ {f.accessible} +

{f.accessibleText}

-
-

{f.ssr}

+
+

+ {f.ssr} +

{f.ssrText}

-
-

{f.agents}

+
+

+ {f.agents} +

@@ -621,7 +631,7 @@ const jsonLd = {

{item.question}

- +

{item.answer} @@ -650,8 +660,10 @@ const jsonLd = {

{h.cta.text}

- {h.cta.start}{h.cta.start}