From 91fd6dbae6990cfbec60658d2e2afc3e9de7fe76 Mon Sep 17 00:00:00 2001 From: TheEverests <231477374+TheEverests@users.noreply.github.com> Date: Sun, 7 Jun 2026 02:48:01 +0800 Subject: [PATCH 1/3] fix(site): refresh landing performance and repo stats --- apps/site/.env.example | 4 + apps/site/astro.config.mjs | 1 + apps/site/public/apple-touch-icon.png | Bin 0 -> 16035 bytes .../public/demo-utils/touchai-lite-math.js | 253 ++++ .../demo-utils/touchai-lite-renderer.js | 102 ++ .../touchai-components.html | 302 +++-- .../feature-reminder/touchai-components.html | 302 +++-- .../feature-solver-en/touchai-components.html | 323 +++-- .../feature-solver/touchai-components.html | 321 +++-- .../touchai-components.html | 295 +++-- .../touchai-components.html | 295 +++-- apps/site/public/icon-192.png | Bin 0 -> 17449 bytes apps/site/public/icon-512.png | Bin 0 -> 76433 bytes apps/site/public/robots.txt | 4 + apps/site/public/seo-card.png | Bin 0 -> 121376 bytes apps/site/public/site.webmanifest | 29 + .../touchai-intro-en/touchai-components.html | 282 ++-- .../touchai-intro/touchai-components.html | 280 ++-- apps/site/src/components/ComponentDemo.astro | 161 ++- apps/site/src/content.config.ts | 10 + apps/site/src/content/docs/404.md | 7 + apps/site/src/content/docs/getting-started.md | 29 + apps/site/src/pages/index.astro | 1155 ++++++++++++++--- .../src/scripts/component-demo-runtime.ts | 299 ++++- 24 files changed, 3420 insertions(+), 1034 deletions(-) create mode 100644 apps/site/public/apple-touch-icon.png create mode 100644 apps/site/public/demo-utils/touchai-lite-math.js create mode 100644 apps/site/public/demo-utils/touchai-lite-renderer.js create mode 100644 apps/site/public/icon-192.png create mode 100644 apps/site/public/icon-512.png create mode 100644 apps/site/public/robots.txt create mode 100644 apps/site/public/seo-card.png create mode 100644 apps/site/public/site.webmanifest create mode 100644 apps/site/src/content.config.ts create mode 100644 apps/site/src/content/docs/404.md create mode 100644 apps/site/src/content/docs/getting-started.md diff --git a/apps/site/.env.example b/apps/site/.env.example index 2ad925ae..69a000da 100644 --- a/apps/site/.env.example +++ b/apps/site/.env.example @@ -11,3 +11,7 @@ PUBLIC_CLARITY_ID= # Waitlist subscribe endpoint (Cloudflare Worker URL + /subscribe). # Leave empty to disable form submission gracefully. PUBLIC_WAITLIST_ENDPOINT= + +# Generic analytics collector endpoint that accepts JSON POST payloads. +# Leave empty to disable the built-in pageview and click tracking. +PUBLIC_ANALYTICS_ENDPOINT= diff --git a/apps/site/astro.config.mjs b/apps/site/astro.config.mjs index 0bd4df59..1d9f6c31 100644 --- a/apps/site/astro.config.mjs +++ b/apps/site/astro.config.mjs @@ -10,6 +10,7 @@ export default defineConfig({ react(), starlight({ title: 'TouchAI', + disable404Route: true, social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/TouchAI-org/TouchAI' }], sidebar: [ ], diff --git a/apps/site/public/apple-touch-icon.png b/apps/site/public/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..69e40dd469d68e52f4bb9f464d83d8d35084e731 GIT binary patch literal 16035 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 literal 0 HcmV?d00001 diff --git a/apps/site/public/demo-utils/touchai-lite-math.js b/apps/site/public/demo-utils/touchai-lite-math.js new file mode 100644 index 00000000..10f29755 --- /dev/null +++ b/apps/site/public/demo-utils/touchai-lite-math.js @@ -0,0 +1,253 @@ +(function () { + const renderer = window.TouchAILiteRenderer; + + function escapeHtml(value) { + return renderer ? renderer.escapeHtml(value) : String(value); + } + + function normalizeFormula(source) { + return String(source) + .replace(/\\left/g, '') + .replace(/\\right/g, '') + .replace(/\\,/g, ' ') + .replace(/\\:/g, ' ') + .replace(/\\;/g, ' ') + .replace(/\\quad/g, ' ') + .replace(/\\qquad/g, ' ') + .replace(/\\!/g, ''); + } + + function renderFormula(source, displayMode) { + if (window.katex && typeof window.katex.renderToString === 'function') { + try { + return window.katex.renderToString(String(source), { + displayMode, + throwOnError: false, + strict: 'ignore', + trust: false, + }); + } catch (error) {} + } + + const input = normalizeFormula(source); + let index = 0; + + const commandMap = { + theta: 'θ', + cos: 'cos', + sin: 'sin', + max: 'max', + min: 'min', + in: '∈', + Rightarrow: '⇒', + to: '→', + cdot: '·', + }; + + const readCommandName = () => { + index += 1; + let name = ''; + while (index < input.length && /[A-Za-z]/.test(input[index])) { + name += input[index]; + index += 1; + } + + if (!name && index < input.length) { + name = input[index]; + index += 1; + } + + return name; + }; + + const readRawGroup = () => { + if (input[index] !== '{') { + const start = index; + index += 1; + return input.slice(start, index); + } + + index += 1; + let depth = 1; + let value = ''; + + while (index < input.length && depth > 0) { + const char = input[index]; + index += 1; + + if (char === '{') { + depth += 1; + value += char; + continue; + } + + if (char === '}') { + depth -= 1; + if (depth > 0) value += char; + continue; + } + + value += char; + } + + return value; + }; + + const readArgument = () => { + while (input[index] === ' ') index += 1; + + if (index >= input.length) return ''; + + if (input[index] === '{') { + const raw = readRawGroup(); + return renderFormula(raw, false); + } + + if (input[index] === '\\') { + const command = readCommandName(); + if (command === 'text') { + return `${escapeHtml(readRawGroup())}`; + } + if (command === 'frac') { + const num = readArgument(); + const den = readArgument(); + return `${num}${den}`; + } + if (command === 'sqrt') { + const radicand = readArgument(); + return `${radicand}`; + } + if (command === 'boxed') { + return `${readArgument()}`; + } + + const mapped = commandMap[command] ?? command; + return `${escapeHtml(mapped)}`; + } + + const char = input[index]; + index += 1; + return escapeHtml(char); + }; + + const parse = (stopChar) => { + let html = ''; + + while (index < input.length) { + const char = input[index]; + + if (stopChar && char === stopChar) { + index += 1; + break; + } + + if (char === '{') { + index += 1; + html += parse('}'); + continue; + } + + if (char === '^' || char === '_') { + index += 1; + const tag = char === '^' ? 'sup' : 'sub'; + html += `<${tag}>${readArgument()}`; + continue; + } + + if (char === '\\') { + const command = readCommandName(); + + if (command === 'frac') { + const num = readArgument(); + const den = readArgument(); + html += `${num}${den}`; + continue; + } + + if (command === 'sqrt') { + const radicand = readArgument(); + html += `${radicand}`; + continue; + } + + if (command === 'boxed') { + html += `${readArgument()}`; + continue; + } + + if (command === 'text') { + html += `${escapeHtml(readRawGroup())}`; + continue; + } + + if ( + command === ',' || + command === ':' || + command === ';' || + command === 'quad' || + command === 'qquad' + ) { + html += ' '; + continue; + } + + const mapped = commandMap[command] ?? command; + const className = /^[A-Za-z]+$/.test(mapped) ? 'op' : 'punct'; + html += `${escapeHtml(mapped)}`; + continue; + } + + html += escapeHtml(char); + index += 1; + } + + return html; + }; + + const inner = parse(); + const className = displayMode + ? 'formula-module' + : 'formula-module inline-formula'; + + return `${inner}`; + } + + function renderMarkdownWithMath(markdown) { + const mathTokens = []; + const protectedMarkdown = String(markdown) + .replace(/\$\$([\s\S]+?)\$\$/g, (_, formula) => { + const token = `@@MATH_BLOCK_${mathTokens.length}@@`; + mathTokens.push({ token, formula: formula.trim(), display: true }); + return `\n\n${token}\n\n`; + }) + .replace(/\$([^$\n]+?)\$/g, (_, formula) => { + const token = `@@MATH_INLINE_${mathTokens.length}@@`; + mathTokens.push({ token, formula: formula.trim(), display: false }); + return token; + }); + + let html = renderer + ? renderer.renderMarkdownContent(protectedMarkdown) + : escapeHtml(protectedMarkdown); + + mathTokens.forEach(({ token, formula, display }) => { + const rendered = renderFormula(formula, display); + const replacement = display + ? `
${rendered}
` + : `${rendered}`; + html = html + .replace( + new RegExp(`

