18 Commits

Author SHA1 Message Date
twosugar 2843b64766 fix: 补 @types/markdown-it 依赖 2026-08-28 17:26:28 +08:00
twosugar 43a386ca92 chore(lint): 引入 oxlint 并清理未使用代码
新增 oxlint@1.80.0 + .oxlintrc.json + lint/lint:fix 脚本;清空所有
no-unused-vars 告警(未用 React/导入/变量/参数),删除无引用的 ui/Skill。
oxlint exit 0。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-28 16:14:18 +08:00
twosugar 2cdddf342f fix(build): bidirectional copy-routes, css minify, sitemap filter & CI dist path
copy-routes now emits both foo.html and foo/index.html so the unchanged nginx serves docs/sdk (.html) and the catch-all (/index.html). Fix an invalid empty selector in api-reference.css that broke lightningcss minify. Exclude migration URLs from the sitemap. Point the release/canary deploy at dist/ instead of the removed docs/.vitepress/dist (was uploading an empty dir → no md/html on OSS).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-28 15:04:41 +08:00
twosugar ebc9ed3628 feat(migrate): align shell/docs with legacy, add mobile responsive & login redirect
Header is now position:fixed (like legacy) so it stays pinned during overscroll; #main-content reserves its 60px. Rebuild the mobile top nav (icon hamburger, accordion Features, overlay panel) and the docs local-nav (reveal-on-scroll bar + On this page TOC). Fixed-header/mobile fixes: 60px logo→menu gap, mobile tail alignment, footer 2-col + centered bottom bar, breadcrumb/doc-footer alignment, symmetric mobile padding. MCP page excluded from the docs sidebar (sidebar:false). Migrate the login redirect logic from the legacy AppNav: createLoginRedirectPath (/login?redirect_to=<sso?redirect_to=current>&logout=1&with-us=1), login state via window.longportInternal, and the logged-in Dashboard + avatar dropdown; UserAvatar now renders the full login block.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-28 13:40:03 +08:00
twosugar b38e88f63c feat(migrate): replicate homepage & skill pages 1:1 with legacy
Port the legacy VitePress homepage (10 sections: hero, channels, features, CLI spotlight, AI Skill, MCP, API capabilities, SDK, get-started, CTA) and the Skill page (hero, demo, catalog, capability, cases, get-started) as hydrated React islands, matching legacy markup/CSS and interactions. Add a shared CopyButton with copied feedback across the homepage code blocks. Remove 14 orphaned homepage sections and the old SkillCatalog; wire the home/skill islands via the [...slug] routes and the mdx-component map.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-28 13:39:19 +08:00
twosugar 7a3daba71c feat(migrate): sync upstream main into Astro and align footer with legacy
Content (from origin/main, 3 locales):
- add grid trading, multi-leg, CLI ai/serve, and style-guide pages (58 files)
- rename Longbridge AI -> LongbridgeAI; add multi-leg fields, remove
  contract_size, add US paper-account notes (39 files)
- sync grid trading endpoints into openapi.yaml

Components:
- footer: add AI Integrations column (MCP / ChatGPT App / Claude Connector);
  restore legacy tagline, status pill, padding, grid, heading + link styles;
  hug footer to content (drop mt-16)
- sdk-links: support grid module (GridContext, hideGo)
- raw markdown: serve EN source prefixless at /docs/<path>.md (legacy parity)

Polish:
- CliCommand terminal card with per-command doc deep-links
- resolve relative-slug URLs in sidebar / prev-next / breadcrumb
- hydrate pricing billing toggle + eyebrow badge; thin scrollbars
- global body base + site-wide antialiasing

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-27 15:56:05 +08:00
twosugar b90cbb4eb4 feat(docs): align doc detail page with legacy (footer, callout, meta, anchors, TOC, sidebar)
- Docs pages render a slim link-row footer (DocFooter) instead of the big
  marketing footer; BaseLayout gains a hideFooter prop
- Callout blocks restyled to the legacy TipContainer look (1px border, radius,
  per-type icon, accent-coloured title + body)
- Doc meta row (Markdown / Edit / Last Updated) via DocMeta; real per-page
  dates from origin/main git history (src/lib/last-updated.ts)
- Body copy: antialiased smoothing + faint rgba(0,0,0,.06) underline colour to
  match legacy .vp-doc
- Heading anchors moved to the left gutter; scroll-margin-top offsets the 61px
  sticky header on TOC/anchor jumps
- TOC pinned at its at-rest offset so it no longer jumps up on scroll
- Breadcrumb: bold current-page crumb
- Sidebar: childless category folders (e.g. cli/ipo) render as clickable bold
  headers instead of dead muted leaves

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-25 19:45:38 +08:00
twosugar fd6b5a6996 fix(migrate): restore root "Overview" sidebar entry (docs/{locale}/index.mdx)
Follow-up to the sidebar refactor. The legacy sidebar shows a top-level
"Overview" (/docs) as the first, active item — it's docs/{locale}/docs/
index.mdx (title Overview / 平台介绍 / 平台介紹, sidebar_position -999,
book_open icon). buildItems() skipped EVERY index.mdx, so that page never
appeared in the tree and /docs had no active sidebar item.

buildItems() gains an `includeIndex` param (default false). buildSidebar's
root call passes true so the root index.mdx is emitted as a top-level leaf
(link /docs, /zh-CN/docs, /zh-HK/docs via urlFromAbsPath; -999 sorts it
first). Nested index.mdx files still skip — they're absorbed as directory
links via _category_.json, unchanged.

Applies to both scopes: docs/{locale}/docs/index.mdx and the cli sidebar's
docs/{locale}/docs/cli/index.mdx (both exist in all three locales).

