mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
feat(web): add EntryHelpMenu and GithubStarBadge components for enhanced user support
- Introduced `EntryHelpMenu` to provide quick access to help resources, including links for GitHub issues, feature requests, and downloads, enhancing user support. - Added `GithubStarBadge` to display the current star count for the GitHub repository, encouraging user engagement and visibility. - Updated `EntryNavRail` to include the new help menu, improving navigation and accessibility of support options. - Enhanced internationalization support by adding relevant translations for new components and menu items. - Created a new CSS file for the "Use Everywhere" modal, which documents non-UI surfaces and provides a guide for users. This update significantly improves user experience by integrating support resources directly into the application interface.
This commit is contained in:
parent
45760a75aa
commit
1daa60b283
26 changed files with 923 additions and 17 deletions
120
apps/web/src/components/EntryHelpMenu.tsx
Normal file
120
apps/web/src/components/EntryHelpMenu.tsx
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
// Help launcher anchored to the bottom of the entry nav rail.
|
||||
//
|
||||
// Mirrors the Lovart-style "?" affordance shown in the bottom-left
|
||||
// corner of the workspace: a single round button that opens a small
|
||||
// popover with the four external help links we want every user to be
|
||||
// one click away from — GitHub issues for help, GitHub PRs for feature
|
||||
// requests, releases for the changelog, and the desktop download.
|
||||
//
|
||||
// The links open in a new tab (with safe `noopener` rel) and are
|
||||
// labeled via the i18n dictionary so locale switching keeps the menu
|
||||
// in the user's language.
|
||||
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Icon } from './Icon';
|
||||
import { useT } from '../i18n';
|
||||
|
||||
const REPO = 'https://github.com/nexu-io/open-design';
|
||||
const ISSUES_URL = `${REPO}/issues/new`;
|
||||
const PRS_URL = `${REPO}/pulls`;
|
||||
const RELEASES_URL = `${REPO}/releases`;
|
||||
const LATEST_RELEASE_URL = `${REPO}/releases/latest`;
|
||||
|
||||
const ext = { target: '_blank', rel: 'noreferrer noopener' } as const;
|
||||
|
||||
export function EntryHelpMenu() {
|
||||
const t = useT();
|
||||
const [open, setOpen] = useState(false);
|
||||
const wrapRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
function onDocClick(e: MouseEvent) {
|
||||
if (!wrapRef.current) return;
|
||||
if (!wrapRef.current.contains(e.target as Node)) setOpen(false);
|
||||
}
|
||||
function onKey(e: KeyboardEvent) {
|
||||
if (e.key === 'Escape') setOpen(false);
|
||||
}
|
||||
document.addEventListener('mousedown', onDocClick);
|
||||
document.addEventListener('keydown', onKey);
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', onDocClick);
|
||||
document.removeEventListener('keydown', onKey);
|
||||
};
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<div className="entry-help-menu" ref={wrapRef}>
|
||||
<button
|
||||
type="button"
|
||||
className="entry-nav-rail__btn entry-help-menu__trigger"
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
aria-haspopup="menu"
|
||||
aria-expanded={open}
|
||||
aria-label={t('entry.helpAria')}
|
||||
data-tooltip={t('entry.helpAria')}
|
||||
data-testid="entry-help-trigger"
|
||||
>
|
||||
<Icon name="help-circle" size={18} />
|
||||
</button>
|
||||
{open ? (
|
||||
<div
|
||||
className="entry-help-popover"
|
||||
role="menu"
|
||||
aria-label={t('entry.helpMenuAria')}
|
||||
>
|
||||
<a
|
||||
className="entry-help-popover__item"
|
||||
href={ISSUES_URL}
|
||||
{...ext}
|
||||
role="menuitem"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<span className="entry-help-popover__icon" aria-hidden>
|
||||
<Icon name="comment" size={14} />
|
||||
</span>
|
||||
<span>{t('entry.helpGetHelp')}</span>
|
||||
</a>
|
||||
<a
|
||||
className="entry-help-popover__item"
|
||||
href={PRS_URL}
|
||||
{...ext}
|
||||
role="menuitem"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<span className="entry-help-popover__icon" aria-hidden>
|
||||
<Icon name="sparkles" size={14} />
|
||||
</span>
|
||||
<span>{t('entry.helpSubmitFeature')}</span>
|
||||
</a>
|
||||
<a
|
||||
className="entry-help-popover__item"
|
||||
href={LATEST_RELEASE_URL}
|
||||
{...ext}
|
||||
role="menuitem"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<span className="entry-help-popover__icon" aria-hidden>
|
||||
<Icon name="bell" size={14} />
|
||||
</span>
|
||||
<span>{t('entry.helpWhatsNew')}</span>
|
||||
</a>
|
||||
<div className="entry-help-popover__divider" aria-hidden />
|
||||
<a
|
||||
className="entry-help-popover__item"
|
||||
href={RELEASES_URL}
|
||||
{...ext}
|
||||
role="menuitem"
|
||||
onClick={() => setOpen(false)}
|
||||
>
|
||||
<span className="entry-help-popover__icon" aria-hidden>
|
||||
<Icon name="download" size={14} />
|
||||
</span>
|
||||
<span>{t('entry.helpDownloadDesktop')}</span>
|
||||
</a>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -2,12 +2,15 @@
|
|||
//
|
||||
// Renders a narrow icon-only column. The first slot is the brand
|
||||
// logo (clicking navigates to home), followed by four primary
|
||||
// actions (new project, home, projects, design systems). The
|
||||
// rail no longer carries any footer chrome — language switching
|
||||
// and other account-scoped controls live behind the floating
|
||||
// settings cog in the top-right corner of the main content.
|
||||
// actions (new project, home, projects, design systems). A small
|
||||
// help launcher sits at the bottom and opens a popover with the
|
||||
// canonical "ask for help / submit a feature / what's new / download
|
||||
// desktop" external links. Language switching and other account-
|
||||
// scoped controls live behind the floating settings cog in the
|
||||
// top-right corner of the main content.
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
import { EntryHelpMenu } from './EntryHelpMenu';
|
||||
import { Icon } from './Icon';
|
||||
import { useT } from '../i18n';
|
||||
|
||||
|
|
@ -22,13 +25,13 @@ interface Props {
|
|||
interface NavButtonProps {
|
||||
active?: boolean;
|
||||
ariaLabel: string;
|
||||
title: string;
|
||||
tooltip: string;
|
||||
onClick: () => void;
|
||||
testId?: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
function NavButton({ active, ariaLabel, title, onClick, testId, children }: NavButtonProps) {
|
||||
function NavButton({ active, ariaLabel, tooltip, onClick, testId, children }: NavButtonProps) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -36,7 +39,7 @@ function NavButton({ active, ariaLabel, title, onClick, testId, children }: NavB
|
|||
onClick={onClick}
|
||||
aria-label={ariaLabel}
|
||||
aria-current={active ? 'page' : undefined}
|
||||
title={title}
|
||||
data-tooltip={tooltip}
|
||||
{...(testId ? { 'data-testid': testId } : {})}
|
||||
>
|
||||
{children}
|
||||
|
|
@ -56,7 +59,7 @@ export function EntryNavRail({ view, onViewChange, onNewProject }: Props) {
|
|||
className="entry-nav-rail__logo"
|
||||
onClick={() => onViewChange('home')}
|
||||
aria-label={brandLabel}
|
||||
title={brandLabel}
|
||||
data-tooltip={brandLabel}
|
||||
data-testid="entry-nav-logo"
|
||||
>
|
||||
<img
|
||||
|
|
@ -67,8 +70,8 @@ export function EntryNavRail({ view, onViewChange, onNewProject }: Props) {
|
|||
/>
|
||||
</button>
|
||||
<NavButton
|
||||
ariaLabel="New project"
|
||||
title="New project"
|
||||
ariaLabel={t('entry.navNewProject')}
|
||||
tooltip={t('entry.navNewProject')}
|
||||
onClick={onNewProject}
|
||||
testId="entry-nav-new-project"
|
||||
>
|
||||
|
|
@ -76,8 +79,8 @@ export function EntryNavRail({ view, onViewChange, onNewProject }: Props) {
|
|||
</NavButton>
|
||||
<NavButton
|
||||
active={view === 'home'}
|
||||
ariaLabel="Home"
|
||||
title="Home"
|
||||
ariaLabel={t('entry.navHome')}
|
||||
tooltip={t('entry.navHome')}
|
||||
onClick={() => onViewChange('home')}
|
||||
testId="entry-nav-home"
|
||||
>
|
||||
|
|
@ -85,8 +88,8 @@ export function EntryNavRail({ view, onViewChange, onNewProject }: Props) {
|
|||
</NavButton>
|
||||
<NavButton
|
||||
active={view === 'projects'}
|
||||
ariaLabel="Projects"
|
||||
title="Projects"
|
||||
ariaLabel={t('entry.navProjects')}
|
||||
tooltip={t('entry.navProjects')}
|
||||
onClick={() => onViewChange('projects')}
|
||||
testId="entry-nav-projects"
|
||||
>
|
||||
|
|
@ -94,14 +97,17 @@ export function EntryNavRail({ view, onViewChange, onNewProject }: Props) {
|
|||
</NavButton>
|
||||
<NavButton
|
||||
active={view === 'design-systems'}
|
||||
ariaLabel="Design systems"
|
||||
title="Design systems"
|
||||
ariaLabel={t('entry.navDesignSystems')}
|
||||
tooltip={t('entry.navDesignSystems')}
|
||||
onClick={() => onViewChange('design-systems')}
|
||||
testId="entry-nav-design-systems"
|
||||
>
|
||||
<Icon name="palette" size={18} />
|
||||
</NavButton>
|
||||
</div>
|
||||
<div className="entry-nav-rail__footer">
|
||||
<EntryHelpMenu />
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,12 +30,14 @@ import { DesignsTab } from './DesignsTab';
|
|||
import { DesignSystemPreviewModal } from './DesignSystemPreviewModal';
|
||||
import { DesignSystemsTab } from './DesignSystemsTab';
|
||||
import { EntryNavRail, type EntryView as EntryViewKind } from './EntryNavRail';
|
||||
import { GithubStarBadge } from './GithubStarBadge';
|
||||
import { HomeView } from './HomeView';
|
||||
import { Icon } from './Icon';
|
||||
import { InlineModelSwitcher } from './InlineModelSwitcher';
|
||||
import { NewProjectModal } from './NewProjectModal';
|
||||
import type { CreateInput } from './NewProjectPanel';
|
||||
import type { PluginLoopSubmit } from './PluginLoopHome';
|
||||
import { UseEverywhereModal } from './UseEverywhereModal';
|
||||
|
||||
// Default scenario plugin for each project kind. The modal-based
|
||||
// create flow no longer surfaces a plugin picker — every submission
|
||||
|
|
@ -102,6 +104,7 @@ interface Props {
|
|||
| 'execution'
|
||||
| 'media'
|
||||
| 'composio'
|
||||
| 'integrations'
|
||||
| 'language'
|
||||
| 'appearance'
|
||||
| 'notifications'
|
||||
|
|
@ -151,8 +154,17 @@ export function EntryShell({
|
|||
const [avatarMenuOpen, setAvatarMenuOpen] = useState(false);
|
||||
const [languageExpanded, setLanguageExpanded] = useState(false);
|
||||
const [newProjectOpen, setNewProjectOpen] = useState(false);
|
||||
const [useEverywhereOpen, setUseEverywhereOpen] = useState(false);
|
||||
const avatarMenuRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// The agent-handoff guide substitutes 127.0.0.1:7456 in every snippet
|
||||
// with whatever URL the user actually has open, so the curl examples
|
||||
// they paste into Hermes / openclaw / Cursor work without manual
|
||||
// editing. Falls back to the documented default when window is
|
||||
// unavailable (SSR / unit-test render).
|
||||
const liveDaemonUrl =
|
||||
typeof window !== 'undefined' ? window.location.origin : undefined;
|
||||
|
||||
function changeView(next: EntryViewKind) {
|
||||
navigate({ kind: 'home', view: next });
|
||||
}
|
||||
|
|
@ -308,6 +320,20 @@ export function EntryShell({
|
|||
</div>
|
||||
) : null}
|
||||
<div style={{ height: 1, background: 'var(--border-soft)', margin: '4px 6px' }} />
|
||||
<button
|
||||
type="button"
|
||||
className="avatar-item"
|
||||
onClick={() => {
|
||||
setAvatarMenuOpen(false);
|
||||
setUseEverywhereOpen(true);
|
||||
}}
|
||||
data-testid="entry-avatar-use-everywhere"
|
||||
>
|
||||
<span className="avatar-item-icon" aria-hidden>
|
||||
<Icon name="link" size={14} />
|
||||
</span>
|
||||
<span>{t('entry.useEverywhereTitle')}</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="avatar-item"
|
||||
|
|
@ -336,6 +362,7 @@ export function EntryShell({
|
|||
/>
|
||||
<main className="entry-main entry-main--scroll">
|
||||
<div className="entry-main__topbar">
|
||||
<GithubStarBadge />
|
||||
<InlineModelSwitcher
|
||||
config={config}
|
||||
agents={agents}
|
||||
|
|
@ -347,6 +374,21 @@ export function EntryShell({
|
|||
onApiModelChange={onApiModelChange}
|
||||
onOpenSettings={onOpenSettings}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="use-everywhere-chip"
|
||||
onClick={() => setUseEverywhereOpen(true)}
|
||||
title={t('entry.useEverywhereTitle')}
|
||||
aria-label={t('entry.useEverywhereAria')}
|
||||
data-testid="entry-use-everywhere-button"
|
||||
>
|
||||
<span className="use-everywhere-chip__icon" aria-hidden>
|
||||
<Icon name="link" size={13} />
|
||||
</span>
|
||||
<span className="use-everywhere-chip__label">
|
||||
{t('entry.useEverywhereTitle')}
|
||||
</span>
|
||||
</button>
|
||||
{avatarMenu}
|
||||
</div>
|
||||
<div
|
||||
|
|
@ -424,6 +466,16 @@ export function EntryShell({
|
|||
onOpenConnectorsTab={() => onOpenSettings('composio')}
|
||||
onClose={() => setNewProjectOpen(false)}
|
||||
/>
|
||||
{useEverywhereOpen ? (
|
||||
<UseEverywhereModal
|
||||
onClose={() => setUseEverywhereOpen(false)}
|
||||
onOpenSettings={() => {
|
||||
setUseEverywhereOpen(false);
|
||||
onOpenSettings('integrations');
|
||||
}}
|
||||
{...(liveDaemonUrl ? { daemonUrl: liveDaemonUrl } : {})}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ interface Props {
|
|||
onOpenLiveArtifact: (projectId: string, artifactId: string) => void;
|
||||
onDeleteProject: (id: string) => void;
|
||||
onChangeDefaultDesignSystem: (id: string) => void;
|
||||
onOpenSettings: (section?: 'execution' | 'media' | 'composio' | 'language' | 'appearance' | 'notifications' | 'pet' | 'about') => void;
|
||||
onOpenSettings: (section?: 'execution' | 'media' | 'composio' | 'integrations' | 'language' | 'appearance' | 'notifications' | 'pet' | 'about') => void;
|
||||
}
|
||||
|
||||
const CONNECTOR_CALLBACK_MESSAGE_TYPE = 'open-design:connector-connected';
|
||||
|
|
|
|||
123
apps/web/src/components/GithubStarBadge.tsx
Normal file
123
apps/web/src/components/GithubStarBadge.tsx
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// Sticky "Star · <count>" pill in the entry top bar.
|
||||
//
|
||||
// Mirrors the marketing landing-page header (`apps/landing-page`):
|
||||
// fetches `/repos/nexu-io/open-design` once on mount, formats the
|
||||
// count, and renders a small CTA that opens the GitHub repo in a new
|
||||
// tab. The result is cached at module scope so navigating between
|
||||
// entry sub-views doesn't trigger a fresh API call, and the request
|
||||
// is wrapped in a try/catch so an offline / rate-limited fetch never
|
||||
// breaks the topbar layout — the pill simply falls back to "Star".
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Icon } from './Icon';
|
||||
import { useT } from '../i18n';
|
||||
|
||||
const REPO = 'https://github.com/nexu-io/open-design';
|
||||
const API = 'https://api.github.com/repos/nexu-io/open-design';
|
||||
const LS_KEY = 'open-design:gh-stars';
|
||||
// One-hour soft cache — long enough to dodge GitHub's 60/hr
|
||||
// unauthenticated quota when the same user reopens the app several
|
||||
// times in a session, short enough that growing star counts still
|
||||
// surface within a single working day.
|
||||
const CACHE_TTL_MS = 60 * 60 * 1000;
|
||||
|
||||
type CachedStars = { count: number; ts: number };
|
||||
|
||||
let memoryCache: CachedStars | null = null;
|
||||
|
||||
function readPersistedCache(): CachedStars | null {
|
||||
if (typeof window === 'undefined') return null;
|
||||
try {
|
||||
const raw = window.localStorage.getItem(LS_KEY);
|
||||
if (!raw) return null;
|
||||
const parsed = JSON.parse(raw) as Partial<CachedStars>;
|
||||
if (
|
||||
typeof parsed.count !== 'number' ||
|
||||
typeof parsed.ts !== 'number'
|
||||
)
|
||||
return null;
|
||||
return { count: parsed.count, ts: parsed.ts };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function writePersistedCache(value: CachedStars): void {
|
||||
if (typeof window === 'undefined') return;
|
||||
try {
|
||||
window.localStorage.setItem(LS_KEY, JSON.stringify(value));
|
||||
} catch {
|
||||
// Quota errors are fine to swallow — the in-memory cache still
|
||||
// keeps subsequent renders cheap within this tab.
|
||||
}
|
||||
}
|
||||
|
||||
function formatStars(count: number): string {
|
||||
if (!Number.isFinite(count) || count <= 0) return '0';
|
||||
if (count < 1000) return String(count);
|
||||
return `${(count / 1000).toFixed(1).replace(/\.0$/, '')}K`;
|
||||
}
|
||||
|
||||
export function GithubStarBadge() {
|
||||
const t = useT();
|
||||
const [count, setCount] = useState<number | null>(() => {
|
||||
if (memoryCache) return memoryCache.count;
|
||||
const persisted = readPersistedCache();
|
||||
if (persisted) memoryCache = persisted;
|
||||
return persisted ? persisted.count : null;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const now = Date.now();
|
||||
const cached = memoryCache ?? readPersistedCache();
|
||||
if (cached && now - cached.ts < CACHE_TTL_MS) {
|
||||
memoryCache = cached;
|
||||
setCount(cached.count);
|
||||
return;
|
||||
}
|
||||
const ctrl = new AbortController();
|
||||
(async () => {
|
||||
try {
|
||||
const res = await fetch(API, {
|
||||
headers: { Accept: 'application/vnd.github+json' },
|
||||
signal: ctrl.signal,
|
||||
});
|
||||
if (!res.ok) return;
|
||||
const data = (await res.json()) as { stargazers_count?: unknown };
|
||||
if (typeof data.stargazers_count !== 'number') return;
|
||||
const next: CachedStars = {
|
||||
count: data.stargazers_count,
|
||||
ts: Date.now(),
|
||||
};
|
||||
memoryCache = next;
|
||||
writePersistedCache(next);
|
||||
setCount(next.count);
|
||||
} catch {
|
||||
// Network failures and rate-limit 403s both land here. The
|
||||
// pill keeps rendering its previous (or fallback) count.
|
||||
}
|
||||
})();
|
||||
return () => ctrl.abort();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<a
|
||||
className="entry-star-badge"
|
||||
href={REPO}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
aria-label={t('entry.githubStarAria')}
|
||||
title={t('entry.githubStarTitle')}
|
||||
data-testid="entry-star-badge"
|
||||
>
|
||||
<Icon name="github" size={13} className="entry-star-badge__icon" />
|
||||
<span className="entry-star-badge__label">{t('entry.githubStarLabel')}</span>
|
||||
<span className="entry-star-badge__sep" aria-hidden>
|
||||
·
|
||||
</span>
|
||||
<span className="entry-star-badge__count" data-loading={count === null}>
|
||||
{count === null ? '—' : formatStars(count)}
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ type IconName =
|
|||
| 'folder'
|
||||
| 'github'
|
||||
| 'grid'
|
||||
| 'help-circle'
|
||||
| 'history'
|
||||
| 'home'
|
||||
| 'image'
|
||||
|
|
@ -236,6 +237,14 @@ export function Icon({ name, size = 14, strokeWidth = 1.6, ...rest }: Props) {
|
|||
<rect x="14" y="14" width="7" height="7" rx="1" />
|
||||
</svg>
|
||||
);
|
||||
case 'help-circle':
|
||||
return (
|
||||
<svg {...common}>
|
||||
<circle cx="12" cy="12" r="10" />
|
||||
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" />
|
||||
<path d="M12 17h.01" />
|
||||
</svg>
|
||||
);
|
||||
case 'history':
|
||||
return (
|
||||
<svg {...common}>
|
||||
|
|
|
|||
|
|
@ -168,6 +168,19 @@ export const ar: Dict = {
|
|||
'entry.openSettingsAria': 'فتح الإعدادات',
|
||||
'entry.resizeAria': 'تغيير حجم الشريط الجانبي',
|
||||
'entry.loadingWorkspace': 'جاري تحميل مساحة العمل...',
|
||||
'entry.navNewProject': 'مشروع جديد',
|
||||
'entry.navHome': 'الرئيسية',
|
||||
'entry.navProjects': 'المشاريع',
|
||||
'entry.navDesignSystems': 'أنظمة التصميم',
|
||||
'entry.helpAria': 'المساعدة',
|
||||
'entry.helpMenuAria': 'قائمة المساعدة',
|
||||
'entry.helpGetHelp': 'احصل على مساعدة على GitHub',
|
||||
'entry.helpSubmitFeature': 'اقترح ميزة',
|
||||
'entry.helpWhatsNew': 'الجديد',
|
||||
'entry.helpDownloadDesktop': 'تنزيل تطبيق سطح المكتب',
|
||||
'entry.githubStarLabel': 'نجمة',
|
||||
'entry.githubStarTitle': 'انقر لمنحنا نجمة على GitHub',
|
||||
'entry.githubStarAria': 'منح Open Design نجمة على GitHub',
|
||||
'entry.tabImageTemplates': 'قوالب الصور',
|
||||
'entry.tabVideoTemplates': 'قوالب الفيديو',
|
||||
'promptTemplates.searchPlaceholder': 'بحث في القوالب...',
|
||||
|
|
|
|||
|
|
@ -167,6 +167,21 @@ export const de: Dict = {
|
|||
'entry.openSettingsAria': 'Einstellungen öffnen',
|
||||
'entry.resizeAria': 'Seitenleiste skalieren',
|
||||
'entry.loadingWorkspace': 'Workspace wird geladen…',
|
||||
'entry.useEverywhereTitle': 'Überall verwenden',
|
||||
'entry.useEverywhereAria': 'Anleitung „Überall verwenden“ öffnen (CLI, MCP, HTTP, Skills)',
|
||||
'entry.navNewProject': 'Neues Projekt',
|
||||
'entry.navHome': 'Start',
|
||||
'entry.navProjects': 'Projekte',
|
||||
'entry.navDesignSystems': 'Design-Systeme',
|
||||
'entry.helpAria': 'Hilfe',
|
||||
'entry.helpMenuAria': 'Hilfemenü',
|
||||
'entry.helpGetHelp': 'Hilfe auf GitHub',
|
||||
'entry.helpSubmitFeature': 'Feature vorschlagen',
|
||||
'entry.helpWhatsNew': 'Neuigkeiten',
|
||||
'entry.helpDownloadDesktop': 'Desktop-App herunterladen',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'Klicken, um uns auf GitHub einen Stern zu geben',
|
||||
'entry.githubStarAria': 'Open Design auf GitHub einen Stern geben',
|
||||
'entry.tabImageTemplates': 'Bildvorlagen',
|
||||
'entry.tabVideoTemplates': 'Videovorlagen',
|
||||
'promptTemplates.searchPlaceholder': 'Templates suchen…',
|
||||
|
|
|
|||
|
|
@ -166,6 +166,8 @@ export const en: Dict = {
|
|||
'entry.openSettingsAria': 'Open settings',
|
||||
'entry.resizeAria': 'Resize sidebar',
|
||||
'entry.loadingWorkspace': 'Loading workspace…',
|
||||
'entry.useEverywhereTitle': 'Use everywhere',
|
||||
'entry.useEverywhereAria': 'Open the Use Everywhere guide (CLI, MCP, HTTP, Skills)',
|
||||
'entry.navNewProject': 'New project',
|
||||
'entry.navHome': 'Home',
|
||||
'entry.navProjects': 'Projects',
|
||||
|
|
|
|||
|
|
@ -167,6 +167,21 @@ export const esES: Dict = {
|
|||
'entry.openSettingsAria': 'Abrir ajustes',
|
||||
'entry.resizeAria': 'Redimensionar barra lateral',
|
||||
'entry.loadingWorkspace': 'Cargando espacio de trabajo…',
|
||||
'entry.useEverywhereTitle': 'Usar en todas partes',
|
||||
'entry.useEverywhereAria': 'Abrir la guía «Usar en todas partes» (CLI, MCP, HTTP, Skills)',
|
||||
'entry.navNewProject': 'Nuevo proyecto',
|
||||
'entry.navHome': 'Inicio',
|
||||
'entry.navProjects': 'Proyectos',
|
||||
'entry.navDesignSystems': 'Sistemas de diseño',
|
||||
'entry.helpAria': 'Ayuda',
|
||||
'entry.helpMenuAria': 'Menú de ayuda',
|
||||
'entry.helpGetHelp': 'Obtener ayuda en GitHub',
|
||||
'entry.helpSubmitFeature': 'Enviar una sugerencia',
|
||||
'entry.helpWhatsNew': 'Novedades',
|
||||
'entry.helpDownloadDesktop': 'Descargar app de escritorio',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'Haz clic para darnos una estrella en GitHub',
|
||||
'entry.githubStarAria': 'Dar una estrella a Open Design en GitHub',
|
||||
'entry.tabImageTemplates': 'Plantillas de imagen',
|
||||
'entry.tabVideoTemplates': 'Plantillas de vídeo',
|
||||
'promptTemplates.searchPlaceholder': 'Buscar plantillas…',
|
||||
|
|
|
|||
|
|
@ -168,6 +168,19 @@ export const fa: Dict = {
|
|||
'entry.openSettingsAria': 'باز کردن تنظیمات',
|
||||
'entry.resizeAria': 'تغییر اندازه نوار کناری',
|
||||
'entry.loadingWorkspace': 'در حال بارگذاری فضای کاری…',
|
||||
'entry.navNewProject': 'پروژه جدید',
|
||||
'entry.navHome': 'خانه',
|
||||
'entry.navProjects': 'پروژهها',
|
||||
'entry.navDesignSystems': 'سیستمهای طراحی',
|
||||
'entry.helpAria': 'راهنما',
|
||||
'entry.helpMenuAria': 'منوی راهنما',
|
||||
'entry.helpGetHelp': 'دریافت کمک در GitHub',
|
||||
'entry.helpSubmitFeature': 'پیشنهاد قابلیت',
|
||||
'entry.helpWhatsNew': 'تازهها',
|
||||
'entry.helpDownloadDesktop': 'دانلود اپلیکیشن دسکتاپ',
|
||||
'entry.githubStarLabel': 'ستاره',
|
||||
'entry.githubStarTitle': 'برای ما در GitHub ستاره بگذارید',
|
||||
'entry.githubStarAria': 'به Open Design در GitHub ستاره بدهید',
|
||||
'promptTemplates.searchPlaceholder': 'جستجوی قالبها…',
|
||||
'promptTemplates.countLabel': '{n} نتیجه',
|
||||
'promptTemplates.emptyImage': 'هنوز قالب پرامپت تصویر نصب نشده است.',
|
||||
|
|
|
|||
|
|
@ -168,6 +168,21 @@ export const fr: Dict = {
|
|||
'entry.openSettingsAria': 'Ouvrir les paramètres',
|
||||
'entry.resizeAria': 'Redimensionner la barre latérale',
|
||||
'entry.loadingWorkspace': 'Chargement de l\'espace de travail…',
|
||||
'entry.useEverywhereTitle': 'Utiliser partout',
|
||||
'entry.useEverywhereAria': 'Ouvrir le guide « Utiliser partout » (CLI, MCP, HTTP, Skills)',
|
||||
'entry.navNewProject': 'Nouveau projet',
|
||||
'entry.navHome': 'Accueil',
|
||||
'entry.navProjects': 'Projets',
|
||||
'entry.navDesignSystems': 'Systèmes de design',
|
||||
'entry.helpAria': 'Aide',
|
||||
'entry.helpMenuAria': 'Menu d\'aide',
|
||||
'entry.helpGetHelp': 'Obtenir de l\'aide sur GitHub',
|
||||
'entry.helpSubmitFeature': 'Proposer une fonctionnalité',
|
||||
'entry.helpWhatsNew': 'Nouveautés',
|
||||
'entry.helpDownloadDesktop': 'Télécharger l\'app de bureau',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'Cliquez pour nous mettre une étoile sur GitHub',
|
||||
'entry.githubStarAria': 'Mettre une étoile à Open Design sur GitHub',
|
||||
'entry.tabImageTemplates': 'Modèles d\'image',
|
||||
'entry.tabVideoTemplates': 'Modèles de vidéo',
|
||||
'promptTemplates.searchPlaceholder': 'Rechercher des modèles…',
|
||||
|
|
|
|||
|
|
@ -168,6 +168,19 @@ export const hu: Dict = {
|
|||
'entry.openSettingsAria': 'Beállítások megnyitása',
|
||||
'entry.resizeAria': 'Oldalsáv átméretezése',
|
||||
'entry.loadingWorkspace': 'Munkaterület betöltése…',
|
||||
'entry.navNewProject': 'Új projekt',
|
||||
'entry.navHome': 'Kezdőlap',
|
||||
'entry.navProjects': 'Projektek',
|
||||
'entry.navDesignSystems': 'Tervezőrendszerek',
|
||||
'entry.helpAria': 'Súgó',
|
||||
'entry.helpMenuAria': 'Súgó menü',
|
||||
'entry.helpGetHelp': 'Kérj segítséget a GitHubon',
|
||||
'entry.helpSubmitFeature': 'Funkció javaslása',
|
||||
'entry.helpWhatsNew': 'Újdonságok',
|
||||
'entry.helpDownloadDesktop': 'Asztali alkalmazás letöltése',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'Csillagozz meg minket a GitHubon',
|
||||
'entry.githubStarAria': 'Csillagozd meg az Open Design projektet a GitHubon',
|
||||
'entry.tabImageTemplates': 'Képsablonok',
|
||||
'entry.tabVideoTemplates': 'Videósablonok',
|
||||
'promptTemplates.searchPlaceholder': 'Sablonok keresése…',
|
||||
|
|
|
|||
|
|
@ -260,6 +260,19 @@ export const id: Dict = {
|
|||
'entry.openSettingsAria': 'Buka pengaturan',
|
||||
'entry.resizeAria': 'Ubah ukuran sidebar',
|
||||
'entry.loadingWorkspace': 'Memuat workspace...',
|
||||
'entry.navNewProject': 'Proyek baru',
|
||||
'entry.navHome': 'Beranda',
|
||||
'entry.navProjects': 'Proyek',
|
||||
'entry.navDesignSystems': 'Sistem desain',
|
||||
'entry.helpAria': 'Bantuan',
|
||||
'entry.helpMenuAria': 'Menu bantuan',
|
||||
'entry.helpGetHelp': 'Dapatkan bantuan di GitHub',
|
||||
'entry.helpSubmitFeature': 'Ajukan fitur',
|
||||
'entry.helpWhatsNew': 'Apa yang baru',
|
||||
'entry.helpDownloadDesktop': 'Unduh aplikasi desktop',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'Klik untuk memberi star di GitHub',
|
||||
'entry.githubStarAria': 'Beri star Open Design di GitHub',
|
||||
'entry.tabImageTemplates': 'Templat gambar',
|
||||
'entry.tabVideoTemplates': 'Templat video',
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,21 @@ export const ja: Dict = {
|
|||
'entry.openSettingsAria': '設定を開く',
|
||||
'entry.resizeAria': 'サイドバーをリサイズ',
|
||||
'entry.loadingWorkspace': 'ワークスペースを読み込み中…',
|
||||
'entry.useEverywhereTitle': 'どこでも使う',
|
||||
'entry.useEverywhereAria': '「どこでも使う」ガイドを開く(CLI、MCP、HTTP、Skills)',
|
||||
'entry.navNewProject': '新規プロジェクト',
|
||||
'entry.navHome': 'ホーム',
|
||||
'entry.navProjects': 'プロジェクト',
|
||||
'entry.navDesignSystems': 'デザインシステム',
|
||||
'entry.helpAria': 'ヘルプ',
|
||||
'entry.helpMenuAria': 'ヘルプメニュー',
|
||||
'entry.helpGetHelp': 'GitHub でサポートを受ける',
|
||||
'entry.helpSubmitFeature': '機能をリクエスト',
|
||||
'entry.helpWhatsNew': '最新情報',
|
||||
'entry.helpDownloadDesktop': 'デスクトップアプリをダウンロード',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'GitHub でスターを付ける',
|
||||
'entry.githubStarAria': 'GitHub で Open Design にスターを付ける',
|
||||
'entry.tabImageTemplates': '画像テンプレート',
|
||||
'entry.tabVideoTemplates': '動画テンプレート',
|
||||
'promptTemplates.searchPlaceholder': 'テンプレートを検索…',
|
||||
|
|
|
|||
|
|
@ -168,6 +168,21 @@ export const ko: Dict = {
|
|||
'entry.openSettingsAria': '설정 열기',
|
||||
'entry.resizeAria': '사이드바 크기 조절',
|
||||
'entry.loadingWorkspace': '워크스페이스를 불러오는 중…',
|
||||
'entry.useEverywhereTitle': '어디서나 사용',
|
||||
'entry.useEverywhereAria': '‘어디서나 사용’ 가이드 열기 (CLI, MCP, HTTP, Skills)',
|
||||
'entry.navNewProject': '새 프로젝트',
|
||||
'entry.navHome': '홈',
|
||||
'entry.navProjects': '프로젝트',
|
||||
'entry.navDesignSystems': '디자인 시스템',
|
||||
'entry.helpAria': '도움말',
|
||||
'entry.helpMenuAria': '도움말 메뉴',
|
||||
'entry.helpGetHelp': 'GitHub 에서 도움 받기',
|
||||
'entry.helpSubmitFeature': '기능 제안하기',
|
||||
'entry.helpWhatsNew': '새로운 소식',
|
||||
'entry.helpDownloadDesktop': '데스크탑 앱 다운로드',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'GitHub 에서 별을 눌러주세요',
|
||||
'entry.githubStarAria': 'GitHub 에서 Open Design 에 별 누르기',
|
||||
'entry.tabImageTemplates': '이미지 템플릿',
|
||||
'entry.tabVideoTemplates': '비디오 템플릿',
|
||||
'promptTemplates.searchPlaceholder': '템플릿 검색…',
|
||||
|
|
|
|||
|
|
@ -168,6 +168,19 @@ export const pl: Dict = {
|
|||
'entry.openSettingsAria': 'Otwórz ustawienia',
|
||||
'entry.resizeAria': 'Zmień rozmiar paska bocznego',
|
||||
'entry.loadingWorkspace': 'Ładowanie obszaru roboczego…',
|
||||
'entry.navNewProject': 'Nowy projekt',
|
||||
'entry.navHome': 'Strona główna',
|
||||
'entry.navProjects': 'Projekty',
|
||||
'entry.navDesignSystems': 'Systemy projektowe',
|
||||
'entry.helpAria': 'Pomoc',
|
||||
'entry.helpMenuAria': 'Menu pomocy',
|
||||
'entry.helpGetHelp': 'Uzyskaj pomoc na GitHubie',
|
||||
'entry.helpSubmitFeature': 'Zaproponuj funkcję',
|
||||
'entry.helpWhatsNew': 'Co nowego',
|
||||
'entry.helpDownloadDesktop': 'Pobierz aplikację na komputer',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'Daj nam gwiazdkę na GitHubie',
|
||||
'entry.githubStarAria': 'Daj Open Design gwiazdkę na GitHubie',
|
||||
'entry.tabImageTemplates': 'Szablony obrazów',
|
||||
'entry.tabVideoTemplates': 'Szablony wideo',
|
||||
'promptTemplates.searchPlaceholder': 'Szukaj szablonów…',
|
||||
|
|
|
|||
|
|
@ -165,6 +165,21 @@ export const ptBR: Dict = {
|
|||
'entry.openSettingsAria': 'Abrir configurações',
|
||||
'entry.resizeAria': 'Redimensionar barra lateral',
|
||||
'entry.loadingWorkspace': 'Carregando área de trabalho…',
|
||||
'entry.useEverywhereTitle': 'Usar em qualquer lugar',
|
||||
'entry.useEverywhereAria': 'Abrir o guia “Usar em qualquer lugar” (CLI, MCP, HTTP, Skills)',
|
||||
'entry.navNewProject': 'Novo projeto',
|
||||
'entry.navHome': 'Início',
|
||||
'entry.navProjects': 'Projetos',
|
||||
'entry.navDesignSystems': 'Design systems',
|
||||
'entry.helpAria': 'Ajuda',
|
||||
'entry.helpMenuAria': 'Menu de ajuda',
|
||||
'entry.helpGetHelp': 'Obter ajuda no GitHub',
|
||||
'entry.helpSubmitFeature': 'Sugerir um recurso',
|
||||
'entry.helpWhatsNew': 'Novidades',
|
||||
'entry.helpDownloadDesktop': 'Baixar app para desktop',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'Clique para nos dar uma estrela no GitHub',
|
||||
'entry.githubStarAria': 'Dar uma estrela ao Open Design no GitHub',
|
||||
'entry.tabImageTemplates': 'Modelos de imagem',
|
||||
'entry.tabVideoTemplates': 'Modelos de vídeo',
|
||||
'promptTemplates.searchPlaceholder': 'Buscar templates…',
|
||||
|
|
|
|||
|
|
@ -165,6 +165,19 @@ export const ru: Dict = {
|
|||
'entry.openSettingsAria': 'Открыть настройки',
|
||||
'entry.resizeAria': 'Изменить размер боковой панели',
|
||||
'entry.loadingWorkspace': 'Загрузка рабочего пространства…',
|
||||
'entry.navNewProject': 'Новый проект',
|
||||
'entry.navHome': 'Главная',
|
||||
'entry.navProjects': 'Проекты',
|
||||
'entry.navDesignSystems': 'Дизайн-системы',
|
||||
'entry.helpAria': 'Помощь',
|
||||
'entry.helpMenuAria': 'Меню помощи',
|
||||
'entry.helpGetHelp': 'Получить помощь на GitHub',
|
||||
'entry.helpSubmitFeature': 'Предложить функцию',
|
||||
'entry.helpWhatsNew': 'Что нового',
|
||||
'entry.helpDownloadDesktop': 'Скачать настольное приложение',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'Поставьте нам звезду на GitHub',
|
||||
'entry.githubStarAria': 'Поставить Open Design звезду на GitHub',
|
||||
'entry.tabImageTemplates': 'Шаблоны изображений',
|
||||
'entry.tabVideoTemplates': 'Шаблоны видео',
|
||||
'promptTemplates.searchPlaceholder': 'Поиск шаблонов…',
|
||||
|
|
|
|||
|
|
@ -162,6 +162,19 @@ export const tr: Dict = {
|
|||
'entry.openSettingsAria': 'Ayarları aç',
|
||||
'entry.resizeAria': 'Yan çubuğu yeniden boyutlandır',
|
||||
'entry.loadingWorkspace': 'Çalışma alanı yükleniyor…',
|
||||
'entry.navNewProject': 'Yeni proje',
|
||||
'entry.navHome': 'Ana sayfa',
|
||||
'entry.navProjects': 'Projeler',
|
||||
'entry.navDesignSystems': 'Tasarım sistemleri',
|
||||
'entry.helpAria': 'Yardım',
|
||||
'entry.helpMenuAria': 'Yardım menüsü',
|
||||
'entry.helpGetHelp': 'GitHub üzerinden yardım alın',
|
||||
'entry.helpSubmitFeature': 'Özellik öner',
|
||||
'entry.helpWhatsNew': 'Yenilikler',
|
||||
'entry.helpDownloadDesktop': 'Masaüstü uygulamasını indir',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'GitHub üzerinde bize yıldız verin',
|
||||
'entry.githubStarAria': 'Open Design\u2019a GitHub üzerinde yıldız ver',
|
||||
'entry.tabImageTemplates': 'Görsel istemleri',
|
||||
'entry.tabVideoTemplates': 'Video istemleri',
|
||||
'promptTemplates.searchPlaceholder': 'Şablon ara…',
|
||||
|
|
@ -483,6 +496,24 @@ export const tr: Dict = {
|
|||
'avatar.reasoningLabel': 'Akıl yürütme',
|
||||
'avatar.customSuffix': '(özel)',
|
||||
|
||||
'inlineSwitcher.chipTitle': 'CLI / modeli değiştir',
|
||||
'inlineSwitcher.chipCli': 'Yerel CLI',
|
||||
'inlineSwitcher.chipByok': 'BYOK',
|
||||
'inlineSwitcher.modelDefault': 'varsayılan',
|
||||
'inlineSwitcher.noAgent': 'ajan yok',
|
||||
'inlineSwitcher.modeLabel': 'Mod',
|
||||
'inlineSwitcher.agentLabel': 'Ajan',
|
||||
'inlineSwitcher.providerLabel': 'Sağlayıcı',
|
||||
'inlineSwitcher.modelLabel': 'Model',
|
||||
'inlineSwitcher.useCli': 'Yerel CLI kullan',
|
||||
'inlineSwitcher.useByok': 'Kendi API anahtarını kullan',
|
||||
'inlineSwitcher.daemonOffline': 'Daemon çevrimdışı — ayarları aç',
|
||||
'inlineSwitcher.noAgentsDetected': "PATH'te CLI bulunamadı",
|
||||
'inlineSwitcher.openSettingsForModel': 'Sağlayıcıyı Ayarlardan yapılandırın',
|
||||
'inlineSwitcher.missingApiKey': 'API anahtarı yok — Ayarlardan ekleyin.',
|
||||
'inlineSwitcher.openFullSettings': 'Yürütme ayarlarını aç',
|
||||
'inlineSwitcher.customSuffix': '(özel)',
|
||||
|
||||
'project.backToProjects': 'Projelere dön',
|
||||
'project.metaFreeform': 'serbest stil',
|
||||
'project.resizeChatPanel': 'Sohbet panelini yeniden boyutlandır',
|
||||
|
|
|
|||
|
|
@ -167,6 +167,19 @@ export const uk: Dict = {
|
|||
'entry.openSettingsAria': 'Відкрити налаштування',
|
||||
'entry.resizeAria': 'Змінити розмір бічної панелі',
|
||||
'entry.loadingWorkspace': 'Завантаження робочого простору…',
|
||||
'entry.navNewProject': 'Новий проєкт',
|
||||
'entry.navHome': 'Головна',
|
||||
'entry.navProjects': 'Проєкти',
|
||||
'entry.navDesignSystems': 'Дизайн-системи',
|
||||
'entry.helpAria': 'Довідка',
|
||||
'entry.helpMenuAria': 'Меню довідки',
|
||||
'entry.helpGetHelp': 'Отримати допомогу на GitHub',
|
||||
'entry.helpSubmitFeature': 'Запропонувати функцію',
|
||||
'entry.helpWhatsNew': 'Що нового',
|
||||
'entry.helpDownloadDesktop': 'Завантажити настільний застосунок',
|
||||
'entry.githubStarLabel': 'Star',
|
||||
'entry.githubStarTitle': 'Поставте нам зірку на GitHub',
|
||||
'entry.githubStarAria': 'Поставити Open Design зірку на GitHub',
|
||||
'entry.tabImageTemplates': 'Шаблони зображень',
|
||||
'entry.tabVideoTemplates': 'Шаблони відеороликів',
|
||||
'promptTemplates.searchPlaceholder': 'Пошук шаблонів…',
|
||||
|
|
@ -501,6 +514,24 @@ export const uk: Dict = {
|
|||
'avatar.reasoningLabel': 'Міркування',
|
||||
'avatar.customSuffix': '(власна)',
|
||||
|
||||
'inlineSwitcher.chipTitle': 'Перемкнути CLI / модель',
|
||||
'inlineSwitcher.chipCli': 'Локальна CLI',
|
||||
'inlineSwitcher.chipByok': 'BYOK',
|
||||
'inlineSwitcher.modelDefault': 'за замовчуванням',
|
||||
'inlineSwitcher.noAgent': 'агент не вибрано',
|
||||
'inlineSwitcher.modeLabel': 'Режим',
|
||||
'inlineSwitcher.agentLabel': 'Агент',
|
||||
'inlineSwitcher.providerLabel': 'Провайдер',
|
||||
'inlineSwitcher.modelLabel': 'Модель',
|
||||
'inlineSwitcher.useCli': 'Використовувати локальну CLI',
|
||||
'inlineSwitcher.useByok': 'Використовувати власний API-ключ',
|
||||
'inlineSwitcher.daemonOffline': 'Демон офлайн — відкрийте налаштування',
|
||||
'inlineSwitcher.noAgentsDetected': 'CLI не знайдено в PATH',
|
||||
'inlineSwitcher.openSettingsForModel': 'Налаштуйте провайдера в Налаштуваннях',
|
||||
'inlineSwitcher.missingApiKey': 'Не задано API-ключ — відкрийте Налаштування.',
|
||||
'inlineSwitcher.openFullSettings': 'Відкрити налаштування виконання',
|
||||
'inlineSwitcher.customSuffix': '(власна)',
|
||||
|
||||
'project.backToProjects': 'Назад до проектів',
|
||||
'project.metaFreeform': 'вільна форма',
|
||||
'project.resizeChatPanel': 'Змінити розмір панелі чату',
|
||||
|
|
|
|||
|
|
@ -164,6 +164,8 @@ export const zhCN: Dict = {
|
|||
'entry.openSettingsAria': '打开设置',
|
||||
'entry.resizeAria': '调整侧边栏宽度',
|
||||
'entry.loadingWorkspace': '正在加载工作区…',
|
||||
'entry.useEverywhereTitle': '随处使用',
|
||||
'entry.useEverywhereAria': '打开「随处使用」指南(CLI、MCP、HTTP、Skills)',
|
||||
'entry.navNewProject': '新建项目',
|
||||
'entry.navHome': '主页',
|
||||
'entry.navProjects': '项目',
|
||||
|
|
|
|||
|
|
@ -164,6 +164,8 @@ export const zhTW: Dict = {
|
|||
'entry.openSettingsAria': '開啟設定',
|
||||
'entry.resizeAria': '調整側邊欄寬度',
|
||||
'entry.loadingWorkspace': '正在載入工作區…',
|
||||
'entry.useEverywhereTitle': '隨處使用',
|
||||
'entry.useEverywhereAria': '開啟「隨處使用」指南(CLI、MCP、HTTP、Skills)',
|
||||
'entry.navNewProject': '新建專案',
|
||||
'entry.navHome': '主頁',
|
||||
'entry.navProjects': '專案',
|
||||
|
|
|
|||
|
|
@ -320,6 +320,8 @@ export interface Dict {
|
|||
'entry.openSettingsAria': string;
|
||||
'entry.resizeAria': string;
|
||||
'entry.loadingWorkspace': string;
|
||||
'entry.useEverywhereTitle': string;
|
||||
'entry.useEverywhereAria': string;
|
||||
// Left nav rail (icon-only) — surface labels also serve as tooltips
|
||||
'entry.navNewProject': string;
|
||||
'entry.navHome': string;
|
||||
|
|
|
|||
|
|
@ -11,3 +11,4 @@
|
|||
@import './recent-projects.css';
|
||||
@import './plugins-home.css';
|
||||
@import './new-project-modal.css';
|
||||
@import './use-everywhere.css';
|
||||
|
|
|
|||
357
apps/web/src/styles/home/use-everywhere.css
Normal file
357
apps/web/src/styles/home/use-everywhere.css
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
/* ============================================================
|
||||
Use Open Design Everywhere — modal that documents Open Design's
|
||||
non-UI surfaces (CLI, MCP, HTTP, Skills) and lets the user copy
|
||||
a one-shot guide into their agent (Claude Code, Codex, openclaw,
|
||||
hermes, etc.).
|
||||
|
||||
Block names follow the same BEM convention as `.plugin-details-modal`
|
||||
so the visual language stays consistent inside the entry shell.
|
||||
============================================================ */
|
||||
|
||||
.use-everywhere-modal-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 920;
|
||||
background: rgba(28, 27, 26, 0.42);
|
||||
backdrop-filter: blur(2px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
.use-everywhere-modal {
|
||||
width: 100%;
|
||||
max-width: 860px;
|
||||
max-height: calc(100vh - 64px);
|
||||
background: var(--bg-panel);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-lg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.use-everywhere-modal__head {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding: 20px 22px 16px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: var(--bg-panel);
|
||||
}
|
||||
.use-everywhere-modal__head-titles {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
.use-everywhere-modal__kicker {
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--accent-strong, var(--accent));
|
||||
font-weight: 600;
|
||||
}
|
||||
.use-everywhere-modal__title {
|
||||
margin: 0;
|
||||
font-size: 19px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--text-strong);
|
||||
}
|
||||
.use-everywhere-modal__subtitle {
|
||||
margin: 0;
|
||||
font-size: 12.5px;
|
||||
line-height: 1.55;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.use-everywhere-modal__close {
|
||||
appearance: none;
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
color: var(--text-muted);
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: var(--radius-sm, 6px);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.use-everywhere-modal__close:hover,
|
||||
.use-everywhere-modal__close:focus-visible {
|
||||
background: var(--bg-subtle);
|
||||
color: var(--text);
|
||||
border-color: var(--border);
|
||||
}
|
||||
|
||||
/* Tab strip — one row of pill buttons for the five surfaces. */
|
||||
.use-everywhere-modal__tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
padding: 10px 22px 0;
|
||||
border-bottom: 1px dashed var(--border);
|
||||
background: var(--bg-panel);
|
||||
}
|
||||
.use-everywhere-modal__tab {
|
||||
appearance: none;
|
||||
border: 1px solid transparent;
|
||||
background: transparent;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
padding: 6px 12px 8px;
|
||||
margin-bottom: -1px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
cursor: pointer;
|
||||
transition: color 120ms ease, background-color 120ms ease,
|
||||
border-color 120ms ease;
|
||||
}
|
||||
.use-everywhere-modal__tab:hover {
|
||||
color: var(--text);
|
||||
background: var(--bg-subtle);
|
||||
}
|
||||
.use-everywhere-modal__tab.is-active {
|
||||
color: var(--text-strong);
|
||||
background: var(--bg);
|
||||
border-color: var(--border);
|
||||
border-bottom-color: var(--bg);
|
||||
}
|
||||
|
||||
.use-everywhere-modal__body {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
padding: 18px 22px 6px;
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.use-everywhere-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
}
|
||||
.use-everywhere-section__head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
.use-everywhere-section__heading {
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
letter-spacing: -0.005em;
|
||||
}
|
||||
.use-everywhere-section__intro {
|
||||
margin: 0;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.use-everywhere-section__bullets {
|
||||
margin: 0;
|
||||
padding-left: 18px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
font-size: 12.5px;
|
||||
line-height: 1.55;
|
||||
color: var(--text);
|
||||
}
|
||||
.use-everywhere-section__bullets li::marker {
|
||||
color: var(--text-faint);
|
||||
}
|
||||
.use-everywhere-section__snippets {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
.use-everywhere-section__footer {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
line-height: 1.55;
|
||||
color: var(--text-muted);
|
||||
background: var(--bg-subtle);
|
||||
border: 1px dashed var(--border);
|
||||
border-radius: var(--radius-sm, 6px);
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
.use-everywhere-snippet {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-sm, 6px);
|
||||
background: var(--bg-panel);
|
||||
overflow: hidden;
|
||||
}
|
||||
.use-everywhere-snippet__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 8px 10px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: var(--bg-subtle);
|
||||
font-size: 11.5px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.use-everywhere-snippet__label {
|
||||
font-weight: 500;
|
||||
color: var(--text);
|
||||
}
|
||||
.use-everywhere-snippet__copy {
|
||||
appearance: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg);
|
||||
color: var(--text-muted);
|
||||
padding: 3px 8px;
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
cursor: pointer;
|
||||
transition: color 120ms ease, border-color 120ms ease;
|
||||
}
|
||||
.use-everywhere-snippet__copy:hover {
|
||||
color: var(--accent);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
.use-everywhere-snippet__pre {
|
||||
margin: 0;
|
||||
padding: 12px 14px;
|
||||
font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
||||
font-size: 12px;
|
||||
line-height: 1.55;
|
||||
color: var(--text);
|
||||
overflow-x: auto;
|
||||
white-space: pre;
|
||||
background: var(--bg-panel);
|
||||
}
|
||||
.use-everywhere-snippet__pre code {
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.use-everywhere-modal__foot {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
padding: 14px 22px;
|
||||
border-top: 1px solid var(--border);
|
||||
background: var(--bg-panel);
|
||||
}
|
||||
.use-everywhere-modal__foot-info {
|
||||
font-size: 12px;
|
||||
line-height: 1.45;
|
||||
color: var(--text-muted);
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
.use-everywhere-modal__foot-info strong {
|
||||
color: var(--text-strong);
|
||||
}
|
||||
.use-everywhere-modal__foot-actions {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.use-everywhere-modal__primary,
|
||||
.use-everywhere-modal__secondary {
|
||||
appearance: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12.5px;
|
||||
font-weight: 500;
|
||||
padding: 8px 14px;
|
||||
border-radius: var(--radius-sm, 6px);
|
||||
cursor: pointer;
|
||||
transition: background-color 120ms ease, color 120ms ease,
|
||||
border-color 120ms ease;
|
||||
}
|
||||
.use-everywhere-modal__secondary {
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
.use-everywhere-modal__secondary:hover {
|
||||
background: var(--bg-subtle);
|
||||
}
|
||||
.use-everywhere-modal__primary {
|
||||
background: var(--accent);
|
||||
color: var(--accent-on, #fff);
|
||||
border: 1px solid var(--accent);
|
||||
}
|
||||
.use-everywhere-modal__primary:hover {
|
||||
background: var(--accent-strong, var(--accent));
|
||||
border-color: var(--accent-strong, var(--accent));
|
||||
}
|
||||
|
||||
/* Top-bar entry chip — sibling of the existing settings cog avatar.
|
||||
The chip wraps an icon + label so the affordance reads like an
|
||||
intentional doc/help entry rather than a generic icon button. On
|
||||
tight viewports the label collapses and the chip acts as an icon. */
|
||||
.use-everywhere-chip {
|
||||
appearance: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 999px;
|
||||
background: var(--bg-panel);
|
||||
color: var(--text);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
box-shadow: var(--shadow-xs);
|
||||
transition: background-color 120ms ease, border-color 120ms ease,
|
||||
color 120ms ease;
|
||||
}
|
||||
.use-everywhere-chip:hover {
|
||||
background: var(--bg-subtle);
|
||||
border-color: var(--border-strong);
|
||||
}
|
||||
.use-everywhere-chip:focus-visible {
|
||||
outline: 2px solid var(--accent);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
.use-everywhere-chip__icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--accent);
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.use-everywhere-chip__label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.use-everywhere-chip__label {
|
||||
display: none;
|
||||
}
|
||||
.use-everywhere-chip {
|
||||
padding: 0 8px;
|
||||
}
|
||||
.use-everywhere-modal__foot {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
.use-everywhere-modal__foot-actions {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue