diff --git a/docusaurus.config.ts b/docusaurus.config.ts index be311a8..f307a7a 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -158,7 +158,6 @@ export default async (): Promise => { } else if ( entry.name.endsWith('.mbt') || entry.name.endsWith('.mbti') || - entry.name === 'moon.pkg' || entry.name === 'moon.pkg.json' || entry.name === 'moon.mod.json' ) { @@ -247,116 +246,6 @@ export default async (): Promise => { }, } }, - // In dev mode, watch showcase .mbt source files and run moon build on - // each change, then copy output to static/rabbita-2026-scc-showcase/ - // for Docusaurus to serve. - function rabbitaShowcasePlugin() { - const showcaseDir = path.join( - process.cwd(), - 'src', - 'rabbita', - '2026-scc-showcase' - ) - const staticDir = path.join( - process.cwd(), - 'static', - 'rabbita-2026-scc-showcase' - ) - const stylesSrc = path.join(showcaseDir, 'styles.css') - - function collectWatchFiles(dir: string, files: string[] = []): string[] { - const skip = new Set(['node_modules', '_build', 'target', '.git']) - for (const entry of readdirSync(dir, { withFileTypes: true })) { - if (skip.has(entry.name)) continue - const full = path.join(dir, entry.name) - if (entry.isDirectory()) { - collectWatchFiles(full, files) - } else if ( - entry.name.endsWith('.mbt') || - entry.name.endsWith('.mbti') || - entry.name === 'moon.pkg' || - entry.name === 'moon.pkg.json' || - entry.name === 'moon.mod.json' - ) { - files.push(full) - } - } - return files - } - - function findFirstJs(dir: string): string | null { - for (const entry of readdirSync(dir, { withFileTypes: true })) { - const full = path.join(dir, entry.name) - if (entry.isDirectory()) { - const found = findFirstJs(full) - if (found) return found - } else if (entry.name.endsWith('.js')) { - return full - } - } - return null - } - - function buildAndCopy(): void { - const result = spawnSync('moon', ['build', '--target', 'js', '--debug'], { - cwd: showcaseDir, - stdio: 'inherit', - }) - if (result.status !== 0) return - const buildDir = path.join(showcaseDir, '_build', 'js', 'debug', 'build') - if (!existsSync(buildDir)) return - const jsFile = findFirstJs(buildDir) - if (!jsFile) return - if (!existsSync(staticDir)) mkdirSync(staticDir, { recursive: true }) - const code = readFileSync(jsFile, 'utf8') - .replace(/\n?\/\/[#@]\s*sourceMappingURL=.*$/m, '') - .replace(/\n?\/\*#\s*sourceMappingURL=.*?\*\//m, '') - writeFileSync(path.join(staticDir, 'main.js'), code) - if (existsSync(stylesSrc)) { - copyFileSync(stylesSrc, path.join(staticDir, 'styles.css')) - } - } - - return { - name: 'rabbita-showcase', - getPathsToWatch() { - const files = collectWatchFiles(showcaseDir) - if (existsSync(stylesSrc)) files.push(stylesSrc) - return files - }, - async loadContent() { - if (process.env.NODE_ENV === 'development') { - buildAndCopy() - } - return null - }, - injectHtmlTags() { - if (process.env.NODE_ENV !== 'development') return {} - return { - headTags: [ - { - tagName: 'script', - innerHTML: ` - (function () { - var known = null; - setInterval(async function () { - if (!document.getElementById('rabbita-scc-showcase')) return; - try { - var r = await fetch('/rabbita-2026-scc-showcase/main.js', { method: 'HEAD', cache: 'no-store' }); - if (!r.ok) return; - var tag = r.headers.get('etag') || r.headers.get('last-modified'); - if (known === null) { known = tag; return; } - if (tag !== known) { known = tag; location.reload(); } - } catch (e) {} - }, 500); - })(); - `, - }, - ], - } - }, - } - }, [ './plugins/blog-plugin', { diff --git a/i18n/zh/docusaurus-plugin-content-pages/2026-scc/index.tsx b/i18n/zh/docusaurus-plugin-content-pages/2026-scc/index.tsx index 2d2827c..359ad20 100644 --- a/i18n/zh/docusaurus-plugin-content-pages/2026-scc/index.tsx +++ b/i18n/zh/docusaurus-plugin-content-pages/2026-scc/index.tsx @@ -1,5 +1,4 @@ import ContestLayout from '@site/src/components/ContestLayout' -import ContestNavbar, { items2026 } from '@site/src/components/ContestNavbar' import styles from '@site/src/pages/2026-scc/styles.module.css' export default function Page() { @@ -8,11 +7,9 @@ export default function Page() { heroImg='/img/2026-contest/kv.jpg' mobileHeroImg='/img/2026-contest/kv.jpg' qqGroupImg='/img/2026-contest/qq-group.png' - heroBgColor='#09184c' - heroBackdropImg='/img/2026-contest/kv.jpg' + heroBgColor='#051033' >
-
@@ -51,9 +48,6 @@ function ChineseContent() { > 立即报名 - - 查看作品 - diff --git a/i18n/zh/docusaurus-plugin-content-pages/2026-scc/showcase/index.tsx b/i18n/zh/docusaurus-plugin-content-pages/2026-scc/showcase/index.tsx deleted file mode 100644 index 73e2102..0000000 --- a/i18n/zh/docusaurus-plugin-content-pages/2026-scc/showcase/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import ContestLayout from '@site/src/components/ContestLayout' -import ContestNavbar, { items2026 } from '@site/src/components/ContestNavbar' -import RabbitaShowcaseMount from '@site/src/components/RabbitaShowcaseMount' -import styles from '@site/src/pages/2026-scc/showcase/wrapper.module.css' - -export default function Page() { - return ( - -
- - -
-
- ) -} diff --git a/package.json b/package.json index 11b6370..d2630dc 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,10 @@ "scripts": { "docusaurus": "docusaurus", "start": "docusaurus start --host 0.0.0.0", - "dev": "pnpm rabbita-home:build && pnpm rabbita-showcase:build && (cd src/pages/rabbita-home && npm run watch &) && docusaurus start --host 0.0.0.0", + "dev": "pnpm rabbita-home:build && (cd src/pages/rabbita-home && npm run watch &) && docusaurus start --host 0.0.0.0", "data": "tsx ./scripts/gen-data.ts", - "build": "pnpm rabbita-home:build && pnpm rabbita-showcase:build && docusaurus build", + "build": "pnpm rabbita-home:build && docusaurus build", "rabbita-home:build": "node ./scripts/build-rabbita-home.mjs", - "rabbita-showcase:build": "node ./scripts/build-rabbita-showcase.mjs", "postbuild": "cp -R static-gallery/* build/gallery/", "swizzle": "docusaurus swizzle", "deploy": "docusaurus deploy", diff --git a/scripts/build-rabbita-showcase.mjs b/scripts/build-rabbita-showcase.mjs deleted file mode 100644 index 71f3241..0000000 --- a/scripts/build-rabbita-showcase.mjs +++ /dev/null @@ -1,56 +0,0 @@ -import { spawnSync } from 'node:child_process' -import { cp, mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises' -import { readdirSync } from 'node:fs' -import path from 'node:path' -import process from 'node:process' - -const websiteDir = process.cwd() -const showcaseDir = path.resolve(websiteDir, 'src/rabbita/2026-scc-showcase') -const targetDir = path.resolve(websiteDir, 'static/rabbita-2026-scc-showcase') -const stylesSrc = path.resolve(showcaseDir, 'styles.css') - -function findFirstJs(dir) { - for (const entry of readdirSync(dir, { withFileTypes: true })) { - const full = path.join(dir, entry.name) - if (entry.isDirectory()) { - const nested = findFirstJs(full) - if (nested) return nested - } else if (entry.name.endsWith('.js')) { - return full - } - } - return null -} - -const build = spawnSync('moon', ['build', '--target', 'js', '--release'], { - cwd: showcaseDir, - stdio: 'inherit', -}) - -if (build.status !== 0) { - process.exit(build.status ?? 1) -} - -const buildDir = path.resolve(showcaseDir, '_build/js/release/build') -const jsFile = findFirstJs(buildDir) - -if (!jsFile) { - console.error('[rabbita-showcase] failed to locate compiled main.js output') - process.exit(1) -} - -const code = await stat(jsFile).then(() => - readFile(jsFile, 'utf8') -).then((text) => - text - .replace(/\n?\/\/[#@]\s*sourceMappingURL=.*$/m, '') - .replace(/\n?\/\*#\s*sourceMappingURL=.*?\*\//m, '') -) - -await stat(stylesSrc) -await rm(targetDir, { recursive: true, force: true }) -await mkdir(targetDir, { recursive: true }) -await writeFile(path.join(targetDir, 'main.js'), code) -await cp(stylesSrc, path.join(targetDir, 'styles.css')) - -console.log(`[rabbita-showcase] synced ${showcaseDir} -> ${targetDir}`) diff --git a/src/components/ContestLayout/index.tsx b/src/components/ContestLayout/index.tsx index 0501d60..de8ed83 100644 --- a/src/components/ContestLayout/index.tsx +++ b/src/components/ContestLayout/index.tsx @@ -1,12 +1,10 @@ import Layout from '@theme/Layout' import styles from './styles.module.css' -import type { CSSProperties } from 'react' type HeroProps = { img: string mobileHeroImg: string bgColor?: string - backdropImg?: string } type LayoutProps = { @@ -15,28 +13,14 @@ type LayoutProps = { qqGroupImg?: string qqGroupId?: string heroBgColor?: string - heroBackdropImg?: string children: React.ReactNode } export default function ContestLayout(props: LayoutProps) { - const { - heroImg, - mobileHeroImg, - children, - qqGroupId, - qqGroupImg, - heroBgColor, - heroBackdropImg - } = props + const { heroImg, mobileHeroImg, children, qqGroupId, qqGroupImg, heroBgColor } = props return ( - +
{qqGroupImg && (
@@ -57,14 +41,9 @@ export default function ContestLayout(props: LayoutProps) { ) } -function Hero({ img, mobileHeroImg, bgColor, backdropImg }: HeroProps) { - const style: CSSProperties & Record<'--hero-bg-image' | '--hero-bg-color', string> = { - '--hero-bg-color': bgColor || 'black', - '--hero-bg-image': backdropImg ? `url(${backdropImg})` : 'none' - } - +function Hero({ img, mobileHeroImg, bgColor }: HeroProps) { return ( -
+
diff --git a/src/components/ContestLayout/styles.module.css b/src/components/ContestLayout/styles.module.css index 233b2a9..667c330 100644 --- a/src/components/ContestLayout/styles.module.css +++ b/src/components/ContestLayout/styles.module.css @@ -1,39 +1,11 @@ .hero { - position: relative; display: flex; justify-content: center; align-items: center; - overflow: hidden; - isolation: isolate; - background-color: var(--hero-bg-color, black); -} - -.hero::before { - content: ''; - position: absolute; - inset: 0; - background-image: var(--hero-bg-image, none); - background-position: center; - background-size: cover; - background-repeat: no-repeat; - filter: blur(22px) saturate(0.9); - transform: scale(1.08); - opacity: 0.88; - pointer-events: none; -} - -.hero::after { - content: ''; - position: absolute; - inset: 0; - background: - linear-gradient(180deg, rgba(4, 8, 18, 0.08), rgba(4, 8, 18, 0.16)); - pointer-events: none; + background-color: black; } .hero img { - position: relative; - z-index: 1; width: 100%; max-width: 1200px; } @@ -47,11 +19,6 @@ } @media (max-width: 996px) { - .hero::before { - filter: blur(14px) saturate(0.92); - transform: scale(1.04); - } - .mobile-hero-img { display: block; } diff --git a/src/components/ContestNavbar/index.tsx b/src/components/ContestNavbar/index.tsx index b8f4e29..9ffd330 100644 --- a/src/components/ContestNavbar/index.tsx +++ b/src/components/ContestNavbar/index.tsx @@ -70,13 +70,7 @@ export const items2025en: ContestNavbarItem[] = [ ] export const items2026: ContestNavbarItem[] = [ - { name: '赛事章程', href: '/2026-scc' }, - { name: '作品展示墙', href: '/2026-scc/showcase' } -] - -export const items2026en: ContestNavbarItem[] = [ - { name: 'Regulations', href: '/2026-scc' }, - { name: 'Showcase Wall', href: '/2026-scc/showcase' } + { name: '赛事章程', href: '/2026-scc' } ] export default function ContestNavbar({ diff --git a/src/components/RabbitaShowcaseMount/index.tsx b/src/components/RabbitaShowcaseMount/index.tsx deleted file mode 100644 index 58ebaf6..0000000 --- a/src/components/RabbitaShowcaseMount/index.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { useEffect } from 'react' -import { useColorMode } from '@docusaurus/theme-common' -import clsx from 'clsx' -import styles from '@site/src/pages/2026-scc/showcase/wrapper.module.css' - -const mountId = 'rabbita-scc-showcase' -const scriptId = 'rabbita-scc-showcase-script' -const styleId = 'rabbita-scc-showcase-style' -const scriptSrc = '/rabbita-2026-scc-showcase/main.js' -const styleHref = '/rabbita-2026-scc-showcase/styles.css' - -type Props = { - lightModeLabel: string - darkModeLabel: string - toggleLabel: string -} - -export default function RabbitaShowcaseMount({ - lightModeLabel, - darkModeLabel, - toggleLabel -}: Props) { - const { colorMode, setColorMode } = useColorMode() - - useEffect(() => { - const oldScript = document.getElementById(scriptId) - if (oldScript) { - oldScript.remove() - } - - const oldStyle = document.getElementById(styleId) - if (oldStyle) { - oldStyle.remove() - } - - const mount = document.getElementById(mountId) - if (mount) { - mount.innerHTML = '' - } - - const style = document.createElement('link') - style.id = styleId - style.rel = 'stylesheet' - style.href = `${styleHref}?ts=${Date.now()}` - document.head.appendChild(style) - - const script = document.createElement('script') - script.id = scriptId - script.src = `${scriptSrc}?ts=${Date.now()}` - script.defer = true - document.body.appendChild(script) - - return () => { - script.remove() - style.remove() - const cleanupMount = document.getElementById(mountId) - if (cleanupMount) { - cleanupMount.innerHTML = '' - } - } - }, []) - - return ( - <> -
-
- - -
-
-
- - ) -} diff --git a/src/pages/2026-scc/index.tsx b/src/pages/2026-scc/index.tsx index dcd14f5..a25ebb2 100644 --- a/src/pages/2026-scc/index.tsx +++ b/src/pages/2026-scc/index.tsx @@ -1,5 +1,4 @@ import ContestLayout from '@site/src/components/ContestLayout' -import ContestNavbar, { items2026en } from '@site/src/components/ContestNavbar' import styles from './styles.module.css' export default function Page() { @@ -7,11 +6,9 @@ export default function Page() {
-
@@ -27,7 +24,6 @@ function EnglishContent() {

This challenge is for developers who want to actively shape the MoonBit ecosystem by leveraging AI for code generation, architectural reasoning, and collaborative engineering.

@@ -198,3 +194,4 @@ function EnglishContent() { ) } + diff --git a/src/pages/2026-scc/showcase/index.tsx b/src/pages/2026-scc/showcase/index.tsx deleted file mode 100644 index 2146e48..0000000 --- a/src/pages/2026-scc/showcase/index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import ContestLayout from '@site/src/components/ContestLayout' -import ContestNavbar, { items2026en } from '@site/src/components/ContestNavbar' -import RabbitaShowcaseMount from '@site/src/components/RabbitaShowcaseMount' -import styles from './wrapper.module.css' - -export default function Page() { - return ( - -
- - -
-
- ) -} diff --git a/src/pages/2026-scc/showcase/wrapper.module.css b/src/pages/2026-scc/showcase/wrapper.module.css deleted file mode 100644 index 5c1deb7..0000000 --- a/src/pages/2026-scc/showcase/wrapper.module.css +++ /dev/null @@ -1,77 +0,0 @@ -.shell { - width: min(1180px, calc(100% - 2rem)); - margin: 0 auto; - padding: 2rem 0 3rem; -} - -.toolbar { - display: flex; - justify-content: flex-end; - margin-bottom: 1rem; -} - -.modeSwitch { - display: inline-flex; - gap: 0.35rem; - padding: 0.3rem; - border: 1px solid rgba(185, 36, 130, 0.14); - border-radius: 999px; - background: rgba(255, 255, 255, 0.82); - box-shadow: 0 14px 30px rgba(15, 23, 42, 0.08); -} - -.modeButton { - border: 0; - padding: 0.65rem 1rem; - border-radius: 999px; - color: #42526b; - font-size: 0.95rem; - font-weight: 700; - background: transparent; - cursor: pointer; - transition: background 0.2s ease, color 0.2s ease, box-shadow 0.2s ease; -} - -.modeButtonActive { - color: #fff; - background: linear-gradient(135deg, #d1288f, #b92482); - box-shadow: 0 10px 24px rgba(185, 36, 130, 0.24); -} - -:global([data-theme='dark']) .modeSwitch { - border-color: rgba(224, 64, 176, 0.22); - background: rgba(16, 22, 34, 0.86); - box-shadow: 0 16px 34px rgba(0, 0, 0, 0.26); -} - -:global([data-theme='dark']) .modeButton { - color: #b8c5d7; -} - -:global([data-theme='dark']) .modeButtonActive { - color: #fff; - background: linear-gradient(135deg, #e040b0, #b92482); - box-shadow: 0 12px 28px rgba(185, 36, 130, 0.3); -} - -@media (max-width: 768px) { - .shell { - width: min(100%, calc(100% - 1rem)); - padding-top: 1rem; - } - - .toolbar { - justify-content: center; - } - - .modeSwitch { - width: 100%; - justify-content: center; - } - - .modeButton { - flex: 1 1 0; - padding-left: 0.8rem; - padding-right: 0.8rem; - } -} diff --git a/src/pages/2026-scc/styles.module.css b/src/pages/2026-scc/styles.module.css index 52a0f6d..b06a9a8 100644 --- a/src/pages/2026-scc/styles.module.css +++ b/src/pages/2026-scc/styles.module.css @@ -19,16 +19,7 @@ .introBtn { margin-top: 1.5rem; - display: flex; - flex-wrap: wrap; - gap: 0.75rem; - justify-content: center; -} - -.introBtn :global(.button) { - position: relative; - z-index: 1; - pointer-events: auto; + text-align: center; } .note { @@ -147,45 +138,3 @@ .container a:global(.button):hover { text-decoration: none; } - -@media (max-width: 768px) { - .container { - padding: 1.4rem 0.9rem 2rem; - } - - .intro { - padding: 1.15rem; - border-radius: 14px; - } - - .introBtn { - flex-direction: column; - align-items: stretch; - } - - .introBtn :global(.button) { - width: 100%; - justify-content: center; - } - - .rewardTable { - display: block; - overflow-x: auto; - white-space: nowrap; - } - - .container section ul, - .container section ol { - padding-left: 1.2rem; - } -} - -@media (max-width: 480px) { - .container { - padding-inline: 0.75rem; - } - - .container section { - margin-bottom: 2rem; - } -} diff --git a/src/pages/rabbita-home/vite.config.js b/src/pages/rabbita-home/vite.config.js index 596184a..336c288 100644 --- a/src/pages/rabbita-home/vite.config.js +++ b/src/pages/rabbita-home/vite.config.js @@ -17,7 +17,6 @@ function findMbtFiles(dir, files = []) { } else if ( entry.name.endsWith('.mbt') || entry.name.endsWith('.mbti') || - entry.name === 'moon.pkg' || entry.name === 'moon.pkg.json' || entry.name === 'moon.mod.json' ) { diff --git a/src/rabbita/2026-scc-showcase/main/main.mbt b/src/rabbita/2026-scc-showcase/main/main.mbt deleted file mode 100644 index 89dbc74..0000000 --- a/src/rabbita/2026-scc-showcase/main/main.mbt +++ /dev/null @@ -1,613 +0,0 @@ -///| -using @html { - a, - div, - h1, - h2, - h3, - nothing, - p, - section, - span, -} - -///| -using @rabbita {type Cmd, type Dispatch, type Html} - -///| -#cfg(target="js") -extern "js" fn get_html_lang() -> String = - #| () => document.documentElement.lang || "en" - -///| -#cfg(not(target="js")) -fn get_html_lang() -> String { - "en" -} - -///| -fn[T] lang(zh~ : T, en~ : T) -> T { - if get_html_lang().has_prefix("zh") { - zh - } else { - en - } -} - -///| -struct Model { - mounted : Bool -} - -///| -let init_model : Model = { mounted: true } - -///| -enum Msg { - Noop -} - -///| -fn update(dispatch : Dispatch[Msg], msg : Msg, model : Model) -> (Cmd, Model) { - ignore(dispatch) - ignore(msg) - (@rabbita.none, model) -} - -///| -struct LinkItem { - label : String - url : String - external : Bool -} - -///| -struct Signal { - value : String - label : String -} - -///| -struct Card { - badge : String - stage : String - category : String - title : String - subtitle : String - desc : String - fallback : String - cover : String - highlights : Array[String] - tags : Array[String] - links : Array[LinkItem] -} - -///| -struct Step { - title : String - desc : String -} - -fn link_official_site() -> String { - "https://www.moonbitlang.com/2026-scc" -} - -///| -fn hero_eyebrow() -> String { - lang( - zh="2026 MoonBit 软件合成挑战赛", - en="2026 MoonBit Software Synthesis Challenge", - ) -} - -///| -fn hero_title() -> String { - lang(zh="选手作品展示墙", en="Participant Showcase Wall") -} - -///| -fn hero_intro() -> String { - lang( - zh="截至 2026 年 3 月 25 日,这一版集中展示当前已经正式启动、并且已经公开 GitHub 仓库的参赛项目。", - en="As of March 25, 2026, this edition focuses on projects that have officially kicked off and already expose a public GitHub repository.", - ) -} - -///| -fn hero_note() -> String { - lang( - zh="本页当前展示已正式启动且已公开仓库的项目,尚未正式启动或暂未公开仓库的项目暂不在这里展示。", - en="This page currently features projects that have officially started and already expose a public GitHub repository. Projects that have not started publicly yet or are not public repos are not listed here.", - ) -} - -///| -fn btn_official_site() -> String { - lang(zh="查看赛事官网", en="View Official Contest Page") -} - -///| -fn title_slots() -> String { - "" -} - -///| -fn title_steps() -> String { - lang( - zh="如果你准备参赛,可以按下面这套信息结构准备材料,后续上墙会非常顺畅", - en="If you plan to join, this is the information structure your project should be ready to present", - ) -} - -///| -fn label_slots() -> String { - lang(zh="已正式启动项目", en="Officially Started Projects") -} - -///| -fn label_steps() -> String { - lang(zh="如何让作品上墙", en="How To Get Featured") -} - -///| -fn label_checklist() -> String { - lang(zh="建议提前准备的上墙材料", en="Suggested Materials To Prepare") -} - -///| -fn card_badge() -> String { - lang(zh="已正式启动", en="Officially Started") -} - -///| -fn contest_signals() -> Array[Signal] { - [ - { - value: lang(zh="11 个项目", en="11 Projects"), - label: lang(zh="当前已正式启动并已收录展示", en="Officially started and already featured here"), - }, - { - value: lang(zh="公开仓库", en="Public Repos"), - label: lang(zh="点击卡片即可跳转至作品仓库", en="Click any card to open the project repository"), - }, - { - value: lang(zh="公开开发中", en="Open Development"), - label: lang(zh="这些项目都已进入公开开发阶段", en="Each listed project is already being built in the open"), - }, - { - value: lang(zh="2026 年 3 月 25 日", en="March 25, 2026"), - label: lang(zh="当前整理日期", en="Current curation date"), - }, - ] -} - -///| -fn contest_cards() -> Array[Card] { - [ - { - badge: card_badge(), - stage: lang(zh="工具链", en="Tooling"), - category: lang(zh="文档转换", en="Document Conversion"), - title: "markitdown", - subtitle: lang(zh="MoonBit 实现的多格式文档转 Markdown 流水线", en="Multi-format document-to-Markdown pipeline in MoonBit"), - desc: lang(zh="markitdown 通过共享 IR 流水线把 docx、pdf、xlsx、pptx 与 html 转成结构化 Markdown,并围绕主要格式补齐了启发式恢复与回归样例。", en="markitdown converts docx, pdf, xlsx, pptx, and html into structured Markdown through a shared IR pipeline, with heuristic recovery and regression coverage across major formats."), - fallback: "markitdown", - cover: "", - highlights: [ - lang(zh="覆盖 docx、pdf、xlsx、pptx 与 html 等输入格式", en="Covers docx, pdf, xlsx, pptx, and html inputs"), - lang(zh="采用统一 IR 与 Markdown 输出器", en="Uses a unified IR plus Markdown emitter"), - lang(zh="配有基于样例的回归验证", en="Built with sample-based regression verification"), - ], - tags: [ - "MoonBit", - "Markdown", - lang(zh="文档处理", en="Document Processing"), - ], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/ZSeanYves/markitdown", external: true }, - ], - }, - { - badge: card_badge(), - stage: lang(zh="引擎", en="Engine"), - category: lang(zh="视觉小说", en="Visual Novel"), - title: "Reisen", - subtitle: lang(zh="面向浏览器的 MoonBit 视觉小说引擎", en="Browser-oriented visual novel engine built with MoonBit"), - desc: lang(zh="Reisen 是一个面向浏览器的 MoonBit 视觉小说引擎,仓库已经拆分出 core、assets、engine、app、presenter 等模块,并提供了独立文档站。", en="Reisen is a browser-focused visual novel engine in MoonBit, organized around modular subpackages such as core, assets, engine, app, and presenter, with a dedicated documentation site."), - fallback: "Reisen", - cover: "", - highlights: [ - lang(zh="围绕浏览器交付与交互体验设计", en="Designed for browser delivery and interaction"), - lang(zh="采用模块化包结构,便于长期演进", en="Modular package layout for long-term evolution"), - lang(zh="配有文档站与模板仓库,便于上手", en="Ships with docs and a companion template repo"), - ], - tags: [ - "MoonBit", - lang(zh="引擎", en="Engine"), - lang(zh="视觉小说", en="Visual Novel"), - ], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/zvmsbackend/reisen", external: true }, - { label: lang(zh="文档站", en="Docs Site"), url: "https://reisen-docs.vercel.app", external: true }, - ], - }, - { - badge: card_badge(), - stage: lang(zh="形式化方法", en="Formal Methods"), - category: lang(zh="定理证明器", en="Theorem Prover"), - title: "QED", - subtitle: lang(zh="结合 MoonBit 运行时与 Lean 验证的 kernel-first 定理证明器", en="Kernel-first theorem prover with MoonBit runtime and Lean verification"), - desc: lang(zh="QED 采用 kernel-first 设计:MoonBit 侧负责可执行、可测试的可信内核与上层封装,Lean 侧负责形式化规范对齐与证明流程。", en="QED follows a kernel-first design: the MoonBit side provides an executable and testable trusted kernel plus upper-layer wrappers, while the Lean side aligns the formal specification and proof workflow."), - fallback: "QED", - cover: "", - highlights: [ - lang(zh="以可信内核作为整个实现的核心", en="Trusted kernel is the center of the implementation"), - lang(zh="把运行时工程与形式化审计清晰分层", en="Separates runtime engineering from formal auditing"), - lang(zh="在内核之上继续扩展 logic 与 tactics 层", en="Includes logic and tactics layers above the kernel"), - ], - tags: [ - "MoonBit", - "Lean", - lang(zh="定理证明", en="Theorem Prover"), - ], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/Luna-Flow/QED", external: true }, - ], - }, - { - badge: card_badge(), - stage: lang(zh="交互工具", en="Interactive Tool"), - category: lang(zh="图表编辑器", en="Diagram Editor"), - title: "kwiver", - subtitle: lang(zh="Quiver 交换图编辑器的社区重实现", en="Community reimplementation of the Quiver commutative diagram editor"), - desc: lang(zh="kwiver 是对 Quiver 交换图编辑器的社区重实现,仓库里已经给出 JS FFI 边界说明和一版可继续扩展的浏览器 demo 骨架。", en="kwiver is a community-driven reimplementation of the Quiver commutative diagram editor, with documented JS FFI boundaries and a first-pass browser demo scaffold already in the repository."), - fallback: "kwiver", - cover: "", - highlights: [ - lang(zh="对现代交换图编辑体验进行重建", en="Recreates a modern diagram editing experience"), - lang(zh="清楚记录了 JS FFI 接入边界", en="Documents the JS FFI integration boundary clearly"), - lang(zh="包含端到端浏览器 demo 骨架", en="Includes an end-to-end browser demo scaffold"), - ], - tags: [ - "MoonBit", - lang(zh="编辑器", en="Editor"), - lang(zh="交换图", en="Diagram"), - ], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/kokic/kwiver", external: true }, - ], - }, - { - badge: card_badge(), - stage: lang(zh="工业通信", en="Industrial Communication"), - category: lang(zh="EtherCAT 主站", en="EtherCAT Master"), - title: "MoonECAT", - subtitle: lang(zh="面向 ETG.1500 Class B 的模块化 EtherCAT 主站库", en="Modular EtherCAT master library targeting ETG.1500 Class B"), - desc: lang(zh="MoonECAT 是一个用 MoonBit 编写的模块化 EtherCAT 主站库,仓库已经拆分出 HAL、protocol、mailbox、runtime 与 CLI 层,并提供了用于测试的 mock 后端。", en="MoonECAT is a modular EtherCAT master library in MoonBit. Its repository already separates HAL, protocol, mailbox, runtime, and CLI layers, and includes a mock backend for testing."), - fallback: "MoonECAT", - cover: "", - highlights: [ - lang(zh="将硬件抽象、协议、邮箱与运行时清晰分层", en="Splits hardware, protocol, mailbox, and runtime layers"), - lang(zh="提供 mock loopback 后端用于验证", en="Provides a mock loopback backend for validation"), - lang(zh="带有独立的 moonecat 命令行入口", en="Includes a dedicated moonecat command-line entry"), - ], - tags: [ - "MoonBit", - "EtherCAT", - lang(zh="工业控制", en="Industrial Control"), - ], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/Afate2023/MoonECAT", external: true }, - ], - }, - { - badge: card_badge(), - stage: lang(zh="运行时沙箱", en="Runtime Sandbox"), - category: lang(zh="POSIX Shell", en="POSIX Shell"), - title: "MoonBash", - subtitle: lang(zh="由 MoonBit 编译到纯 JavaScript 的零依赖 POSIX Shell 沙箱", en="Zero-dependency POSIX shell sandbox compiled from MoonBit to pure JavaScript"), - desc: lang(zh="MoonBash 用 MoonBit 重写 just-bash,目标是为 AI Agent、Edge 函数、浏览器终端等场景提供零依赖、纯内存的 Shell 沙箱。", en="MoonBash rewrites just-bash with MoonBit to provide a zero-dependency, pure-memory shell sandbox for AI agents, edge functions, browser terminals, and other embedded scenarios."), - fallback: "MoonBash", - cover: "", - highlights: [ - lang(zh="编译结果是纯 JavaScript,不依赖 WASM", en="Compiles to pure JavaScript without a WASM dependency"), - lang(zh="面向智能体、Serverless 与浏览器嵌入场景", en="Designed for agents, serverless, and browser embedding"), - lang(zh="在保持沙箱能力的同时扩展命令覆盖面", en="Expands the command surface while staying sandboxed"), - ], - tags: [ - "MoonBit", - "Shell", - "AI Agent", - ], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/Haoxincode/MoonBash", external: true }, - ], - }, - ] -} - -///| -fn reference_cards() -> Array[Card] { - [ - { - badge: card_badge(), - stage: lang(zh="数据层", en="Data Layer"), - category: lang(zh="ORM 工具包", en="ORM Toolkit"), - title: "morm", - subtitle: lang(zh="带有代码生成与查询构建器的轻量级 MoonBit ORM", en="Lightweight MoonBit ORM with code generation and query builders"), - desc: lang(zh="morm 把 schema 实体、生成后的 MoonBit 代码、查询构建器与执行引擎拆开设计,并且明确避免运行时反射与隐藏状态。", en="morm separates schema entities, generated MoonBit code, query builders, and execution engines. The project intentionally avoids runtime reflection and hidden ORM state."), - fallback: "morm", - cover: "", - highlights: [ - lang(zh="通过 `#morm.entity` 元数据与 mapper 生成组织模型", en="Uses `#morm.entity` metadata and generated mappers"), - lang(zh="把查询意图与执行行为清楚分离", en="Keeps query intent and execution behavior explicitly separated"), - lang(zh="提供独立项目站点承载文档", en="Provides a dedicated project site for documentation"), - ], - tags: ["MoonBit", "ORM", "SQL"], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/oboard/morm", external: true }, - { label: lang(zh="项目站点", en="Project Site"), url: "https://morm.oboard.fun", external: true }, - ], - }, - { - badge: card_badge(), - stage: lang(zh="工具链", en="Tooling"), - category: lang(zh="Markdown 引擎", en="Markdown Engine"), - title: "MoonBitMark", - subtitle: lang(zh="带有 CLI 与实验性 MCP 入口的文档转 Markdown 引擎", en="Document-to-Markdown engine with CLI and experimental MCP entrypoint"), - desc: lang(zh="MoonBitMark 提供共享的文档转 Markdown 流水线,既有 CLI 前端,也带实验性的 MCP STDIO 入口,覆盖文本、Office 文档、PDF、图片与 URL。", en="MoonBitMark is a shared document-to-Markdown pipeline with a CLI frontend and an experimental MCP STDIO entrypoint, covering text, office formats, PDFs, images, and URLs."), - fallback: "MoonBitMark", - cover: "", - highlights: [ - lang(zh="支持 TXT、CSV、JSON、PDF、图片、HTML、DOCX、PPTX 与 XLSX", en="Supports TXT, CSV, JSON, PDF, images, HTML, DOCX, PPTX, and XLSX"), - lang(zh="同时提供 CLI 工作流与面向 MCP 的接口", en="Combines a CLI workflow with an MCP-facing interface"), - lang(zh="在多种输入格式之间保持统一转换路径", en="Keeps the conversion path unified across input formats"), - ], - tags: ["MoonBit", "Markdown", "MCP"], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/hnlyxiaobing/MoonBitMark", external: true }, - ], - }, - { - badge: card_badge(), - stage: lang(zh="图形渲染", en="Graphics"), - category: lang(zh="动画播放器", en="Animation Player"), - title: "moon-lottie", - subtitle: lang(zh="带在线演示的原生 MoonBit Lottie 动画播放器", en="Native MoonBit Lottie animation player with live demo"), - desc: lang(zh="moon-lottie 直接用 MoonBit 实现 Lottie 动画播放器,已经提供在线演示,并公开测试与覆盖率状态来支撑持续渲染迭代。", en="moon-lottie implements a Lottie animation player directly in MoonBit, with a live demo plus visible test and coverage status to support ongoing rendering work."), - fallback: "moon-lottie", - cover: "", - highlights: [ - lang(zh="支持常见图形、填充、描边、渐变与 Trim Path", en="Supports common shapes, fills, strokes, gradients, and trim paths"), - lang(zh="覆盖图层、预合成、蒙版与 Matte 效果", en="Handles layers, precompositions, masks, and matte effects"), - lang(zh="提供可直接查看效果的在线演示", en="Ships with a public live demo for direct inspection"), - ], - tags: ["MoonBit", "Lottie", lang(zh="动画", en="Animation")], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/cg-zhou/moon-lottie", external: true }, - { label: lang(zh="在线演示", en="Live Demo"), url: "https://lottie.cg-zhou.top", external: true }, - ], - }, - { - badge: card_badge(), - stage: lang(zh="应用项目", en="Application"), - category: lang(zh="持续构建", en="Ongoing Build"), - title: "MoonAP", - subtitle: lang(zh="一个持续迭代中的 MoonBit 公开项目", en="A public MoonBit project under active iteration"), - desc: lang(zh="MoonAP 已经公开了基础仓库结构与源码入口,README 也明确说明后续会继续逐步扩展实现内容。", en="MoonAP has already opened its repository structure and source entrypoint, and the README explicitly states that the project will keep expanding its implementation step by step."), - fallback: "MoonAP", - cover: "", - highlights: [ - lang(zh="从一开始就公开源码与模块入口", en="Keeps the source and module entrypoint public from the start"), - lang(zh="为后续功能的逐步扩展预留了空间", en="Leaves room for the feature set to grow incrementally"), - lang(zh="适合公开开发、持续迭代的工程路线", en="Fits a public-build, iteration-driven engineering workflow"), - ], - tags: ["MoonBit", lang(zh="应用", en="App"), lang(zh="迭代", en="Iteration")], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/tangmaomao16/MoonAP", external: true }, - ], - }, - { - badge: card_badge(), - stage: lang(zh="创作工具", en="Creative Tools"), - category: lang(zh="2D 动画", en="2D Animation"), - title: "Enimate", - subtitle: lang(zh="用 MoonBit 构建的跨平台 2D 动画工具", en="Cross-platform 2D animation tool built with MoonBit"), - desc: lang(zh="Enimate 是一个用 MoonBit 构建的跨平台 2D 动画工具,已经拥有独立项目站点,仓库也提供了品牌素材与文档资源。", en="Enimate is a cross-platform 2D animation tool built with MoonBit, with a dedicated project site and a repository that already includes branding and documentation assets."), - fallback: "Enimate", - cover: "", - highlights: [ - lang(zh="面向跨平台动画创作工作流", en="Targets cross-platform animation creation workflows"), - lang(zh="直接以 MoonBit 作为创作工具底座", en="Builds directly on MoonBit for creative tooling"), - lang(zh="拥有独立的公开项目网站", en="Has a dedicated public website for the project"), - ], - tags: ["MoonBit", lang(zh="动画", en="Animation"), lang(zh="创作工具", en="Creative Tools")], - links: [ - { label: lang(zh="GitHub 仓库", en="GitHub Repo"), url: "https://github.com/enimate/enimate", external: true }, - { label: lang(zh="官网", en="Official Site"), url: "https://enimate.art", external: true }, - ], - }, - ] -} - -///| -fn steps() -> Array[Step] { - [ - { - title: lang(zh="1. 用明确范围提交申报", en="1. Apply with a concrete scope"), - desc: lang(zh="说明工程目标、目标用户、系统架构思路与可行性。赛事更偏好具备长期演进空间的系统型软件。", en="Describe the engineering goal, target users, architecture idea, and feasibility. The challenge favors system-level software with room to evolve."), - }, - { - title: lang(zh="2. 公开开发并完善交付", en="2. Build in the open"), - desc: lang(zh="准备公开 GitHub 仓库、清晰 README、可运行流程、核心路径测试,以及简明的开发复盘,说明 AI 工具如何参与。", en="Prepare a public GitHub repository, clear README, runnable workflow, tests for core paths, and a concise retrospective on how AI tools participated."), - }, - { - title: lang(zh="3. 正式启动后收录展示", en="3. Start publicly and get listed"), - desc: lang(zh="项目正式启动并进入公开开发后,即可收录到本页展示。后续答辩与遴选安排会根据赛事节奏继续推进。", en="Projects can be listed here once they have officially kicked off and moved into public development. Later-stage reviews and selection rounds will continue with the contest timeline."), - }, - ] -} - -///| -fn checklist_items() -> Array[String] { - [ - lang(zh="公开 GitHub 仓库,并保留完整开发历史", en="A public GitHub repository with commit history preserved"), - lang(zh="README 清楚写明目标、范围、使用方式与环境要求", en="README covering goals, scope, usage, and environment requirements"), - lang(zh="核心流程具备可构建、可运行、可复现路径", en="A reproducible build/run path for the core workflow"), - lang(zh="关键路径与边界情况具备测试或验证材料", en="Tests or validation material for key paths and edge cases"), - lang(zh="强烈建议补充 Demo 视频、截图或在线体验链接", en="Optional but highly recommended: demo video, screenshots, or deployment links"), - ] -} - -///| -fn view_link(link : LinkItem) -> Html { - if link.external { - a(class="rsc-link", href=link.url, target=Blank, link.label) - } else { - a(class="rsc-link", href=link.url, link.label) - } -} - -///| -fn view_signal(signal : Signal) -> Html { - div(class="rsc-signal-card", [ - h3(class="rsc-signal-value", signal.value), - p(class="rsc-signal-label", signal.label), - ]) -} - -///| -fn view_card(card : Card) -> Html { - ignore(card.badge) - ignore(card.cover) - ignore(card.fallback) - div(class="rsc-card", [ - if card.links.length() > 0 { - let primary_link = card.links[0] - a(class="rsc-card-overlay", href=primary_link.url, target=Blank, [ - span( - class="rsc-sr-only", - lang( - zh="\{card.title} 仓库", - en="\{card.title} repository", - ), - ), - ]) - } else { - nothing - }, - div(class="rsc-card-body", [ - div( - class="rsc-meta-row", - [ - span(class="rsc-meta-pill", card.stage), - span(class="rsc-meta-pill", card.category), - ], - ), - h3(class="rsc-card-title", card.title), - p(class="rsc-card-subtitle", card.subtitle), - p(class="rsc-card-desc", card.desc), - div( - class="rsc-highlights", - card.highlights.map(fn(item) { - div(class="rsc-highlight", item) - }), - ), - div( - class="rsc-tags", - card.tags.map(fn(tag) { - span(class="rsc-tag", tag) - }), - ), - div(class="rsc-links", card.links.map(fn(link) { view_link(link) })), - ]), - ]) -} - -///| -fn view_step(step : Step) -> Html { - div(class="rsc-step-card", [ - h3(class="rsc-step-title", step.title), - p(class="rsc-step-desc", step.desc), - ]) -} - -///| -fn view_checklist() -> Html { - div(class="rsc-check-panel", [ - p(class="rsc-section-label", label_checklist()), - div( - class="rsc-check-list", - checklist_items().map(fn(item) { - div(class="rsc-check-item", item) - }), - ), - ]) -} - -///| -fn view_section(label : String, title : String, cards : Array[Card]) -> Html { - section(class="rsc-section", [ - div(class="rsc-section-head", [ - p(class="rsc-section-label", label), - if title == "" { - nothing - } else { - h2(class="rsc-section-title", title) - }, - ]), - div(class="rsc-grid", cards.map(fn(card) { view_card(card) })), - ]) -} - -///| -fn view_hero() -> Html { - section(class="rsc-hero", [ - div(class="rsc-hero-copy", [ - p(class="rsc-eyebrow", hero_eyebrow()), - h1(class="rsc-hero-title", hero_title()), - p(class="rsc-hero-intro", hero_intro()), - p(class="rsc-hero-note", hero_note()), - div(class="rsc-actions", [ - a(class="rsc-btn rsc-btn--primary", href=link_official_site(), target=Blank, btn_official_site()), - ]), - ]), - div(class="rsc-signal-grid", contest_signals().map(fn(signal) { view_signal(signal) })), - ]) -} - -///| -fn view_steps() -> Html { - section(class="rsc-section", [ - div(class="rsc-section-head", [ - p(class="rsc-section-label", label_steps()), - h2(class="rsc-section-title rsc-section-title--subtle", title_steps()), - ]), - div(class="rsc-steps-grid", steps().map(fn(step) { view_step(step) })), - view_checklist(), - ]) -} - -///| -fn view(dispatch : Dispatch[Msg], model : Model) -> Html { - ignore(dispatch) - ignore(model.mounted) - let approved_cards = contest_cards() + reference_cards() - div(class="rsc-page", [ - view_hero(), - view_section(label_slots(), title_slots(), approved_cards), - view_steps(), - ]) -} - -///| -#warnings("-alert_unstable") -fn main { - ignore(Noop) - let (_, app) = @rabbita.cell_with_dispatch( - model=init_model, - update~, - view~, - ) - @rabbita.new(app).mount("rabbita-scc-showcase") -} diff --git a/src/rabbita/2026-scc-showcase/main/moon.pkg b/src/rabbita/2026-scc-showcase/main/moon.pkg deleted file mode 100644 index 78d0028..0000000 --- a/src/rabbita/2026-scc-showcase/main/moon.pkg +++ /dev/null @@ -1,8 +0,0 @@ -import { - "moonbit-community/rabbita", - "moonbit-community/rabbita/html", -} - -options( - "is-main": true, -) diff --git a/src/rabbita/2026-scc-showcase/moon.mod.json b/src/rabbita/2026-scc-showcase/moon.mod.json deleted file mode 100644 index 9f4bd98..0000000 --- a/src/rabbita/2026-scc-showcase/moon.mod.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "user/contest-showcase", - "version": "0.1.0", - "deps": { - "moonbit-community/rabbita": "0.11.5" - }, - "readme": "README.md", - "repository": "", - "license": "Apache-2.0", - "keywords": [], - "description": "Rabbita-powered showcase wall for the 2026 MoonBit Software Synthesis Challenge", - "preferred-target": "js" -} diff --git a/src/rabbita/2026-scc-showcase/styles.css b/src/rabbita/2026-scc-showcase/styles.css deleted file mode 100644 index 06e31fa..0000000 --- a/src/rabbita/2026-scc-showcase/styles.css +++ /dev/null @@ -1,738 +0,0 @@ -#rabbita-scc-showcase, -#rabbita-scc-showcase * , -#rabbita-scc-showcase *::before, -#rabbita-scc-showcase *::after { - box-sizing: border-box; -} - -#rabbita-scc-showcase { - color: var(--rsc-page-text); - --rsc-page-text: #091327; - --rsc-title-text: #0f172a; - --rsc-muted-text: #4c5d78; - --rsc-accent: #b92482; - --rsc-accent-strong: #f7c3e0; - --rsc-card-surface: - radial-gradient(circle at top right, rgba(96, 165, 250, 0.08), transparent 24%), - linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(244, 248, 255, 0.99)); - --rsc-card-border: rgba(8, 18, 45, 0.08); - --rsc-card-shadow: 0 18px 40px rgba(12, 25, 69, 0.07); - --rsc-pill-text: #1740a8; - --rsc-pill-bg: #edf4ff; - --rsc-subtitle: #1740a8; - --rsc-link-bg: linear-gradient(135deg, #163985, #214aa2); - --rsc-link-border: rgba(15, 47, 121, 0.12); - --rsc-link-text: #ffffff; - --rsc-tag-text: #9c1e6f; - --rsc-tag-bg: #fde8f5; - --rsc-highlight-dot: #c8288d; - --rsc-hero-surface: - radial-gradient(circle at top right, rgba(209, 40, 143, 0.24), transparent 30%), - radial-gradient(circle at bottom left, rgba(101, 79, 240, 0.18), transparent 28%), - linear-gradient(145deg, #07143d 0%, #0e2a70 52%, #0e3b86 100%); - --rsc-hero-border: rgba(11, 25, 76, 0.12); - --rsc-hero-shadow: 0 24px 70px rgba(7, 20, 61, 0.24); - --rsc-hero-eyebrow: rgba(255, 255, 255, 0.72); - --rsc-hero-muted: rgba(247, 251, 255, 0.88); - --rsc-hero-note-text: #fff7df; - --rsc-hero-note-bg: rgba(255, 255, 255, 0.12); - --rsc-hero-note-border: rgba(255, 255, 255, 0.08); - --rsc-secondary-btn-text: #ffffff; - --rsc-secondary-btn-bg: rgba(255, 255, 255, 0.08); - --rsc-secondary-btn-border: rgba(255, 255, 255, 0.24); - --rsc-signal-surface: - radial-gradient(circle at top right, rgba(56, 189, 248, 0.18), transparent 34%), - linear-gradient(180deg, rgba(11, 21, 51, 0.9), rgba(5, 13, 35, 0.96)); - --rsc-signal-border: rgba(160, 183, 255, 0.18); - --rsc-signal-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.06), - 0 20px 40px rgba(4, 10, 28, 0.18); - --rsc-signal-label: rgba(247, 251, 255, 0.84); - --rsc-gridline: rgba(255, 255, 255, 0.045); - --rsc-guide-surface: - radial-gradient(circle at top right, rgba(96, 165, 250, 0.12), transparent 32%), - radial-gradient(circle at bottom left, rgba(209, 40, 143, 0.1), transparent 24%), - linear-gradient(180deg, rgba(249, 252, 255, 0.96), rgba(235, 242, 252, 0.98)); - --rsc-guide-border: rgba(148, 163, 184, 0.22); - --rsc-guide-title: #0f172a; - --rsc-guide-text: #47566f; - --rsc-guide-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.55), - 0 22px 48px rgba(15, 23, 42, 0.08); - --rsc-step-surface: - radial-gradient(circle at top right, rgba(96, 165, 250, 0.06), transparent 24%), - linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(247, 250, 255, 0.99)); - --rsc-step-border: rgba(148, 163, 184, 0.2); - --rsc-step-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.6), - 0 18px 36px rgba(15, 23, 42, 0.06); - --rsc-check-surface: - radial-gradient(circle at top right, rgba(101, 79, 240, 0.16), transparent 28%), - radial-gradient(circle at bottom left, rgba(209, 40, 143, 0.14), transparent 28%), - linear-gradient(180deg, #0f1838, #08122a); - --rsc-check-border: rgba(148, 163, 184, 0.18); - --rsc-check-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.06), - 0 24px 48px rgba(8, 18, 45, 0.14); - --rsc-check-text: #dbe7ff; - --rsc-check-label: #d1288f; -} - -#rabbita-scc-showcase .rsc-page { - position: relative; - isolation: isolate; - width: min(1180px, 100%); - margin: 1.5rem auto 3.5rem; -} - -#rabbita-scc-showcase .rsc-hero { - display: grid; - grid-template-columns: minmax(0, 1.28fr) minmax(320px, 0.92fr); - gap: 1.25rem; - overflow: hidden; - padding: 2rem; - border: 1px solid var(--rsc-hero-border); - border-radius: 32px; - color: #f7fbff; - background: var(--rsc-hero-surface); - box-shadow: var(--rsc-hero-shadow); -} - -#rabbita-scc-showcase .rsc-eyebrow { - margin: 0 0 0.8rem; - color: var(--rsc-hero-eyebrow); - font-size: 0.88rem; - font-weight: 700; - letter-spacing: 0.12em; - text-transform: uppercase; -} - -#rabbita-scc-showcase .rsc-hero-title { - margin: 0; - font-size: clamp(2rem, 4.5vw, 3.45rem); - line-height: 1.06; -} - -#rabbita-scc-showcase .rsc-hero-intro { - max-width: 60ch; - margin: 1rem 0 0; - color: var(--rsc-hero-muted); - font-size: 1.05rem; - line-height: 1.82; -} - -#rabbita-scc-showcase .rsc-hero-note { - display: inline-flex; - flex-wrap: wrap; - max-width: 100%; - margin: 1rem 0 0; - padding: 0.72rem 0.95rem; - border: 1px solid var(--rsc-hero-note-border); - border-radius: 999px; - color: var(--rsc-hero-note-text); - background: var(--rsc-hero-note-bg); - line-height: 1.6; -} - -#rabbita-scc-showcase .rsc-actions { - display: flex; - flex-wrap: wrap; - gap: 0.85rem; - margin-top: 1.35rem; -} - -#rabbita-scc-showcase .rsc-btn { - display: inline-flex; - align-items: center; - justify-content: center; - min-height: 48px; - max-width: 100%; - padding: 0.78rem 1.15rem; - border-radius: 999px; - font-weight: 700; - text-decoration: none; - touch-action: manipulation; - transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease, background 0.2s ease; -} - -#rabbita-scc-showcase .rsc-btn--primary { - color: #fff; - background: linear-gradient(135deg, #d1288f, #b92482); - box-shadow: 0 12px 28px rgba(185, 36, 130, 0.24); -} - -#rabbita-scc-showcase .rsc-btn--secondary { - color: var(--rsc-secondary-btn-text); - border: 1px solid var(--rsc-secondary-btn-border); - background: var(--rsc-secondary-btn-bg); -} - -#rabbita-scc-showcase .rsc-signal-grid { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 0.85rem; -} - -#rabbita-scc-showcase .rsc-signal-card { - position: relative; - overflow: hidden; - min-height: 142px; - padding: 1rem; - border: 1px solid var(--rsc-signal-border); - border-radius: 22px; - background: var(--rsc-signal-surface); - backdrop-filter: blur(12px); - box-shadow: var(--rsc-signal-shadow); -} - -#rabbita-scc-showcase .rsc-signal-card::after { - content: ""; - position: absolute; - inset: 0; - background: - linear-gradient( - 180deg, - transparent 0, - transparent calc(100% - 1px), - var(--rsc-gridline) calc(100% - 1px) - ), - linear-gradient( - 90deg, - transparent 0, - transparent calc(100% - 1px), - var(--rsc-gridline) calc(100% - 1px) - ); - background-size: 100% 28px, 36px 100%; - opacity: 0.38; - pointer-events: none; -} - -#rabbita-scc-showcase .rsc-signal-value { - margin: 0 0 0.75rem; - font-size: 1.15rem; - line-height: 1.35; -} - -#rabbita-scc-showcase .rsc-signal-label { - margin: 0; - color: var(--rsc-signal-label); - line-height: 1.72; -} - -#rabbita-scc-showcase .rsc-section { - margin-top: 2rem; -} - -#rabbita-scc-showcase .rsc-section-head { - margin-bottom: 1rem; -} - -#rabbita-scc-showcase .rsc-section-label { - margin: 0 0 0.45rem; - color: var(--rsc-accent); - font-size: clamp(1.18rem, 2vw, 1.5rem); - font-weight: 700; - letter-spacing: 0.01em; -} - -#rabbita-scc-showcase .rsc-section-title { - margin: 0; - max-width: 54rem; - color: var(--rsc-title-text); - font-size: clamp(1.02rem, 1.65vw, 1.22rem); - font-weight: 600; - line-height: 1.72; -} - -#rabbita-scc-showcase .rsc-section-title--subtle { - font-size: clamp(0.98rem, 1.4vw, 1.08rem); - line-height: 1.68; -} - -#rabbita-scc-showcase .rsc-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); - gap: 1.2rem; -} - -#rabbita-scc-showcase .rsc-card { - position: relative; - overflow: hidden; - border: 1px solid var(--rsc-card-border); - border-radius: 26px; - background: var(--rsc-card-surface); - box-shadow: var(--rsc-card-shadow); - transition: box-shadow 0.2s ease, border-color 0.2s ease, transform 0.2s ease; -} - -#rabbita-scc-showcase .rsc-card-body { - position: relative; - padding: 1.25rem 1.2rem 1.3rem; -} - -#rabbita-scc-showcase .rsc-card-overlay { - display: block; - position: absolute; - inset: 0; - z-index: 1; - border-radius: inherit; - cursor: pointer; - text-decoration: none; -} - -#rabbita-scc-showcase .rsc-sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; -} - -#rabbita-scc-showcase .rsc-card:focus-within { - border-color: rgba(185, 36, 130, 0.28); - box-shadow: - 0 0 0 3px rgba(185, 36, 130, 0.1), - var(--rsc-card-shadow); -} - -#rabbita-scc-showcase .rsc-meta-row { - display: flex; - flex-wrap: wrap; - gap: 0.55rem; - margin-bottom: 0.7rem; -} - -#rabbita-scc-showcase .rsc-meta-pill { - display: inline-flex; - align-items: center; - padding: 0.32rem 0.65rem; - border-radius: 999px; - color: var(--rsc-pill-text); - font-size: 0.82rem; - font-weight: 600; - background: var(--rsc-pill-bg); -} - -#rabbita-scc-showcase .rsc-card-title { - margin: 0; - color: var(--rsc-title-text); - font-size: 1.32rem; - line-height: 1.25; -} - -#rabbita-scc-showcase .rsc-card-subtitle { - margin: 0.58rem 0 0; - color: var(--rsc-subtitle); - font-weight: 600; - line-height: 1.62; -} - -#rabbita-scc-showcase .rsc-card-desc { - margin: 0.78rem 0 0; - color: var(--rsc-muted-text); - line-height: 1.78; -} - -#rabbita-scc-showcase .rsc-highlights { - display: grid; - gap: 0.55rem; - margin-top: 0.95rem; -} - -#rabbita-scc-showcase .rsc-highlight { - position: relative; - padding-left: 1rem; - color: var(--rsc-muted-text); - line-height: 1.68; -} - -#rabbita-scc-showcase .rsc-highlight::before { - content: ""; - position: absolute; - left: 0; - top: 0.68rem; - width: 0.38rem; - height: 0.38rem; - border-radius: 999px; - background: var(--rsc-highlight-dot); -} - -#rabbita-scc-showcase .rsc-tags { - display: flex; - flex-wrap: wrap; - gap: 0.55rem; - margin-top: 0.95rem; -} - -#rabbita-scc-showcase .rsc-tag { - display: inline-flex; - align-items: center; - padding: 0.38rem 0.68rem; - border-radius: 999px; - color: var(--rsc-tag-text); - font-size: 0.82rem; - font-weight: 700; - background: var(--rsc-tag-bg); -} - -#rabbita-scc-showcase .rsc-links { - position: relative; - z-index: 2; - display: flex; - flex-wrap: wrap; - gap: 0.7rem; - margin-top: 1rem; -} - -#rabbita-scc-showcase .rsc-link { - display: inline-flex; - align-items: center; - justify-content: center; - min-height: 40px; - max-width: 100%; - padding: 0.52rem 0.84rem; - border-radius: 999px; - color: var(--rsc-link-text); - font-size: 0.9rem; - font-weight: 600; - text-decoration: none; - border: 1px solid var(--rsc-link-border); - background: var(--rsc-link-bg); - touch-action: manipulation; - transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; -} - -#rabbita-scc-showcase .rsc-steps-grid { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 1rem; -} - -#rabbita-scc-showcase .rsc-step-card { - padding: 1.2rem; - border: 1px solid var(--rsc-step-border); - border-radius: 24px; - background: var(--rsc-step-surface); - box-shadow: var(--rsc-step-shadow); -} - -#rabbita-scc-showcase .rsc-step-title { - margin: 0; - color: var(--rsc-title-text); - font-size: 1.08rem; -} - -#rabbita-scc-showcase .rsc-step-desc { - margin: 0.75rem 0 0; - color: var(--rsc-muted-text); - line-height: 1.76; -} - -#rabbita-scc-showcase .rsc-section:last-of-type { - padding: 1.35rem; - border: 1px solid var(--rsc-guide-border); - border-radius: 32px; - background: var(--rsc-guide-surface); - box-shadow: var(--rsc-guide-shadow); -} - -#rabbita-scc-showcase .rsc-section:last-of-type .rsc-section-head { - margin-bottom: 1.2rem; -} - -#rabbita-scc-showcase .rsc-section:last-of-type .rsc-section-label { - color: var(--rsc-accent); -} - -#rabbita-scc-showcase .rsc-section:last-of-type .rsc-section-title { - color: var(--rsc-guide-title); -} - -#rabbita-scc-showcase .rsc-section:last-of-type .rsc-step-card { - border: 1px solid var(--rsc-step-border); - background: var(--rsc-step-surface); - box-shadow: var(--rsc-step-shadow); -} - -#rabbita-scc-showcase .rsc-section:last-of-type .rsc-step-title { - color: var(--rsc-guide-title); -} - -#rabbita-scc-showcase .rsc-section:last-of-type .rsc-step-desc { - color: var(--rsc-guide-text); -} - -#rabbita-scc-showcase .rsc-check-panel { - display: grid; - gap: 0.55rem; - padding: 1.2rem; - margin-top: 1rem; - border: 1px solid var(--rsc-check-border); - border-radius: 28px; - background: var(--rsc-check-surface); - box-shadow: var(--rsc-check-shadow); -} - -#rabbita-scc-showcase .rsc-check-panel .rsc-section-label { - color: var(--rsc-check-label); -} - -#rabbita-scc-showcase .rsc-check-panel .rsc-check-item { - color: var(--rsc-check-text); -} - -#rabbita-scc-showcase .rsc-check-list { - display: grid; - gap: 0.6rem; - margin-top: 0.45rem; -} - -#rabbita-scc-showcase .rsc-check-item { - position: relative; - padding-left: 1rem; - line-height: 1.72; -} - -#rabbita-scc-showcase .rsc-check-item::before { - content: ""; - position: absolute; - left: 0; - top: 0.68rem; - width: 0.38rem; - height: 0.38rem; - border-radius: 999px; - background: var(--rsc-accent); -} - -@media (hover: hover) and (pointer: fine) { - #rabbita-scc-showcase .rsc-btn:hover, - #rabbita-scc-showcase .rsc-link:hover { - transform: translateY(-1px); - } - - #rabbita-scc-showcase .rsc-btn--primary:hover { - box-shadow: 0 16px 34px rgba(185, 36, 130, 0.3); - } - - #rabbita-scc-showcase .rsc-btn--secondary:hover { - border-color: rgba(255, 255, 255, 0.34); - background: rgba(255, 255, 255, 0.12); - } - - #rabbita-scc-showcase .rsc-card:hover, - #rabbita-scc-showcase .rsc-step-card:hover { - transform: translateY(-2px); - } - - #rabbita-scc-showcase .rsc-link:hover { - box-shadow: 0 12px 26px rgba(15, 47, 121, 0.18); - } -} - -[data-theme="dark"] #rabbita-scc-showcase { - color: var(--rsc-page-text); - --rsc-page-text: #d8e1ef; - --rsc-title-text: #f7f9fd; - --rsc-muted-text: #9aa9be; - --rsc-accent: #e040b0; - --rsc-accent-strong: #f5b5dc; - --rsc-card-surface: - radial-gradient(circle at top right, rgba(68, 116, 214, 0.07), transparent 22%), - linear-gradient(180deg, rgba(18, 23, 34, 0.98), rgba(11, 15, 24, 0.99)); - --rsc-card-border: rgba(118, 133, 164, 0.18); - --rsc-card-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.025), - 0 20px 44px rgba(0, 0, 0, 0.36); - --rsc-pill-text: #dbe5f7; - --rsc-pill-bg: rgba(95, 109, 140, 0.18); - --rsc-subtitle: #d9e3f5; - --rsc-link-bg: linear-gradient(135deg, rgba(31, 43, 66, 0.98), rgba(37, 51, 78, 0.98)); - --rsc-link-border: rgba(120, 135, 170, 0.2); - --rsc-link-text: #eef3fb; - --rsc-tag-text: #f5badf; - --rsc-tag-bg: rgba(185, 36, 130, 0.22); - --rsc-highlight-dot: #e040b0; - --rsc-hero-surface: - radial-gradient(circle at top right, rgba(209, 40, 143, 0.22), transparent 24%), - radial-gradient(circle at bottom left, rgba(101, 79, 240, 0.14), transparent 26%), - linear-gradient(145deg, #090f1b 0%, #10192b 52%, #15233d 100%); - --rsc-hero-border: rgba(126, 141, 173, 0.16); - --rsc-hero-shadow: 0 28px 70px rgba(0, 0, 0, 0.42); - --rsc-hero-eyebrow: rgba(214, 224, 239, 0.68); - --rsc-hero-muted: rgba(232, 238, 247, 0.84); - --rsc-hero-note-text: #f3e2c9; - --rsc-hero-note-bg: rgba(255, 255, 255, 0.04); - --rsc-hero-note-border: rgba(255, 255, 255, 0.07); - --rsc-secondary-btn-text: #edf2fa; - --rsc-secondary-btn-bg: rgba(255, 255, 255, 0.04); - --rsc-secondary-btn-border: rgba(144, 158, 188, 0.16); - --rsc-signal-surface: - radial-gradient(circle at top right, rgba(69, 120, 214, 0.12), transparent 28%), - linear-gradient(180deg, rgba(13, 18, 30, 0.98), rgba(8, 12, 20, 1)); - --rsc-signal-border: rgba(112, 129, 161, 0.18); - --rsc-signal-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.03), - 0 18px 38px rgba(0, 0, 0, 0.34); - --rsc-signal-label: rgba(221, 229, 241, 0.78); - --rsc-gridline: rgba(255, 255, 255, 0.02); - --rsc-guide-surface: - radial-gradient(circle at top right, rgba(209, 40, 143, 0.14), transparent 24%), - linear-gradient(180deg, rgba(14, 19, 30, 0.98), rgba(9, 13, 21, 1)); - --rsc-guide-border: rgba(116, 131, 162, 0.16); - --rsc-guide-title: #f5f8fd; - --rsc-guide-text: #b1bfd2; - --rsc-guide-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.025), - 0 24px 50px rgba(0, 0, 0, 0.34); - --rsc-step-surface: - radial-gradient(circle at top right, rgba(71, 121, 215, 0.05), transparent 22%), - linear-gradient(180deg, rgba(18, 24, 37, 0.98), rgba(12, 17, 27, 0.99)); - --rsc-step-border: rgba(118, 133, 164, 0.18); - --rsc-step-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.02), - 0 16px 30px rgba(0, 0, 0, 0.26); - --rsc-check-surface: - radial-gradient(circle at top right, rgba(209, 40, 143, 0.14), transparent 24%), - radial-gradient(circle at bottom left, rgba(101, 79, 240, 0.1), transparent 24%), - linear-gradient(180deg, rgba(11, 16, 26, 0.99), rgba(7, 10, 18, 1)); - --rsc-check-border: rgba(121, 136, 166, 0.16); - --rsc-check-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.025), - 0 24px 52px rgba(0, 0, 0, 0.38); - --rsc-check-text: #dce5f3; - --rsc-check-label: #f08fcd; -} - -[data-theme="dark"] #rabbita-scc-showcase .rsc-card:hover { - border-color: rgba(150, 164, 193, 0.26); - box-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.03), - 0 24px 52px rgba(0, 0, 0, 0.42); -} - -[data-theme="dark"] #rabbita-scc-showcase .rsc-card:focus-within { - border-color: rgba(224, 64, 176, 0.34); - box-shadow: - 0 0 0 3px rgba(224, 64, 176, 0.14), - inset 0 1px 0 rgba(255, 255, 255, 0.03), - 0 24px 52px rgba(0, 0, 0, 0.42); -} - -[data-theme="dark"] #rabbita-scc-showcase .rsc-btn--primary { - background: linear-gradient(135deg, #e040b0, #b92482); - box-shadow: 0 12px 28px rgba(185, 36, 130, 0.3); -} - -[data-theme="dark"] #rabbita-scc-showcase .rsc-btn--primary:hover { - box-shadow: 0 16px 34px rgba(185, 36, 130, 0.36); -} - -[data-theme="dark"] #rabbita-scc-showcase .rsc-link:hover { - border-color: rgba(154, 168, 198, 0.28); - box-shadow: 0 14px 30px rgba(0, 0, 0, 0.3); -} - -[data-theme="dark"] #rabbita-scc-showcase .rsc-section:last-of-type, -[data-theme="dark"] #rabbita-scc-showcase .rsc-check-panel { - backdrop-filter: blur(14px); -} - -@media (max-width: 996px) { - #rabbita-scc-showcase .rsc-hero, - #rabbita-scc-showcase .rsc-steps-grid { - grid-template-columns: 1fr; - } -} - -@media (max-width: 768px) { - #rabbita-scc-showcase .rsc-page { - margin-top: 1rem; - margin-bottom: calc(2rem + env(safe-area-inset-bottom)); - } - - #rabbita-scc-showcase .rsc-section:last-of-type { - padding: 1rem; - border-radius: 24px; - } - - #rabbita-scc-showcase .rsc-hero { - padding: 1.2rem; - border-radius: 24px; - } - - #rabbita-scc-showcase .rsc-hero-intro { - font-size: 0.98rem; - line-height: 1.72; - } - - #rabbita-scc-showcase .rsc-hero-note { - display: flex; - border-radius: 18px; - } - - #rabbita-scc-showcase .rsc-actions, - #rabbita-scc-showcase .rsc-links { - flex-direction: column; - } - - #rabbita-scc-showcase .rsc-btn, - #rabbita-scc-showcase .rsc-link { - width: 100%; - } - - #rabbita-scc-showcase .rsc-signal-grid, - #rabbita-scc-showcase .rsc-grid { - grid-template-columns: 1fr; - } - - #rabbita-scc-showcase .rsc-card-body, - #rabbita-scc-showcase .rsc-step-card, - #rabbita-scc-showcase .rsc-check-panel { - padding: 1rem; - } -} - -@media (max-width: 480px) { - #rabbita-scc-showcase .rsc-page { - margin-top: 0.75rem; - } - - #rabbita-scc-showcase .rsc-section:last-of-type { - padding: 0.9rem; - border-radius: 20px; - } - - #rabbita-scc-showcase .rsc-hero { - padding: 1rem; - border-radius: 20px; - } - - #rabbita-scc-showcase .rsc-hero-title { - font-size: 1.9rem; - } - - #rabbita-scc-showcase .rsc-signal-grid { - grid-template-columns: 1fr; - } - - #rabbita-scc-showcase .rsc-signal-card { - min-height: auto; - padding: 0.95rem; - } - - #rabbita-scc-showcase .rsc-card-title { - font-size: 1.18rem; - } - - #rabbita-scc-showcase .rsc-section-title, - #rabbita-scc-showcase .rsc-step-desc, - #rabbita-scc-showcase .rsc-card-desc, - #rabbita-scc-showcase .rsc-highlight, - #rabbita-scc-showcase .rsc-check-item { - line-height: 1.62; - } -}