Verified: /docs now shows "Overview" with book-open icon + teal active
pill at the top of the first group, matching the legacy reference.
navigation.test.ts 3/3 pass (non-empty, zh-CN count == en count, position
ascending all still hold — the new node's -999 sorts first).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-24 11:14:51 +08:00
twosugar f5793031f0 fix(migrate): pre-cutover polish — title fallback, SDK hero SVG, locale SSR binding
Gate-4 flagged three A-class residuals blocking cutover:

- **A5/A21** — Homepage tab title `(untitled)` on / and /zh-CN/.
  index.mdx frontmatter uses `titleTemplate` (not `title`); the 3
  [...slug].astro dispatchers were hard-fallback to '(untitled)'.
  Now cascade: title → titleTemplate → 'Longbridge Developers'.
  content.config.ts schema gains a `titleTemplate` z.string().optional().

- **A19** — /sdk hero SVG rendered as literal text `/assets/sdk.svg`.
  Stage-1 T11 SDK.tsx placeholder shipped a text stub instead of
  <img>. Ported the layout from legacy SDK.vue (max-w-4xl 2-col hero
  with h-244 svg on the right). Asset copied to
  public/assets/sdk.svg (matches legacy `docs/public/assets/sdk.svg`
  path convention).

- **B8** (new) — /zh-CN/ hero rendered English strings ("Powering",
  "Get Started") despite Chinese nav. Root: mdx `<NewHomePage />`
  tag has no way to thread route locale through <Content components>.
  Solved via `buildMdxComponents(locale)` factory that binds locale
  at SSR time to any component with a `locale?` prop
  (SkillCatalog / NewHomePage / McpTools / Pricing / QuotePermission
  / TryIt). Three [...slug].astro files now call
  `buildMdxComponents('en'|'zh-CN'|'zh-HK')` per locale.

  NewHomePage also grows a client-side detectLocale() fallback via
  document.documentElement.lang for edge cases where propsLocale is
  absent (defensive; the factory ensures it's always passed).

Verified:
- astro check: 0 errors (138 files)
- / SSR: "Powering" / "Get Started" (en)
- /zh-CN/ SSR: "接入" / "快速开始" (Simplified)
- /zh-HK/ SSR: "接入" / "快速開始" (Traditional)
- /sdk SSR: <img class="h-[244px]" src="/assets/sdk.svg" alt="">
- /assets/sdk.svg → 200

Gate-4 A-class findings all closed; cutover unblocked pending §S12
(nginx) + §S13 (canary).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-19 11:59:11 +08:00
twosugar 3679945744 feat(migrate): port inspira animation components to React workspace
Sprint 2 §S9. Ports 18 vue animation components (1462 lines) from
`docs/.vitepress/theme/components/inspira/` to React inside a new
`packages/inspira` workspace published as `@longbridge/openapi-inspira`.
Adds `motion` (v13.x — API-compatible with the ^11 the plan
suggested; `motion-v` in vue → `motion/react` in React).

Files created (18 components + barrel):
- packages/inspira/package.json — bun workspace, motion dep
- packages/inspira/tsconfig.json
- packages/inspira/src/index.ts — barrel
- packages/inspira/src/AnimatedBeam.tsx (from 190-line vue)
- packages/inspira/src/BentoGrid.tsx (18)
- packages/inspira/src/BentoGridItem.tsx (32)
- packages/inspira/src/BlurReveal.tsx (54)
- packages/inspira/src/BorderBeam.tsx (61)
- packages/inspira/src/BoxReveal.tsx (47)
- packages/inspira/src/ColourfulText.tsx (73)
- packages/inspira/src/FlickeringGrid.tsx (256)
- packages/inspira/src/GlowBorder.tsx (59)
- packages/inspira/src/GlowingEffect.tsx (94)
- packages/inspira/src/InteractiveGridPattern.tsx (70)
- packages/inspira/src/InteractiveHoverButton.tsx (64)
- packages/inspira/src/Marquee.tsx (73)
- packages/inspira/src/Meteors.tsx (57)
- packages/inspira/src/MorphingText.tsx (100)
- packages/inspira/src/NumberTicker.tsx (75)
- packages/inspira/src/ShimmerButton.tsx (75)
- packages/inspira/src/TextHighlight.tsx (64)

Migration decisions:
- `motion/react` in place of `motion-v` — same underlying framer-motion
- CSS keyframes from Vue `<style scoped>` re-emitted as `<style>` JSX
  tags with `inspira-` prefix to prevent collisions
- `propsRef` pattern in FlickeringGrid + MorphingText to avoid stale
  closures in RAF loops
- `useElementVisibility` + `useTransition` (@vueuse/core) replaced with
  native `IntersectionObserver` + `requestAnimationFrame`
- Fixed 2 type errors uncovered by check: duplicate borderRadius in
  GlowBorder inline styles; canvas/ctx narrowing through nested
  closures in FlickeringGrid

Modified:
- root package.json — @longbridge/openapi-inspira workspace dep +
  motion dep

Verified:
- astro check: 0 errors (132 files)
- 8 canonical URLs return 200

Deferred: rewiring homepage sections to use inspira components lands
alongside §S10 composite polish; §S9 scope is producing the package.

Closes Sprint 2 §S9.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-19 10:12:38 +08:00
twosugar 01efaccf80 feat(migrate): port NewHomePage (15 sections + ArchCanvas) to React workspace
Sprint 2 §S8. Ports legacy `docs/.vitepress/theme/components/NewHomePage/`
(16 vue files, 9122 lines) to React inside a new `packages/homepage`
workspace published as `@longbridge/openapi-homepage`. Chunked-read
protocol across four subagent batches (§S8, §S8-b, §S8-c, §S8-d) since
individual vue files were too large for a single subagent context (up
to 930 lines each; index.vue at 2912 lines was skipped in favour of a
purpose-built React aggregator).

Sections ported (15):
- HeroSection (352 lines vue)
- CoreFeaturesSection (290)
- CapSection (236)
- ArchSection (231; wires SdkMarquee with SDK data lifted from vue)
- ArchCanvas (498; pure CSS flexbox arch diagram — no @xyflow/react
  needed after all)
- MarketCoverage (177)
- PlatformStats (458)
- ProductOpenAPI (668)
- ProductCLI (730)
- ProductMCP (792)
- ProductSkill (930)
- SdkMarquee (401)
- GetStarted (278)
- StyleToggle (36; kept as controlled widget, not page section)
- HomepageFooter (133; distinct from site-wide shell/Footer)

Files created:
- packages/homepage/package.json — bun workspace; @longbridge/openapi-utils dep
- packages/homepage/tsconfig.json
- packages/homepage/src/index.ts — barrel
- packages/homepage/src/NewHomePage.tsx — aggregator, imports all 15
  sections in the same order as legacy index.vue
- packages/homepage/src/ArchCanvas.tsx
- packages/homepage/src/homepage.css — page-level styles
- packages/homepage/src/sections/*.tsx — 15 section files

Files modified:
- src/mdx-components.tsx — swap import from placeholder to
  `@longbridge/openapi-homepage`
- root package.json — workspace dep

Files deleted:
- src/components/mdx/placeholders/NewHomePage.tsx

Verified:
- astro check: 0 errors (113 files)
- 7 canonical URLs return 200
- data-lbus-component tags visible in /: hero-section, core-features,
  cap-section, arch-section, market-coverage, platform-stats,
  product-openapi, product-cli, product-mcp, product-skill, sdk-marquee,
  arch-canvas, get-started, homepage-footer, new-home-page

Deferrals:
- SdkMarquee is wired through ArchSection with the SDK_LIST hoisted
  out; if legacy shows SdkMarquee elsewhere on the page, that mount
  point will surface in the gate visual diff and can be adjusted
- Animations (parallax, typewriter, particles, gradient shifts) match
  legacy behavioral shape; pixel-perfect timing may need a second pass
  in §S11 gate

Closes Sprint 2 §S8 (gate finding A1 / A5 / A6 / A7 / A21).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-19 09:58:03 +08:00
twosugar d83d52b73d feat(migrate): port TryIt (interactive API caller) to React workspace
Sprint 2 §S7. Ports legacy TryIt (9 vue files under
`docs/.vitepress/theme/components/TryIt/` + `theme/utils/{http-client,
websocket-client}.ts`) to React inside a new `packages/tryit` workspace
published as `@longbridge/openapi-tryit`. Uses react-hook-form for
form generation from openapi schema; fires real API requests against
`openapi.longportapp.com`.

Files created:
- packages/tryit/package.json — bun workspace, deps: react-hook-form,
  @longbridge/openapi-utils, @longbridge/openapi-api-reference
- packages/tryit/tsconfig.json
- packages/tryit/src/index.ts — barrel
- packages/tryit/src/TryIt.tsx — orchestrator: button mode → panel mode,
  data-lbus-component="tryit" preserved
- packages/tryit/src/AuthorizationForm.tsx — cookie/localStorage-backed
  appKey / appSecret / accessToken inputs
- packages/tryit/src/ParametersForm.tsx — walks op parameters + request
  body via SchemaRenderer
- packages/tryit/src/PlayButton.tsx — assembles request, dispatches via
  clients
- packages/tryit/src/ResponseView.tsx — pretty-prints JSON response
- packages/tryit/src/tryit.css — form + response viewer styles
- packages/tryit/src/clients/http-client.ts — verbatim port of legacy
- packages/tryit/src/clients/websocket-client.ts — verbatim port of legacy
- packages/tryit/src/utils/app-id.ts — id derivation
- packages/tryit/src/utils/request.ts — request assembly helper
- packages/tryit/src/hooks/useTryItMode.ts — `?mode=try-it` URL toggle
- packages/tryit/src/hooks/useAuthorization.ts — cookie sync
- packages/tryit/src/hooks/useResponse.ts — response state

Modified:
- src/mdx-components.tsx — swap import from placeholder to
  `@longbridge/openapi-tryit`
- root package.json — workspace dep

Deleted:
- src/components/mdx/placeholders/TryIt.tsx

Verified:
- astro check: 0 errors (0 new warnings)
- All 15 canonical URLs return 200
- `<TryIt />` registered in mdx-components; mount site (frontmatter
  `httpInfo` or explicit tag) is handled by later plumbing

Closes Sprint 2 §S7.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-19 01:26:53 +08:00
twosugar 535dc86a7a feat(migrate): port ApiReference (Scalar-style) to React workspace package
Sprint 2 §S6. Ports legacy `docs/.vitepress/theme/components/ApiReference.vue`
(1370 lines) to React inside a new `packages/api-reference` workspace
published as `@longbridge/openapi-api-reference`. Zero use of
`@scalar/*` or any third-party OpenAPI viewer — this is a manual 1:1 port.

Match legacy behaviour:
- Hash routing via `?op=<epId>` and `?page=<pageId>` + popstate listener
- Three views: intro / page / endpoint
- Sidebar with search + tag groups + method-color badges (GET/POST/PUT/DELETE)
- markdown-it prose rendering + external-link renderer patch
- Schema tree walker with `$ref` resolution + envelope detection
- Code-sample tabs (JS/Python/Rust/Java/Go/C++) via inline regex highlighter
- `QuotePermission` badge sourced from `quote-permissions.yaml`
- Locale-aware doc-link rewrites (`localizeDocLinks`)
- Dark mode double-guard `[data-theme="dark"]` + `prefers-color-scheme`

Files created:
- `packages/api-reference/package.json` — bun workspace, deps js-yaml + markdown-it
- `packages/api-reference/tsconfig.json` — extends root, includes .astro types
- `packages/api-reference/src/index.ts` — barrel
- `packages/api-reference/src/openapi-loader.ts` — yaml.load + $ref resolver
- `packages/api-reference/src/ApiReference.tsx` — top-level CSR component
- `packages/api-reference/src/CodeSample.tsx` — code panel + syntax highlight
- `packages/api-reference/src/QuotePermission.tsx` — permissions badge
- `packages/api-reference/src/api-reference.css` — 280px sidebar + fluid main +
  440px code panel + method colors + dark-mode

Files modified:
- `src/layouts/ApiReferenceLayout.astro` — mounts <ApiReference client:load
  rawYaml={rawYaml} locale={locale} /> with the CSS import (needed subpath in
  the package's `exports` field to resolve the CSS through the workspace name)
- `src/data/locale.{en,zh-CN,zh-HK}.ts` — api.* keys (search, section labels,
  copy states, intro copy, param labels, fallback, pathCopy)
- `src/mdx-components.tsx` — remove dead ApiReference entry (mounted via
  layout, not mdx tag)
- root `package.json` — workspace dep `@longbridge/openapi-api-reference`

Files deleted:
- `src/components/mdx/placeholders/ApiReference.tsx`

Runtime bugfix (post-subagent): package.json `exports` field only exposed
`.` and rejected `./src/api-reference.css` subpath, throwing a 500 on every
route once the layout tried to import the CSS. Added the CSS subpath to
`exports`. All 15 canonical URLs return 200 after fix.

Verified:
- astro check: 0 errors (85 files)
- /docs/api renders with sidebar (Overview / Real-Time Market Data / Error
  Codes + tag groups Watchlist Management / Market Temperature / Portfolio
  & Cash / News & Filings + method-color badges) + intro cards
  (REST API / WebSocket) — screenshot in gate/s6-verify-api.png
- /zh-CN/docs/api, /zh-HK/docs/api, /docs/quote/overview all 200
- `data-lbus-component` on api-reference / api-sidebar / api-intro

Closes Sprint 2 §S6 (gate finding A13 / A14).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-19 01:00:50 +08:00
twosugar 0e2dcb4c81 refactor(migrate): extract @longbridge/openapi-utils workspace package
Sprint 2 §S5: move src/lib/{slug,region,navigation,i18n}.ts + tests
into a new bun workspace `packages/utils` published as
`@longbridge/openapi-utils`. Consumers import from the package name
instead of relative paths or `@lib/*` aliases.

Files moved (git mv preserves history):
- src/lib/slug{,.test}.ts       → packages/utils/src/
- src/lib/region{,.test}.ts     → packages/utils/src/
- src/lib/navigation{,.test}.ts → packages/utils/src/
- src/lib/i18n.ts               → packages/utils/src/

New package skeleton:
- packages/utils/package.json (private workspace, "@longbridge/openapi-utils")
- packages/utils/tsconfig.json (extends root, includes .astro types
  so `astro:content` resolves in isolated TS server)
- packages/utils/src/index.ts (barrel re-exports)

Consumer updates (22 files): shell components, layouts, [...slug]
routes on all 3 locales, llms.txt endpoints, md endpoint — all import
from `@longbridge/openapi-utils` now.

tsconfig.json — removed `@lib/*` alias (dead after the move); other
aliases (`@/*`, `@components/*`, `@styles/*`, `@data/*`) intact.

Two slug.test.ts expectations updated to reflect the T3 semantics
locked in during Sprint 1.5:
- absolute slug in `en/docs/**` → `/docs/{slug}` (was `/{slug}`)
- absolute slug in `zh-CN/docs/**` → `/zh-CN/docs/{slug}` (was `/zh-CN/{slug}`)
- new coverage: absolute slug for `en/{marketing}.mdx` still site-absolute
The test file was carrying pre-T3 expectations; §S5 is when
they had to move regardless, so the correction lands here.

Verified:
- astro check: 0 errors (81 files)
- vitest: 23/23 pass
- 8 canonical URLs: all 200
- zero residual `../lib/*` / `@lib/*` import paths anywhere in
  src/ or packages/

Known deferred:
- `packages/utils/src/i18n.ts` still reads locale data via
  `../../../src/data/locale.*` (cross-boundary). Acceptable for §S5
  scope; §S10 may relocate locale data into the utils package.

Closes Sprint 2 §S5.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-18 22:13:43 +08:00
twosugar ae2121ff50 feat(migrate): render vitepress ::: callouts and Tabs UI
Sprint 1.5 mini §S11 gate flagged (A8, A12, A20):
- vitepress `:::warning`/`:::tip`/`:::success` containers render as raw
  text ("`:::warning Package Renamed`" appears in body) — 335 usages
- `<Tabs><TabItem>` ships to browser but tab bar never appears; all
  TabItems stack under each other (e.g. macOS/Windows/Linux install
  commands, /sdk language SDK panels)

A8 — Callout directive rendering
--------------------------------

remark-directive v4 (micromark-extension-directive) rejects the bare
title form `:::warning Package Renamed` and only accepts bracket labels.
Two-part fix:

- Preflight Rule 10 rewrites `:::name Title` → `:::name[Title]` in mdx
  source before the remark pipeline; scoped to known names
  (success/warning/tip/info/danger/note/caution) and never rewrites
  lines that already use `[…]` or `{…}` syntax.
- New remark plugin `src/integrations/remark-callout.ts` transforms
  parsed `containerDirective` AST nodes into
  `<div class="callout callout-{name}" role="note"
    data-lbus-component="callout-{name}">` with an optional
  `<p class="callout-title">` from the directive label (default:
  capitalised name).
- `src/styles/callout.css` maps each variant to `--lb-status-*` /
  `--lb-brand` tokens: warning=orange, danger=red, tip=teal,
  success=green, info/note/caution=blue.

A12/A20 — Tabs SSR + client hydration
--------------------------------------

Root cause: Astro renders each React component in mdx in its own React
root — `<Tabs>` children arrive as pre-serialised HTML, so
`React.Children.forEach` yields nothing, and `<TabItem>` never sees
`TabsContext.Provider`. The `useState`+`useEffect`+`registerTab` pattern
was silently no-op'ing.

Rebuilt as progressive-enhancement:

- `packages/ui/src/TabItem.tsx` — `!ctx` branch emits
  `data-tab-value`/`-label`/`-default` attrs for a client script to
  discover. TabItem's public props unchanged.
- `packages/ui/src/Tabs.tsx` — removes broken `useMemo` introspection;
  SSR renders `<div data-lbus-component="tabs" data-tabs-group-id=…
  data-tabs-variant=…>` with an empty `<div data-tabs-bar>` placeholder
  and children below. `registerTab`/localStorage machinery retained
  for future client:load hydration paths.
- `src/scripts/tabs-hydrate.ts` — vanilla-JS module bundled by Vite.
  On `DOMContentLoaded` walks `[data-lbus-component="tabs"]` wrappers,
  reads TabItem attrs, builds `<button>`s into the empty bar, hides
  non-active TabItems via inline style, wires click handlers, honours
  the existing localStorage `vitepress-tabs-{groupId}` key + syncs
  cross-instance via `__LBTabsState` / `__LBTabsListeners`.
- `src/layouts/BaseLayout.astro` — appends
  `<script>import '../scripts/tabs-hydrate'</script>` before `</body>`.

The vanilla-JS path deliberately mirrors the pre-existing React
`__LBTabsState` API so future migrations back to a React-hydrated Tabs
(e.g. under `client:load`) can coexist without behavioural diff.

Verified:
- astro-check green (after adding `export {}` to tabs-hydrate.ts so
  `declare global` is legal in a module context)
- 8 canonical URLs return 200
- chrome-devtools MCP 1440×900 hard-reload:
  - /docs/cli/install shows 4 tabs (macOS Homebrew / Linux macOS
    Script / Windows Scoop / Windows PowerShell), only active tab's
    code visible
  - /sdk shows orange "Package Renamed" callout with border-left +
    tinted background; 6 language tabs (Python / JavaScript / Rust /
    Java / Go / C++) render, only active tab visible

Closes Sprint 1.5 T5. Sprint 1.5 remediation complete — next: re-run
mini §S11 gate before beginning Sprint 2.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-18 17:53:36 +08:00
twosugar 56e3e60562 refactor(migrate): codemod BEM classNames to Tailwind utilities
Stage-1 shipped skeleton with semantic BEM classNames (top-nav,
docs-layout, sidebar, etc.) but no CSS. Hotfix 7d8f5ff4 added a 567-line
stopgap src/styles/shell.css to unblock the demo. This commit migrates
each component's className strings to inline Tailwind v4 utility classes
per spec §T3, then removes the stopgap file:

- 15 shell/ components (TopNav, Footer, Breadcrumb, LocalNav, Sidebar,
  SidebarItem, Backdrop, TOC, PrevNext, ThemeToggle, LanguageSwitcher,
  SearchButton, SearchDialog, SearchResults, UserAvatar) — BEM → Tailwind
  utility, dark mode via CSS token auto-swap.
- 3 packages/ui/ components — Tabs (`.tab-line-btn` removed; inline
  style already complete), TabItem (`.tab-item` → `py-4`), CliCommand
  (legacy `.language-bash .vp-adaptive-theme .cli-command-block` classes
  removed; `.relative` inline).
- shell.css deleted; @import removed from global.css.

Layout grid (`.docs-layout`) and mdx-emit typography (`.docs-content`
h1/h2/pre/code/blockquote) extracted to src/styles/docs.css and
imported from global.css — these style DOM emitted by mdx that cannot
be Tailwind-utility-inlined.

Token references normalised: previously-undefined `--lbus-c-border`,
`--lbus-c-text-muted`, `--lbus-c-brand`, `--lbus-c-bg-soft` (which
fell back to `currentColor` / transparent in the stopgap) replaced with
their real values in tokens.css: `--lb-stroke`, `--lb-fg-2`,
`--lb-brand`, `--lb-bg-2`.

Verified:
- astro-check green (0 errors, 5 pre-existing hints)
- 884/884 dev URLs return 200
- Chrome DevTools MCP screenshot 1440x900: top nav / sidebar / content /
  TOC / footer all render (verified against vitepress baseline; residual
  pixel-parity gaps — Features dropdown, GitHub / Get Started CTAs,
  sidebar emoji icons, breadcrumb full path, mdx table styling — are
  stage-1 skeleton residuals not introduced by this codemod; queued for
  Sprint 1.5 mini §S11 gate).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-18 15:52:05 +08:00
twosugar 4a3647e5c7 fix(migrate): add types field to @longbridge/openapi-ui package.json
Without an explicit "types" field, VS Code tsserver falls back to
seeking .d.ts files and emits TS2307 for the workspace import.
astro check is unaffected (Vite bundler resolver reads exports map)
but the editor diagnostic appears in every developer session.
Ruling in
.superpowers/sdd/2026-08-17-astro-migration-stage-1/progress.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-17 19:38:06 +08:00
twosugar c1b9ee1a0a refactor(migrate): extract mdx primitives into @longbridge/openapi-ui workspace package
- Add `"workspaces": ["packages/*"]` to root package.json
- Scaffold packages/ui with package.json (name: @longbridge/openapi-ui, v0.0.0) and tsconfig.json
- git mv 7 primitives from src/components/mdx/ to packages/ui/src/ (Tabs, TabItem, TipContainer, CliCommand, SDK, SDKLinks, Skill)
- Create packages/ui/src/index.ts barrel re-exporting all 7 components + Props types
- Update src/mdx-components.tsx to import all 7 from @longbridge/openapi-ui (single import line)
- No @lib/* / @styles/* / @components/* path aliases found in moved files; tsconfig.json requires no path overrides
- bun install links workspace package; astro check: 0 errors, 4 pre-existing hints

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-17 19:34:16 +08:00