${token}

`, 'g'), + replacement + ) + .replace(new RegExp(token, 'g'), replacement); + }); + + return html; + } + + window.TouchAILiteMathRenderer = { + renderFormula, + renderMarkdownWithMath, + }; +})(); diff --git a/apps/site/public/demo-utils/touchai-lite-renderer.js b/apps/site/public/demo-utils/touchai-lite-renderer.js new file mode 100644 index 00000000..659cc5e2 --- /dev/null +++ b/apps/site/public/demo-utils/touchai-lite-renderer.js @@ -0,0 +1,102 @@ +(function () { + function escapeHtml(value) { + return String(value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); + } + + function stripImageMarkdown(value) { + return String(value) + .replace(/\[!\[[^\]]*\]\([^)]*\)\]\([^)]*\)/g, '') + .replace(/!\[[^\]]*\]\([^)]*\)/g, ''); + } + + function renderInline(source) { + const segments = stripImageMarkdown(source).split(/(`[^`]+`)/g); + + return segments + .map((segment) => { + if (!segment) return ''; + if (segment.startsWith('`') && segment.endsWith('`')) { + return `${escapeHtml(segment.slice(1, -1))}`; + } + + return escapeHtml(segment).replace( + /\*\*([^*]+)\*\*/g, + '$1' + ); + }) + .join(''); + } + + function renderMarkdownContent(markdown) { + const lines = String(markdown).split(/\r?\n/); + const html = []; + let paragraphLines = []; + let listItems = []; + + const flushParagraph = () => { + if (!paragraphLines.length) return; + html.push( + `

${paragraphLines.map(renderInline).join('
')}

` + ); + paragraphLines = []; + }; + + const flushList = () => { + if (!listItems.length) return; + html.push( + `
    ${listItems + .map((item) => `
  • ${renderInline(item)}
  • `) + .join('')}
` + ); + listItems = []; + }; + + lines.forEach((line) => { + const trimmed = stripImageMarkdown(line).trim(); + + if (!trimmed) { + flushParagraph(); + flushList(); + return; + } + + if (trimmed === '---') { + flushParagraph(); + flushList(); + html.push(``); + return; + } + + if (trimmed.startsWith('## ')) { + flushParagraph(); + flushList(); + html.push(`

${renderInline(trimmed.slice(3))}

`); + return; + } + + if (trimmed.startsWith('- ')) { + flushParagraph(); + listItems.push(trimmed.slice(2)); + return; + } + + flushList(); + paragraphLines.push(trimmed); + }); + + flushParagraph(); + flushList(); + + return html.join('\n'); + } + + window.TouchAILiteRenderer = { + escapeHtml, + renderInline, + renderMarkdownContent, + }; +})(); diff --git a/apps/site/public/feature-reminder-en/touchai-components.html b/apps/site/public/feature-reminder-en/touchai-components.html index 6458f3bf..3c851613 100644 --- a/apps/site/public/feature-reminder-en/touchai-components.html +++ b/apps/site/public/feature-reminder-en/touchai-components.html @@ -83,6 +83,10 @@ margin-bottom 640ms cubic-bezier(0.22, 1, 0.36, 1); } + body.is-scroll-driven .chat-panel { + will-change: auto; + } + body.is-idle .chat-panel { max-height: 56px; min-height: 56px; @@ -148,20 +152,20 @@ flex: 1 1 auto; min-height: 0; overflow-y: auto; + overscroll-behavior: contain; + -webkit-overflow-scrolling: touch; scrollbar-width: none; padding-top: 0; padding-bottom: 20px; } - body.is-answering .conversation-content { - flex: 0 0 auto; - overflow: visible; - padding-bottom: 0; - } - + body.is-answering .conversation-content, body.is-answering.is-scrolling .conversation-content { flex: 1 1 auto; + min-height: 0; overflow-y: auto; + overscroll-behavior: contain; + -webkit-overflow-scrolling: touch; padding-top: 0; padding-bottom: 20px; } @@ -463,6 +467,16 @@ flex: 0 0 auto; } + body.is-complete .conversation-content, + body.is-complete.is-scrolling .conversation-content { + flex: 1 1 auto; + min-height: 0; + overflow-y: auto; + overscroll-behavior: contain; + -webkit-overflow-scrolling: touch; + padding-bottom: 20px; + } + body.is-answering .composer { margin-top: 0; } @@ -471,6 +485,35 @@ margin-top: auto; } + body.is-complete .composer { + margin-top: 0; + } + + body.is-complete.is-scrolling .composer { + margin-top: auto; + } + + body.is-scroll-driven.is-complete .chat-panel { + min-height: var(--window-min-height); + max-height: var(--window-min-height); + height: var(--window-min-height); + } + + body.is-scroll-driven.is-answering .conversation-content, + body.is-scroll-driven.is-complete .conversation-content { + flex: 1 1 auto; + min-height: 0; + overflow-y: auto; + overscroll-behavior: contain; + -webkit-overflow-scrolling: touch; + padding-bottom: 20px; + } + + body.is-scroll-driven.is-answering .composer, + body.is-scroll-driven.is-complete .composer { + margin-top: auto; + } + .response > p, .response > ul, .response > .math-block, @@ -714,6 +757,7 @@ } body.is-answering .response p:not(.is-visible), + body.is-answering .response h2:not(.is-visible), body.is-answering .response li:not(.is-visible), body.is-answering .response ul:not(.is-visible), body.is-answering .response .tool-call-list:not(.is-visible), @@ -1150,7 +1194,7 @@ -
+
-
+
-
+

Here is the short solution:

设过 @@ -1545,7 +1588,7 @@