diff --git a/ci/baselines.json b/ci/baselines.json index 9c32ca2df5..c1b4bece2e 100644 --- a/ci/baselines.json +++ b/ci/baselines.json @@ -26,7 +26,7 @@ "webkit-adoption": { "command": "pnpm -s lint:webkit && pnpm -s report:webkit-adoption", "pattern": "\\| Violations \\| \\*\\*(\\d+)\\*\\* \\|", - "baseline": 160, + "baseline": 56, "label": "violações das regras do design system" } } diff --git a/src/components/PageContent/PageContent.astro b/src/components/PageContent/PageContent.astro index 0753458490..b0c712d4d0 100644 --- a/src/components/PageContent/PageContent.astro +++ b/src/components/PageContent/PageContent.astro @@ -1,6 +1,7 @@ --- import FallbackNotice from '../FallbackNotice.astro'; +import AgentPageHeader from '~/components/webkit/AgentPageHeader.vue'; import DocPageHeader from '~/components/webkit/DocPageHeader.vue'; import ReadableContent from '~/components/webkit/ReadableContent.vue'; import DocPagination from '@aziontech/webkit/doc-pagination'; @@ -9,11 +10,18 @@ import { rtlLanguages } from '~/i18n/languages'; import { normalizeLangTag } from '~/i18n/bcp-normalize'; import { useTranslations } from '~/i18n/util'; +import type { CollectionEntry } from 'astro:content'; + import { getLanguageFromURL } from '~/util'; import { getBreadcrumb, getPageFacts, getPageHref, getTreeId, type Lang } from '~/nav/index'; export interface Props { - content: { title: string; description?: string; page_header?: boolean }; + content: { + title: string; + description?: string; + page_header?: boolean; + agent?: CollectionEntry<'docs'>['data']['agent']; + }; previous?: { text: string; link: string }; next?: { text: string; link: string }; } @@ -65,7 +73,26 @@ const headerLabels = { } -->
{ - content.page_header !== false && ( + content.page_header !== false && content.agent && ( + + ) + } + { + content.page_header !== false && !content.agent && ( diff --git a/src/components/agents/AgentCardGrid.vue b/src/components/agents/AgentCardGrid.vue deleted file mode 100644 index 5bd4ed310b..0000000000 --- a/src/components/agents/AgentCardGrid.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/src/components/agents/AgentCompareTable.astro b/src/components/agents/AgentCompareTable.astro deleted file mode 100644 index 1e419dc368..0000000000 --- a/src/components/agents/AgentCompareTable.astro +++ /dev/null @@ -1,11 +0,0 @@ ---- -import { getLanguageFromURL } from '~/util'; -import type { Lang } from '~/nav/index'; -import AgentCompareTable from './AgentCompareTable.vue'; -import { agentHrefs } from './server'; - -const lang = getLanguageFromURL(Astro.url.pathname) as Lang; -const hrefs = await agentHrefs(lang); ---- - - diff --git a/src/components/agents/AgentDocsList.vue b/src/components/agents/AgentDocsList.vue deleted file mode 100644 index 721ed41fdf..0000000000 --- a/src/components/agents/AgentDocsList.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - diff --git a/src/components/agents/AgentHeader.astro b/src/components/agents/AgentHeader.astro deleted file mode 100644 index 48b53219fa..0000000000 --- a/src/components/agents/AgentHeader.astro +++ /dev/null @@ -1,47 +0,0 @@ ---- -import { getLanguageFromURL } from '~/util'; -import { useTranslations } from '~/i18n/util'; -import { normalizeLangTag } from '~/i18n/bcp-normalize'; -import { getBreadcrumb, type Lang } from '~/nav/index'; -import AgentPageHeader from '~/components/agents/AgentPageHeader.vue'; -import { agentBySlug, agentLinks } from './data'; -import { agentPageUpdated, toolHrefs } from './server'; - -interface Props { - agent: string; -} - -const { agent } = Astro.props; -const lang = getLanguageFromURL(Astro.url.pathname) as Lang; -const t = useTranslations(Astro); -const breadcrumb = (await getBreadcrumb(Astro.url.pathname, lang)).map(({ label, url }) => ({ - label, - href: url, -})); -const markdownHref = `${Astro.url.pathname.replace(/\/$/, '')}.md`; -const entry = agentBySlug(agent); -const links = entry ? agentLinks(entry, lang, await toolHrefs(lang)) : []; -const lastUpdated = await agentPageUpdated(Astro.url.pathname, lang); -const headerLabels = { - lastUpdated: t('pageHeader.lastUpdated'), - copy: t('pageHeader.copy'), - copied: t('pageHeader.copied'), - copyTip: t('pageHeader.copyTip'), - view: t('pageHeader.view'), - viewTip: t('pageHeader.viewTip'), - agents: t('pageHeader.agents'), - agentsTip: t('pageHeader.agentsTip'), -}; ---- - - diff --git a/src/components/agents/AgentPicker.astro b/src/components/agents/AgentPicker.astro deleted file mode 100644 index 186e629522..0000000000 --- a/src/components/agents/AgentPicker.astro +++ /dev/null @@ -1,11 +0,0 @@ ---- -import { getLanguageFromURL } from '~/util'; -import type { Lang } from '~/nav/index'; -import AgentPicker from './AgentPicker.vue'; -import { agentHrefs } from './server'; - -const lang = getLanguageFromURL(Astro.url.pathname) as Lang; -const hrefs = await agentHrefs(lang); ---- - - diff --git a/src/components/agents/AgentQuickStart.vue b/src/components/agents/AgentQuickStart.vue deleted file mode 100644 index 908b824881..0000000000 --- a/src/components/agents/AgentQuickStart.vue +++ /dev/null @@ -1,97 +0,0 @@ - - - diff --git a/src/components/agents/ConceptCards.vue b/src/components/agents/ConceptCards.vue deleted file mode 100644 index 2c85a526b9..0000000000 --- a/src/components/agents/ConceptCards.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/src/components/agents/InlineText.vue b/src/components/agents/InlineText.vue deleted file mode 100644 index 72619763ba..0000000000 --- a/src/components/agents/InlineText.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - diff --git a/src/components/agents/Samples.vue b/src/components/agents/Samples.vue deleted file mode 100644 index d369557181..0000000000 --- a/src/components/agents/Samples.vue +++ /dev/null @@ -1,46 +0,0 @@ - - - diff --git a/src/components/agents/data.ts b/src/components/agents/data.ts deleted file mode 100644 index 56712f930a..0000000000 --- a/src/components/agents/data.ts +++ /dev/null @@ -1,70 +0,0 @@ -import raw from '~/data/agent-setup.json'; -import { text } from '~/nav/resolve'; -import type { Lang } from '~/nav/schema'; - -import type { Agent, AgentSetup, Localized, Sample } from './schema'; - -export type { Agent, Lang, Localized, Sample }; - -// server.ts parses this file against `agentSetup` on every build; the islands read it under that type. -export const data = raw as AgentSetup; - -export const agents = data.agents; - -export function t(value: Localized | undefined, lang: Lang): string { - if (value === undefined) return ''; - if (typeof value === 'string') return value; - return text(value, lang) ?? ''; -} - -export function fill(text: string, vars: Record): string { - return text.replace(/\{(\w+)\}/g, (_, key: string) => vars[key] ?? `{${key}}`); -} - -export function agentBySlug(slug: string): Agent | undefined { - return agents.find((agent) => agent.slug === slug); -} - -type LabelGroup = 'filters' | 'values' | 'columns' | 'links'; - -export function label(group: LabelGroup, key: string, lang: Lang): string { - return t(data.labels[group][key] ?? key, lang); -} - -export function agentTags(agent: Agent, lang: Lang): string[] { - return [ - ...agent.workflows.map((w) => label('filters', w, lang)), - label('values', agent.pricing, lang), - label('values', agent.model, lang), - label('values', agent.context, lang), - ...(agent.openSource ? [label('values', 'Open source', lang)] : []), - ]; -} - -export interface AgentLink { - label: string; - href: string; -} - -export function agentLinks( - agent: Agent, - lang: Lang, - hrefs: { mcp?: string; cli?: string } -): AgentLink[] { - return [ - { label: label('links', 'mcp', lang), href: hrefs.mcp }, - { label: label('links', 'cli', lang), href: hrefs.cli }, - { label: fill(label('links', 'docs', lang), { name: agent.name }), href: agent.docsUrl }, - ].filter((link): link is AgentLink => Boolean(link.href)); -} - -export function tooltip(key: string, lang: Lang) { - const entry = data.tooltips[key]; - if (!entry) return undefined; - return { - headline: entry.headline, - tip: t(entry.tip, lang), - cta: t(entry.cta, lang), - href: t(entry.href, lang), - }; -} diff --git a/src/components/agents/inline.ts b/src/components/agents/inline.ts deleted file mode 100644 index b69a51b854..0000000000 --- a/src/components/agents/inline.ts +++ /dev/null @@ -1,34 +0,0 @@ -export type InlineToken = - | { type: 'text'; value: string } - | { type: 'code'; value: string } - | { type: 'strong'; value: string } - | { type: 'link'; value: string; href: string } - | { type: 'tooltip'; value: string; key: string }; - -/** An href the docs will render as a link: same-site path, in-page anchor or http(s). */ -export const SAFE_HREF = /^(https?:\/\/|\/(?!\/)|#)/; - -const PATTERN = /\[\[(\w+):([^\]]+)\]\]|`([^`]+)`|\*\*([^*]+)\*\*|\[([^\]]+)\]\(([^)\s]+)\)/g; - -export function tokenize(text: string): InlineToken[] { - const tokens: InlineToken[] = []; - let last = 0; - for (const match of text.matchAll(PATTERN)) { - const index = match.index ?? 0; - if (index > last) tokens.push({ type: 'text', value: text.slice(last, index) }); - const [, tipKey, tipText, code, strong, linkText, href] = match; - if (tipKey) tokens.push({ type: 'tooltip', key: tipKey, value: tipText }); - else if (code !== undefined) tokens.push({ type: 'code', value: code }); - else if (strong !== undefined) tokens.push({ type: 'strong', value: strong }); - else if (linkText !== undefined) { - tokens.push( - SAFE_HREF.test(href) - ? { type: 'link', value: linkText, href } - : { type: 'text', value: linkText } - ); - } - last = index + match[0].length; - } - if (last < text.length) tokens.push({ type: 'text', value: text.slice(last) }); - return tokens; -} diff --git a/src/components/agents/schema.ts b/src/components/agents/schema.ts deleted file mode 100644 index 649e6d8943..0000000000 --- a/src/components/agents/schema.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { z } from 'astro/zod'; - -import { SAFE_HREF } from './inline'; - -const localized = z.union([ - z.string(), - z.object({ en: z.string(), 'pt-br': z.string().optional() }), -]); - -export type Localized = z.infer; - -const href = z.string().regex(SAFE_HREF, 'an href starts with https://, / or #'); - -const localizedHref = z.union([href, z.object({ en: href, 'pt-br': href.optional() })]); - -const sample = z.object({ - label: localized, - language: z.string(), - code: z.string(), - fileName: z.string().optional(), -}); - -export type Sample = z.infer; - -export const MARKS = [ - 'claude', - 'cursor', - 'copilot', - 'windsurf', - 'codex', - 'gemini', - 'opencode', -] as const; - -const agent = z.object({ - slug: z.string(), - namespace: z.string(), - name: z.string(), - vendor: z.string(), - mark: z.enum(MARKS), - workflows: z.array(z.string()), - pricing: z.string(), - model: z.string(), - context: z.string(), - openSource: z.boolean(), - docsUrl: href, - contextFile: z.string(), - description: localized, - install: z.object({ - body: localized, - samples: z.array(sample).optional(), - link: z.object({ label: localized, href }).optional(), - }), - connect: z.object({ - body: localized, - samples: z.array(sample).optional(), - note: localized.optional(), - }), - verify: z.object({ body: localized, samples: z.array(sample).optional() }), - tips: z.object({ en: z.array(z.string()), 'pt-br': z.array(z.string()) }), -}); - -export type Agent = z.infer; - -const card = z.object({ title: localized, icon: z.string(), description: localized }); - -const entry = z.object({ - question: localized, - answer: localized, - fallbackNote: localized.optional(), -}); - -const labelGroup = z.record(z.string(), localized); - -export const agentSetup = z.object({ - mcpUrl: href, - tokensUrl: href, - agents: z.array(agent).min(1), - tools: z.array(z.object({ id: z.string(), description: localized })), - cli: z.array(sample), - contextPrimer: z.string(), - docs: z.array( - z.object({ - title: localized, - icon: z.string(), - href: localizedHref, - target: z.enum(['_self', '_blank']).optional(), - description: localized, - }) - ), - primer: localized, - prompts: z.object({ en: z.array(z.string()).min(2), 'pt-br': z.array(z.string()).min(2) }), - workflows: z.array(card), - concepts: z.array(card), - tradeoffs: z.array(card), - steps: z.object({ - install: localized, - token: z.object({ title: localized, body: localized, link: localized }), - connect: localized, - verify: localized, - tryIt: localized, - }), - tooltips: z.record( - z.string(), - z.object({ headline: z.string(), tip: localized, cta: localized, href: localizedHref }) - ), - faq: z.array(entry), - surface: z.object({ terminal: localized, editor: localized }), - troubleshooting: z.array(entry), - labels: z.object({ - filters: labelGroup, - values: labelGroup, - columns: labelGroup, - links: labelGroup, - yes: localized, - no: localized, - madeBy: localized, - plusAzion: localized, - }), -}); - -export type AgentSetup = z.infer; diff --git a/src/components/agents/server.ts b/src/components/agents/server.ts deleted file mode 100644 index f3a03120b4..0000000000 --- a/src/components/agents/server.ts +++ /dev/null @@ -1,35 +0,0 @@ -import raw from '~/data/agent-setup.json'; -import { getLastChange, getPageFacts, getPageHref, getTreeHref, type Lang } from '~/nav/index'; - -import { agents } from './data'; -import { agentSetup } from './schema'; - -// Every agent page renders through a wrapper that imports this module, so a JSON that drifts from the schema fails the build. -agentSetup.parse(raw); - -/** Each agent's page, by slug, as the navigation resolves it for `lang`. */ -export async function agentHrefs(lang: Lang): Promise> { - const hrefs: Record = {}; - for (const agent of agents) { - const href = await getPageHref(agent.namespace, lang); - if (href) hrefs[agent.slug] = href; - } - return hrefs; -} - -export async function agentPageUpdated(pathname: string, lang: Lang): Promise { - const dates = [ - (await getPageFacts(pathname, lang))?.updated, - getLastChange('src/data/agent-setup.json'), - ].filter((date): date is string => Boolean(date)); - if (!dates.length) return undefined; - return dates - .sort((a, b) => Date.parse(a) - Date.parse(b)) - .pop() - ?.slice(0, 10); -} - -/** The landing pages the agent header links to, as the navigation resolves them for `lang`. */ -export async function toolHrefs(lang: Lang): Promise<{ mcp?: string; cli?: string }> { - return { mcp: await getTreeHref('mcp', lang), cli: await getTreeHref('cli', lang) }; -} diff --git a/src/components/agents/AgentCompareTable.vue b/src/components/webkit/AgentCompareTable.vue similarity index 62% rename from src/components/agents/AgentCompareTable.vue rename to src/components/webkit/AgentCompareTable.vue index 85189171ad..cb5ccec733 100644 --- a/src/components/agents/AgentCompareTable.vue +++ b/src/components/webkit/AgentCompareTable.vue @@ -4,13 +4,13 @@ - {{ label('columns', 'agent', lang) }} + {{ columns.agent }} - {{ label('columns', key, lang) }} + {{ columns[key] }} - {{ label('columns', key, lang) }} + {{ columns[key] }} @@ -33,9 +33,7 @@ ]" aria-hidden="true" /> - {{ - agent[key] ? t(data.labels.yes, lang) : t(data.labels.no, lang) - }} + {{ agent[key] ? yes : no }} @@ -49,30 +47,37 @@ diff --git a/src/components/agents/AgentFaq.vue b/src/components/webkit/AgentFaq.vue similarity index 52% rename from src/components/agents/AgentFaq.vue rename to src/components/webkit/AgentFaq.vue index d80054efc4..e2ea7c499f 100644 --- a/src/components/agents/AgentFaq.vue +++ b/src/components/webkit/AgentFaq.vue @@ -15,7 +15,7 @@ >

- +

@@ -25,26 +25,20 @@ diff --git a/src/components/webkit/AgentInlineText.vue b/src/components/webkit/AgentInlineText.vue new file mode 100644 index 0000000000..1e4db6341c --- /dev/null +++ b/src/components/webkit/AgentInlineText.vue @@ -0,0 +1,75 @@ + + + diff --git a/src/components/agents/AgentPageHeader.vue b/src/components/webkit/AgentPageHeader.vue similarity index 66% rename from src/components/agents/AgentPageHeader.vue rename to src/components/webkit/AgentPageHeader.vue index a61636e23d..c28e08a07a 100644 --- a/src/components/agents/AgentPageHeader.vue +++ b/src/components/webkit/AgentPageHeader.vue @@ -1,8 +1,6 @@