refactor: перенести сборку в проекты
- перенесены каноны и VitePress-конфиги в projects/<slug> - добавлены корневой и проектные build.ts для сборки артефактов - добавлены shared-библиотеки сборки в projects/_shared/lib - обновлены CI, Dockerfile, package.json, gitignore и README - удалена сборка frontend-агента
This commit is contained in:
@@ -20,22 +20,7 @@ jobs:
|
||||
- name: Установка зависимостей
|
||||
run: npm ci
|
||||
|
||||
- name: Сборка документации SLM Design
|
||||
run: npm run docs:build:slm-design
|
||||
|
||||
- name: Сборка документации NextJS Style Guide
|
||||
run: npm run docs:build:nextjs-style-guide
|
||||
|
||||
- name: Сборка документации Figma Adaptive Standards
|
||||
run: npm run docs:build:figma-adaptive-standards
|
||||
|
||||
- name: Генерация корневых артефактов
|
||||
run: npm run site:generate
|
||||
|
||||
- name: Сборка агентов
|
||||
run: npm run agents:build
|
||||
|
||||
- name: Сборка лендинга
|
||||
- name: Сборка артефактов проекта
|
||||
run: npm run build
|
||||
|
||||
docker:
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -13,14 +13,13 @@ dist-ssr
|
||||
*.local
|
||||
|
||||
# Generated docs
|
||||
docs/*/content/
|
||||
docs/*/.vitepress/cache/
|
||||
projects/*/docs/content/
|
||||
projects/*/docs/.vitepress/cache/
|
||||
public/llms.txt
|
||||
public/slm-design/
|
||||
public/nextjs-style-guide/
|
||||
public/figma-adaptive-standards/
|
||||
public/template-sync-strategy/
|
||||
public/agents/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
|
||||
@@ -6,7 +6,7 @@ COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
COPY . .
|
||||
RUN npm run docs:build:slm-design && npm run docs:build:nextjs-style-guide && npm run docs:build:figma-adaptive-standards && npm run docs:build:template-sync-strategy && npm run agents:build && npm run build
|
||||
RUN npm run build
|
||||
|
||||
FROM caddy:2-alpine
|
||||
|
||||
|
||||
60
README.md
60
README.md
@@ -13,6 +13,7 @@
|
||||
- VitePress-сборка для `Template Sync Strategy`.
|
||||
- Корневой `llms.txt` как карта всех документаций.
|
||||
- Собственные `llms.txt` и `llms-full.txt` внутри каждой документации.
|
||||
- ZIP-архивы Markdown-контента для каждой документации.
|
||||
- Docker/Caddy-конфигурация для публикации статической сборки.
|
||||
- Gitea CI/CD для ветки `master`.
|
||||
|
||||
@@ -27,15 +28,16 @@
|
||||
## Структура
|
||||
|
||||
```text
|
||||
canons/ исходные материалы и черновики
|
||||
docs/slm-design/ VitePress-сайт SLM Design
|
||||
docs/nextjs-style-guide/ VitePress-сайт NextJS Style Guide
|
||||
docs/figma-adaptive-standards/ VitePress-сайт Figma Adaptive Standards
|
||||
docs/template-sync-strategy/ VitePress-сайт Template Sync Strategy
|
||||
scripts/docs/ подготовка контента для документаций
|
||||
scripts/site/ генерация корневых артефактов сайта
|
||||
build.ts сборка всего репозитория
|
||||
projects/<slug>/build.ts сборка конкретного проекта
|
||||
projects/<slug>/canons/ исходные Markdown-материалы проекта
|
||||
projects/<slug>/docs/ VitePress-конфигурация проекта
|
||||
projects/<slug>/scripts/ уникальные вспомогательные скрипты проекта
|
||||
projects/_shared/lib/ общие библиотечные функции сборки
|
||||
projects/_shared/docs/ общая VitePress-тема
|
||||
src/ React-лендинг
|
||||
public/ статические файлы и сгенерированные документации
|
||||
dist/ итоговая статическая сборка
|
||||
```
|
||||
|
||||
## Команды
|
||||
@@ -46,25 +48,39 @@ npm run dev
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run docs:build:slm-design
|
||||
npm run docs:build:nextjs-style-guide
|
||||
npm run docs:build:figma-adaptive-standards
|
||||
npm run docs:build:template-sync-strategy
|
||||
npm run site:generate
|
||||
npm run build
|
||||
```
|
||||
|
||||
Основные скрипты:
|
||||
|
||||
- `npm run dev` — запускает Vite dev server.
|
||||
- `npm run docs:build:slm-design` — подготавливает и собирает VitePress-документацию SLM Design.
|
||||
- `npm run docs:build:nextjs-style-guide` — подготавливает и собирает VitePress-документацию NextJS Style Guide.
|
||||
- `npm run docs:build:figma-adaptive-standards` — подготавливает и собирает VitePress-документацию Figma Adaptive Standards.
|
||||
- `npm run docs:build:template-sync-strategy` — подготавливает и собирает VitePress-документацию Template Sync Strategy.
|
||||
- `npm run site:generate` — генерирует корневой `public/llms.txt` из `src/config/docs.config.ts` и хардкод-секций.
|
||||
- `npm run build` — генерирует корневые артефакты и собирает лендинг.
|
||||
- `npm run build` — одной командой собирает проектные документации, ZIP-архивы, корневой `llms.txt`, агентов и лендинг.
|
||||
- `npm run build:slm-design` — собирает только проект `SLM Design`.
|
||||
- `npm run build:nextjs-style-guide` — собирает только проект `NextJS Style Guide`.
|
||||
- `npm run build:figma-adaptive-standards` — собирает только проект `Figma Adaptive Standards`.
|
||||
- `npm run build:template-sync-strategy` — собирает только проект `Template Sync Strategy`.
|
||||
- `npm run app:build` — собирает React/Vite-лендинг без проектных артефактов.
|
||||
- `npm run lint` — запускает ESLint.
|
||||
|
||||
## Проекты
|
||||
|
||||
Каждая документация живёт в собственной папке `projects/<slug>` и сама владеет исходниками, конфигами и сборкой.
|
||||
|
||||
```text
|
||||
projects/slm-design/
|
||||
build.ts
|
||||
project.config.ts
|
||||
canons/
|
||||
docs/
|
||||
docs.config.ts
|
||||
.vitepress/
|
||||
scripts/
|
||||
```
|
||||
|
||||
Общая команда `npm run build` запускает корневой `build.ts`. Он последовательно вызывает `projects/<slug>/build.ts`, затем собирает общие артефакты репозитория.
|
||||
|
||||
Если скрипт является библиотечной функцией сборки, он лежит в `projects/_shared/lib`. Если скрипт уникален для проекта, он лежит в `projects/<slug>/scripts`.
|
||||
|
||||
## LLM-артефакты
|
||||
|
||||
Корневой файл:
|
||||
@@ -86,6 +102,10 @@ npm run build
|
||||
/figma-adaptive-standards/llms-full.txt
|
||||
/template-sync-strategy/llms.txt
|
||||
/template-sync-strategy/llms-full.txt
|
||||
/slm-design/slm-design.zip
|
||||
/nextjs-style-guide/nextjs-style-guide.zip
|
||||
/figma-adaptive-standards/figma-adaptive-standards.zip
|
||||
/template-sync-strategy/template-sync-strategy.zip
|
||||
```
|
||||
|
||||
Корневой `llms-full.txt` намеренно не создаётся. Полные bundles остаются внутри конкретных документаций.
|
||||
@@ -114,10 +134,6 @@ docker build -t all-docs:test .
|
||||
Docker-сборка выполняет:
|
||||
|
||||
```bash
|
||||
npm run docs:build:slm-design
|
||||
npm run docs:build:nextjs-style-guide
|
||||
npm run docs:build:figma-adaptive-standards
|
||||
npm run docs:build:template-sync-strategy
|
||||
npm run build
|
||||
```
|
||||
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
# Frontend Architect
|
||||
|
||||
## Роль
|
||||
|
||||
Ты frontend-архитектор проекта. К тебе обращаются, когда нужно понять, как правильно спроектировать frontend-часть задачи: где создать код, какие модули затронуть, как разделить ответственность, как связать части приложения и не сломать архитектурные границы.
|
||||
|
||||
В этом проекте архитектурным стандартом является SLM Design. Используй его как рабочую модель для всех решений: слой, модуль, сегмент, публичный API, направление зависимостей, business factory и композиция.
|
||||
|
||||
## Граница ответственности
|
||||
|
||||
- По умолчанию не пиши production-код.
|
||||
- Не реализуй фичи как frontend-разработчик без явного запроса пользователя.
|
||||
- Проектируй реализацию задачи: какие слои, модули, сегменты, public API и factory нужны.
|
||||
- Точно указывай, где создавать или изменять файлы: слой, модуль, сегмент, назначение файла.
|
||||
- Объясняй, почему код должен жить именно там, а не в другом месте.
|
||||
- Проводь архитектурное ревью существующего или предлагаемого кода.
|
||||
- Переходи к правкам кода только если пользователь явно попросил внести изменения.
|
||||
|
||||
## Архитектурная основа
|
||||
|
||||
Единственная архитектура проекта — SLM Design. Все frontend-решения принимай только в терминах SLM: слой, модуль, сегмент, публичный API, направление зависимостей, business factory.
|
||||
|
||||
Не вводи альтернативные архитектурные модели и не объясняй решения через них.
|
||||
|
||||
## Рабочий процесс
|
||||
|
||||
1. Пойми пользовательскую задачу как frontend-изменение: экран, фича, домен, UI-блок, сервис, состояние, данные или инфраструктура.
|
||||
2. Найди существующую структуру проекта, если решение зависит от текущего кода.
|
||||
3. Определи слой SLM, где должна жить основная ответственность.
|
||||
4. Определи модуль или модули, которые нужно создать или изменить.
|
||||
5. Определи сегменты и конкретные файлы внутри модулей.
|
||||
6. Определи публичные API, допустимые импорты и runtime-зависимости.
|
||||
7. Если решение спорное, открой relevant reference и принимай решение по нему.
|
||||
8. Сформулируй итог: как реализовать задачу по SLM, куда что положить, какие границы не нарушать.
|
||||
9. Если пользователь попросил код, сначала зафиксируй архитектурное решение, потом выполняй минимальные правки.
|
||||
|
||||
## Инварианты SLM
|
||||
|
||||
- Импорты между модулями идут только через публичный API.
|
||||
- Deep imports во внутренние сегменты чужого модуля запрещены.
|
||||
- Зависимости идут по направлению SLM-слоёв.
|
||||
- Runtime-связи между business-доменами идут через factory.
|
||||
- `import type` не считается runtime-зависимостью.
|
||||
- Доменные типы не выносятся в `shared`.
|
||||
- `shared` не знает о продукте и доменах.
|
||||
- `ui` не содержит бизнес-логику, сценарную логику и обращения к API.
|
||||
|
||||
## Архитектурные развилки
|
||||
|
||||
При спорных решениях не пересказывай правила из памяти. Открой нужный reference и прими решение по нему.
|
||||
|
||||
- Слой и направление зависимостей → `references/slm-layers.md`.
|
||||
- Модуль, компонент, публичный API, factory → `references/slm-modules.md`.
|
||||
- Размещение файлов внутри модуля → `references/slm-segments.md`.
|
||||
- Monorepo и `packages/*` → `references/slm-monorepo.md`.
|
||||
- Business factory → `references/slm-react-factory.md`.
|
||||
- Композиция business factories → `references/slm-react-factory-composition.md`.
|
||||
- Композиция через Provider → `references/slm-react-composition-provider.md`.
|
||||
|
||||
## Что проектировать
|
||||
|
||||
- Новый экран: определить `screens/{name}`, локальные `parts/`, нужные business/widget/ui зависимости.
|
||||
- Новый UI-блок: решить, это локальный `parts/`, `widgets`, `business/{domain}/parts` или `ui`.
|
||||
- Новая фича: определить доменную принадлежность, business-модуль, factory API и точку композиции.
|
||||
- Новый business-домен: определить factory, types, hooks/services/mappers/ui и public API.
|
||||
- Новый сервис: определить, это `infra` или локальная часть модуля.
|
||||
- Общая утилита: проверить, действительно ли это `shared`, а не локальный `lib/` модуля.
|
||||
- Monorepo-вынос: проверить, допустим ли `packages/ui`, `packages/infra` или `packages/shared`.
|
||||
|
||||
## Формат ответа
|
||||
|
||||
Если пользователь просит архитектурное решение, отвечай коротко:
|
||||
|
||||
```text
|
||||
Решение: ...
|
||||
Почему: ...
|
||||
Куда: ...
|
||||
Что создать/изменить: ...
|
||||
Зависимости: ...
|
||||
Ограничения: ...
|
||||
Reference: ...
|
||||
```
|
||||
|
||||
Если пользователь просит ревью, сначала перечисли нарушения и риски, затем предложи SLM-совместимое исправление.
|
||||
|
||||
## Поведение при конфликте
|
||||
|
||||
Если запрос пользователя требует нарушить SLM, не делай это молча. Коротко объясни конфликт и предложи SLM-совместимый вариант. Если правил недостаточно для решения, задай один уточняющий вопрос.
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "frontend-architect",
|
||||
"title": "Frontend Architect",
|
||||
"version": "0.1.0",
|
||||
"description": "Frontend-архитектор для работы по SLM Design.",
|
||||
"entry": "AGENT.md",
|
||||
"references": [
|
||||
"references/slm-overview.md",
|
||||
"references/slm-layers.md",
|
||||
"references/slm-modules.md",
|
||||
"references/slm-segments.md",
|
||||
"references/slm-monorepo.md",
|
||||
"references/slm-react-factory.md",
|
||||
"references/slm-react-factory-composition.md",
|
||||
"references/slm-react-composition-provider.md"
|
||||
]
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"references": [
|
||||
{
|
||||
"source": "canons/slm-design/architecture/index.md",
|
||||
"target": "references/slm-overview.md"
|
||||
},
|
||||
{
|
||||
"source": "canons/slm-design/architecture/layers.md",
|
||||
"target": "references/slm-layers.md"
|
||||
},
|
||||
{
|
||||
"source": "canons/slm-design/architecture/modules.md",
|
||||
"target": "references/slm-modules.md"
|
||||
},
|
||||
{
|
||||
"source": "canons/slm-design/architecture/segments.md",
|
||||
"target": "references/slm-segments.md"
|
||||
},
|
||||
{
|
||||
"source": "canons/slm-design/architecture/monorepo.md",
|
||||
"target": "references/slm-monorepo.md"
|
||||
},
|
||||
{
|
||||
"source": "canons/slm-design/examples/react/factory.md",
|
||||
"target": "references/slm-react-factory.md"
|
||||
},
|
||||
{
|
||||
"source": "canons/slm-design/examples/react/factory-composition.md",
|
||||
"target": "references/slm-react-factory-composition.md"
|
||||
},
|
||||
{
|
||||
"source": "canons/slm-design/examples/react/composition-provider.md",
|
||||
"target": "references/slm-react-composition-provider.md"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
build.ts
Normal file
9
build.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { generateRootLlms } from './projects/_shared/lib/root-llms';
|
||||
import { run } from './projects/_shared/lib/run';
|
||||
|
||||
run('npm', ['run', 'build:slm-design']);
|
||||
run('npm', ['run', 'build:nextjs-style-guide']);
|
||||
run('npm', ['run', 'build:figma-adaptive-standards']);
|
||||
run('npm', ['run', 'build:template-sync-strategy']);
|
||||
generateRootLlms();
|
||||
run('npm', ['run', 'app:build']);
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from '../../../shared/vitepress/theme';
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from '../../../shared/vitepress/theme';
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from '../../../shared/vitepress/theme';
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from '../../../shared/vitepress/theme';
|
||||
@@ -8,8 +8,8 @@ import { defineConfig, globalIgnores } from 'eslint/config'
|
||||
export default defineConfig([
|
||||
globalIgnores([
|
||||
'dist',
|
||||
'docs/*/content',
|
||||
'docs/*/.vitepress/cache',
|
||||
'projects/*/docs/content',
|
||||
'projects/*/docs/.vitepress/cache',
|
||||
'public',
|
||||
]),
|
||||
{
|
||||
|
||||
18
package.json
18
package.json
@@ -5,18 +5,12 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "npm run site:generate && tsc -b && vite build",
|
||||
"docs:prepare:slm-design": "tsx scripts/docs/prepare.ts slm-design",
|
||||
"docs:build:slm-design": "npm run docs:prepare:slm-design && vitepress build docs/slm-design",
|
||||
"docs:prepare:nextjs-style-guide": "tsx scripts/docs/prepare.ts nextjs-style-guide",
|
||||
"docs:build:nextjs-style-guide": "npm run docs:prepare:nextjs-style-guide && vitepress build docs/nextjs-style-guide",
|
||||
"docs:prepare:figma-adaptive-standards": "tsx scripts/docs/prepare.ts figma-adaptive-standards",
|
||||
"docs:build:figma-adaptive-standards": "npm run docs:prepare:figma-adaptive-standards && vitepress build docs/figma-adaptive-standards",
|
||||
"docs:prepare:template-sync-strategy": "tsx scripts/docs/prepare.ts template-sync-strategy",
|
||||
"docs:build:template-sync-strategy": "npm run docs:prepare:template-sync-strategy && vitepress build docs/template-sync-strategy",
|
||||
"site:generate": "tsx scripts/site/generate-artifacts.ts",
|
||||
"agent:build:frontend-architect": "tsx agents/frontend-architect/scripts/build.ts",
|
||||
"agents:build": "npm run agent:build:frontend-architect",
|
||||
"build": "tsx build.ts",
|
||||
"app:build": "tsc -b && vite build",
|
||||
"build:slm-design": "tsx projects/slm-design/build.ts",
|
||||
"build:nextjs-style-guide": "tsx projects/nextjs-style-guide/build.ts",
|
||||
"build:figma-adaptive-standards": "tsx projects/figma-adaptive-standards/build.ts",
|
||||
"build:template-sync-strategy": "tsx projects/template-sync-strategy/build.ts",
|
||||
"lint": "eslint .",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
|
||||
112
projects/_shared/lib/prepare-docs.ts
Normal file
112
projects/_shared/lib/prepare-docs.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
type Page = {
|
||||
source: string;
|
||||
target: string;
|
||||
};
|
||||
|
||||
type RouteRewrite = {
|
||||
from: string;
|
||||
to: string;
|
||||
};
|
||||
|
||||
type DocsConfig = {
|
||||
mounts: Page[];
|
||||
routeRewrites?: RouteRewrite[];
|
||||
};
|
||||
|
||||
type ProjectConfig = {
|
||||
slug: string;
|
||||
docsDir: string;
|
||||
};
|
||||
|
||||
const MD_LINK_RE = /\]\((?!#|[a-z][a-z0-9+.-]*:|\/\/)([^)\s]+)(#[^)]*)?\)/gi;
|
||||
|
||||
function normalizePath(value: string) {
|
||||
return value.split(path.sep).join('/').replace(/^\.\//, '');
|
||||
}
|
||||
|
||||
function formatRelativeMarkdownPath(fromTarget: string, toTarget: string) {
|
||||
const relative = path.relative(path.dirname(fromTarget), toTarget).split(path.sep).join('/');
|
||||
return relative.startsWith('.') ? relative : `./${relative}`;
|
||||
}
|
||||
|
||||
async function loadDocsConfig(configPath: string) {
|
||||
return (await import(`${pathToFileURL(configPath).href}?t=${Date.now()}`)) as DocsConfig;
|
||||
}
|
||||
|
||||
export async function prepareDocs(projectDir: string, config: ProjectConfig) {
|
||||
const docsDir = path.join(projectDir, config.docsDir);
|
||||
const contentDir = path.join(docsDir, 'content');
|
||||
const docsConfig = await loadDocsConfig(path.join(docsDir, 'docs.config.ts'));
|
||||
const targetBySource = new Map(
|
||||
docsConfig.mounts.map((page) => [normalizePath(path.resolve(projectDir, page.source)), normalizePath(page.target)]),
|
||||
);
|
||||
const routeRewrites = [...(docsConfig.routeRewrites ?? [])].sort((a, b) => b.from.length - a.from.length);
|
||||
|
||||
function applyRouteRewrites(route: string) {
|
||||
for (const rewrite of routeRewrites) {
|
||||
if (route === rewrite.from || route.startsWith(`${rewrite.from}/`) || route.startsWith(`${rewrite.from}#`)) {
|
||||
return `${rewrite.to}${route.slice(rewrite.from.length)}`;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function formatDocsRoute(route: string) {
|
||||
const rewritten = applyRouteRewrites(route);
|
||||
if (rewritten) return rewritten;
|
||||
if (route === '/docs') return '/';
|
||||
if (route.startsWith('/docs/')) return route.slice('/docs'.length);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function formatRelativeRoute(hrefPath: string, sourceDir: string) {
|
||||
const sourcePath = normalizePath(path.relative(projectDir, path.resolve(sourceDir, hrefPath)));
|
||||
if (sourcePath.startsWith('canons/')) return formatDocsRoute(`/docs/${sourcePath.slice('canons/'.length)}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function transformMarkdownLinks(content: string, page: Page) {
|
||||
const sourceDir = path.dirname(path.resolve(projectDir, page.source));
|
||||
|
||||
return content.replace(MD_LINK_RE, (match, href: string, hash = '') => {
|
||||
const [hrefPath, query = ''] = href.split('?');
|
||||
const queryPart = query ? `?${query}` : '';
|
||||
|
||||
if (hrefPath.startsWith('/')) {
|
||||
const route = formatDocsRoute(hrefPath) ?? applyRouteRewrites(hrefPath);
|
||||
return route ? `](${route}${queryPart}${hash})` : match;
|
||||
}
|
||||
|
||||
if (!hrefPath.endsWith('.md')) {
|
||||
const route = formatRelativeRoute(hrefPath, sourceDir);
|
||||
return route ? `](${route}${queryPart}${hash})` : match;
|
||||
}
|
||||
|
||||
const target = targetBySource.get(normalizePath(path.resolve(sourceDir, hrefPath)));
|
||||
if (!target) return match;
|
||||
|
||||
return `](${formatRelativeMarkdownPath(page.target, `${target}${queryPart}`)}${hash})`;
|
||||
});
|
||||
}
|
||||
|
||||
fs.rmSync(contentDir, { recursive: true, force: true });
|
||||
fs.mkdirSync(contentDir, { recursive: true });
|
||||
|
||||
for (const page of docsConfig.mounts) {
|
||||
const sourcePath = path.resolve(projectDir, page.source);
|
||||
const targetPath = path.join(contentDir, page.target);
|
||||
|
||||
if (!fs.existsSync(sourcePath)) throw new Error(`Не найден канон: ${sourcePath}`);
|
||||
|
||||
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
||||
fs.writeFileSync(targetPath, transformMarkdownLinks(fs.readFileSync(sourcePath, 'utf8'), page), 'utf8');
|
||||
console.log(`${page.target} -> ${path.relative(projectDir, sourcePath)}`);
|
||||
}
|
||||
|
||||
console.log(`Подготовлен VitePress content для ${config.slug}: ${docsConfig.mounts.length} страниц`);
|
||||
}
|
||||
51
projects/_shared/lib/root-llms.ts
Normal file
51
projects/_shared/lib/root-llms.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import { docs } from '../../../src/config/docs.config';
|
||||
|
||||
const siteTitle = 'Документация';
|
||||
const siteDescription = 'Единое пространство для идей, черновиков и первых версий документаций, которые ещё формируются и постепенно становятся самостоятельными материалами.';
|
||||
|
||||
function formatMarkdownLink(label: string, href: string, description: string) {
|
||||
return `- [${label}](${href}): ${description}`;
|
||||
}
|
||||
|
||||
function findDocLink(doc: (typeof docs)[number], label: string) {
|
||||
return doc.links.find((link) => link.label === label);
|
||||
}
|
||||
|
||||
export function generateRootLlms(rootDir = process.cwd()) {
|
||||
const publicDir = path.join(rootDir, 'public');
|
||||
const llmsPath = path.join(publicDir, 'llms.txt');
|
||||
const content = [
|
||||
`# ${siteTitle}`,
|
||||
'',
|
||||
`> ${siteDescription}`,
|
||||
'',
|
||||
'Этот файл является корневой картой документаций. Для работы с конкретным направлением используйте его собственный `llms.txt`.',
|
||||
'',
|
||||
'## Documentation',
|
||||
'',
|
||||
...docs
|
||||
.map((doc) => {
|
||||
const link = findDocLink(doc, 'llms.txt');
|
||||
return link ? formatMarkdownLink(doc.title, link.href, doc.description) : undefined;
|
||||
})
|
||||
.filter(Boolean),
|
||||
'',
|
||||
'## Optional',
|
||||
'',
|
||||
...docs
|
||||
.map((doc) => {
|
||||
const link = findDocLink(doc, 'llms-full.txt');
|
||||
return link ? formatMarkdownLink(`${doc.title} full`, link.href, `Полный bundle документации: ${doc.label.toLowerCase()}.`) : undefined;
|
||||
})
|
||||
.filter(Boolean),
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
fs.mkdirSync(publicDir, { recursive: true });
|
||||
fs.writeFileSync(llmsPath, content, 'utf8');
|
||||
|
||||
console.log(`Сгенерирован ${path.relative(rootDir, llmsPath)}`);
|
||||
}
|
||||
12
projects/_shared/lib/run.ts
Normal file
12
projects/_shared/lib/run.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { spawnSync } from 'node:child_process';
|
||||
|
||||
export function run(command: string, args: string[], cwd = process.cwd()) {
|
||||
const result = spawnSync(command, args, {
|
||||
cwd,
|
||||
stdio: 'inherit',
|
||||
shell: process.platform === 'win32',
|
||||
});
|
||||
|
||||
if (result.error) throw result.error;
|
||||
if (result.status !== 0) throw new Error(`Command failed: ${[command, ...args].join(' ')}`);
|
||||
}
|
||||
@@ -1,53 +1,24 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
type ReferenceConfig = {
|
||||
references: Array<{
|
||||
source: string;
|
||||
target: string;
|
||||
}>;
|
||||
};
|
||||
|
||||
type ZipEntry = {
|
||||
name: string;
|
||||
content: Buffer;
|
||||
};
|
||||
|
||||
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const agentDir = path.resolve(scriptDir, '..');
|
||||
const rootDir = path.resolve(agentDir, '../..');
|
||||
const sourceDir = path.join(agentDir, 'source');
|
||||
const tempDir = path.join(agentDir, '.tmp');
|
||||
const packageName = 'frontend-architect';
|
||||
const packageDir = path.join(tempDir, packageName);
|
||||
const publicAgentsDir = path.join(rootDir, 'public', 'agents');
|
||||
const zipPath = path.join(publicAgentsDir, `${packageName}.zip`);
|
||||
|
||||
function readJson<T>(filePath: string): T {
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T;
|
||||
}
|
||||
|
||||
function copyFile(sourcePath: string, targetPath: string) {
|
||||
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
||||
fs.copyFileSync(sourcePath, targetPath);
|
||||
}
|
||||
|
||||
function collectFiles(dir: string, baseDir = dir): ZipEntry[] {
|
||||
function collectFiles(dir: string, baseDir = dir, archiveRoot = path.basename(dir)): ZipEntry[] {
|
||||
return fs
|
||||
.readdirSync(dir, { withFileTypes: true })
|
||||
.flatMap((entry) => {
|
||||
const entryPath = path.join(dir, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
return collectFiles(entryPath, baseDir);
|
||||
}
|
||||
if (entry.isDirectory()) return collectFiles(entryPath, baseDir, archiveRoot);
|
||||
|
||||
const relativePath = path.relative(baseDir, entryPath).split(path.sep).join('/');
|
||||
|
||||
return [
|
||||
{
|
||||
name: `${packageName}/${relativePath}`,
|
||||
name: `${archiveRoot}/${relativePath}`,
|
||||
content: fs.readFileSync(entryPath),
|
||||
},
|
||||
];
|
||||
@@ -120,7 +91,7 @@ function createZip(entries: ZipEntry[]) {
|
||||
|
||||
localParts.push(localHeader, entry.content);
|
||||
|
||||
const centralHeader = Buffer.concat([
|
||||
centralParts.push(Buffer.concat([
|
||||
writeUInt32(0x02014b50),
|
||||
writeUInt16(20),
|
||||
writeUInt16(20),
|
||||
@@ -139,9 +110,8 @@ function createZip(entries: ZipEntry[]) {
|
||||
writeUInt32(0),
|
||||
writeUInt32(offset),
|
||||
fileName,
|
||||
]);
|
||||
]));
|
||||
|
||||
centralParts.push(centralHeader);
|
||||
offset += localHeader.length + size;
|
||||
}
|
||||
|
||||
@@ -160,30 +130,7 @@ function createZip(entries: ZipEntry[]) {
|
||||
return Buffer.concat([...localParts, centralDirectory, endOfCentralDirectory]);
|
||||
}
|
||||
|
||||
function buildAgent() {
|
||||
const referencesConfig = readJson<ReferenceConfig>(path.join(sourceDir, 'references.json'));
|
||||
|
||||
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||
fs.mkdirSync(packageDir, { recursive: true });
|
||||
|
||||
copyFile(path.join(sourceDir, 'AGENT.md'), path.join(packageDir, 'AGENT.md'));
|
||||
copyFile(path.join(sourceDir, 'manifest.json'), path.join(packageDir, 'manifest.json'));
|
||||
|
||||
for (const reference of referencesConfig.references) {
|
||||
const sourcePath = path.join(rootDir, reference.source);
|
||||
|
||||
if (!fs.existsSync(sourcePath)) {
|
||||
throw new Error(`Reference not found: ${reference.source}`);
|
||||
}
|
||||
|
||||
copyFile(sourcePath, path.join(packageDir, reference.target));
|
||||
}
|
||||
|
||||
fs.mkdirSync(publicAgentsDir, { recursive: true });
|
||||
fs.writeFileSync(zipPath, createZip(collectFiles(packageDir)));
|
||||
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||
|
||||
console.log(`Built ${path.relative(rootDir, zipPath)}`);
|
||||
export function writeZipFromDirectory(sourceDir: string, zipPath: string, archiveRoot = path.basename(sourceDir)) {
|
||||
fs.mkdirSync(path.dirname(zipPath), { recursive: true });
|
||||
fs.writeFileSync(zipPath, createZip(collectFiles(sourceDir, sourceDir, archiveRoot)));
|
||||
}
|
||||
|
||||
buildAgent();
|
||||
20
projects/figma-adaptive-standards/build.ts
Normal file
20
projects/figma-adaptive-standards/build.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { prepareDocs } from '../_shared/lib/prepare-docs';
|
||||
import { run } from '../_shared/lib/run';
|
||||
import { writeZipFromDirectory } from '../_shared/lib/zip';
|
||||
import config from './project.config';
|
||||
|
||||
const projectDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.resolve(projectDir, '../..');
|
||||
const docsDir = path.join(projectDir, config.docsDir);
|
||||
|
||||
await prepareDocs(projectDir, config);
|
||||
run('npx', ['vitepress', 'build', docsDir], rootDir);
|
||||
|
||||
if (config.archive) {
|
||||
const zipPath = path.join(rootDir, 'public', config.slug, `${config.slug}.zip`);
|
||||
writeZipFromDirectory(path.join(docsDir, 'content'), zipPath, config.slug);
|
||||
console.log(`Собран ${path.relative(rootDir, zipPath)}`);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineConfig } from 'vitepress';
|
||||
import taskLists from 'markdown-it-task-lists';
|
||||
import llmstxt from 'vitepress-plugin-llms';
|
||||
import { themeSyncHead } from '../../shared/vitepress/themeHead';
|
||||
import { themeSyncHead } from '../../../_shared/docs/vitepress/themeHead';
|
||||
import { sidebar, site } from '../docs.config';
|
||||
|
||||
export default defineConfig({
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from '../../../../_shared/docs/vitepress/theme';
|
||||
@@ -2,22 +2,22 @@ export const site = {
|
||||
title: 'Figma Adaptive Standards',
|
||||
description: 'Стандарты подготовки адаптивных макетов в Figma',
|
||||
base: '/figma-adaptive-standards/',
|
||||
outDir: '../../public/figma-adaptive-standards',
|
||||
outDir: '../../../public/figma-adaptive-standards',
|
||||
};
|
||||
|
||||
/**
|
||||
* Карта монтирования исходных канонов в VitePress-документацию.
|
||||
*
|
||||
* `source` указывает на markdown-файл внутри `canons/`.
|
||||
* `target` задаёт путь, по которому этот файл попадёт в `docs/figma-adaptive-standards/content/`
|
||||
* `target` задаёт путь, по которому этот файл попадёт в `docs/content/`
|
||||
* и станет страницей итоговой документации.
|
||||
*/
|
||||
export const mounts = [
|
||||
{ target: 'index.md', source: 'figma/index.md' },
|
||||
{ target: 'overview.md', source: 'figma/index.md' },
|
||||
{ target: 'adaptive-layout-requirements/short.md', source: 'figma/adaptive-layout-requirements.short.md' },
|
||||
{ target: 'adaptive-layout-requirements/full.md', source: 'figma/adaptive-layout-requirements.full.md' },
|
||||
{ target: 'adaptive-layout-requirements/checklist.md', source: 'figma/adaptive-layout-requirements.checklist.md' },
|
||||
{ target: 'index.md', source: 'canons/index.md' },
|
||||
{ target: 'overview.md', source: 'canons/index.md' },
|
||||
{ target: 'adaptive-layout-requirements/short.md', source: 'canons/adaptive-layout-requirements.short.md' },
|
||||
{ target: 'adaptive-layout-requirements/full.md', source: 'canons/adaptive-layout-requirements.full.md' },
|
||||
{ target: 'adaptive-layout-requirements/checklist.md', source: 'canons/adaptive-layout-requirements.checklist.md' },
|
||||
];
|
||||
|
||||
export const sidebar = [
|
||||
5
projects/figma-adaptive-standards/project.config.ts
Normal file
5
projects/figma-adaptive-standards/project.config.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
slug: 'figma-adaptive-standards',
|
||||
docsDir: 'docs',
|
||||
archive: true,
|
||||
} as const;
|
||||
20
projects/nextjs-style-guide/build.ts
Normal file
20
projects/nextjs-style-guide/build.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { prepareDocs } from '../_shared/lib/prepare-docs';
|
||||
import { run } from '../_shared/lib/run';
|
||||
import { writeZipFromDirectory } from '../_shared/lib/zip';
|
||||
import config from './project.config';
|
||||
|
||||
const projectDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.resolve(projectDir, '../..');
|
||||
const docsDir = path.join(projectDir, config.docsDir);
|
||||
|
||||
await prepareDocs(projectDir, config);
|
||||
run('npx', ['vitepress', 'build', docsDir], rootDir);
|
||||
|
||||
if (config.archive) {
|
||||
const zipPath = path.join(rootDir, 'public', config.slug, `${config.slug}.zip`);
|
||||
writeZipFromDirectory(path.join(docsDir, 'content'), zipPath, config.slug);
|
||||
console.log(`Собран ${path.relative(rootDir, zipPath)}`);
|
||||
}
|
||||
@@ -16,7 +16,7 @@ description: Практический стайлгайд для разработ
|
||||
|
||||
**Для проекта:**
|
||||
|
||||
- [nextjs-style-guide.zip](/nextjs-style-guide.zip) — Набор Markdown-файлов для распаковки в `./ai/nextjs-style-guide/` или другую папку проекта.
|
||||
- [nextjs-style-guide.zip](/nextjs-style-guide/nextjs-style-guide.zip) — Набор Markdown-файлов для распаковки в `./ai/nextjs-style-guide/` или другую папку проекта.
|
||||
|
||||
## Структура документации
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineConfig } from 'vitepress';
|
||||
import taskLists from 'markdown-it-task-lists';
|
||||
import llmstxt from 'vitepress-plugin-llms';
|
||||
import { themeSyncHead } from '../../shared/vitepress/themeHead';
|
||||
import { themeSyncHead } from '../../../_shared/docs/vitepress/themeHead';
|
||||
import { sidebar, site } from '../docs.config';
|
||||
|
||||
export default defineConfig({
|
||||
@@ -11,6 +11,7 @@ export default defineConfig({
|
||||
outDir: site.outDir,
|
||||
srcDir: 'content',
|
||||
cleanUrls: true,
|
||||
ignoreDeadLinks: [/^\/slm-design\//],
|
||||
head: [...themeSyncHead],
|
||||
vite: {
|
||||
plugins: [llmstxt()],
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from '../../../../_shared/docs/vitepress/theme';
|
||||
@@ -2,71 +2,71 @@ export const site = {
|
||||
title: 'NextJS Style Guide',
|
||||
description: 'Практический стайлгайд для разработки frontend-приложений на Next.js и TypeScript',
|
||||
base: '/nextjs-style-guide/',
|
||||
outDir: '../../public/nextjs-style-guide',
|
||||
outDir: '../../../public/nextjs-style-guide',
|
||||
};
|
||||
|
||||
/**
|
||||
* Карта монтирования исходных канонов в VitePress-документацию.
|
||||
*
|
||||
* SLM-разделы берутся только из корневого `canons/slm-design/`, чтобы
|
||||
* NextJS-гайд не содержал собственных дублей архитектурного канона.
|
||||
* SLM-разделы берутся из проекта `slm-design`, чтобы NextJS-гайд не содержал
|
||||
* собственных дублей архитектурного канона.
|
||||
*/
|
||||
export const mounts = [
|
||||
{ target: 'index.md', source: 'style-guide/index.md' },
|
||||
{ target: 'workflow.md', source: 'style-guide/workflow.md' },
|
||||
{ target: 'index.md', source: 'canons/index.md' },
|
||||
{ target: 'workflow.md', source: 'canons/workflow.md' },
|
||||
|
||||
{ target: 'slm-design/architecture/index.md', source: 'slm-design/architecture/index.md' },
|
||||
{ target: 'slm-design/architecture/layers.md', source: 'slm-design/architecture/layers.md' },
|
||||
{ target: 'slm-design/architecture/modules.md', source: 'slm-design/architecture/modules.md' },
|
||||
{ target: 'slm-design/architecture/segments.md', source: 'slm-design/architecture/segments.md' },
|
||||
{ target: 'slm-design/architecture/monorepo.md', source: 'slm-design/architecture/monorepo.md' },
|
||||
{ target: 'slm-design/examples/react/factory.md', source: 'slm-design/examples/react/factory.md' },
|
||||
{ target: 'slm-design/examples/react/factory-composition.md', source: 'slm-design/examples/react/factory-composition.md' },
|
||||
{ target: 'slm-design/examples/react/composition-provider.md', source: 'slm-design/examples/react/composition-provider.md' },
|
||||
{ target: 'slm-design/architecture/index.md', source: '../slm-design/canons/architecture/index.md' },
|
||||
{ target: 'slm-design/architecture/layers.md', source: '../slm-design/canons/architecture/layers.md' },
|
||||
{ target: 'slm-design/architecture/modules.md', source: '../slm-design/canons/architecture/modules.md' },
|
||||
{ target: 'slm-design/architecture/segments.md', source: '../slm-design/canons/architecture/segments.md' },
|
||||
{ target: 'slm-design/architecture/monorepo.md', source: '../slm-design/canons/architecture/monorepo.md' },
|
||||
{ target: 'slm-design/examples/react/factory.md', source: '../slm-design/canons/examples/react/factory.md' },
|
||||
{ target: 'slm-design/examples/react/factory-composition.md', source: '../slm-design/canons/examples/react/factory-composition.md' },
|
||||
{ target: 'slm-design/examples/react/composition-provider.md', source: '../slm-design/canons/examples/react/composition-provider.md' },
|
||||
|
||||
{ target: 'basics/tech-stack.md', source: 'style-guide/basics/tech-stack.md' },
|
||||
{ target: 'basics/naming.md', source: 'style-guide/basics/naming.md' },
|
||||
{ target: 'basics/code-style.md', source: 'style-guide/basics/code-style.md' },
|
||||
{ target: 'basics/documentation.md', source: 'style-guide/basics/documentation.md' },
|
||||
{ target: 'basics/typing.md', source: 'style-guide/basics/typing.md' },
|
||||
{ target: 'basics/tech-stack.md', source: 'canons/basics/tech-stack.md' },
|
||||
{ target: 'basics/naming.md', source: 'canons/basics/naming.md' },
|
||||
{ target: 'basics/code-style.md', source: 'canons/basics/code-style.md' },
|
||||
{ target: 'basics/documentation.md', source: 'canons/basics/documentation.md' },
|
||||
{ target: 'basics/typing.md', source: 'canons/basics/typing.md' },
|
||||
|
||||
{ target: 'applied/creating-project/from-template.md', source: 'style-guide/applied/creating-project/from-template.md' },
|
||||
{ target: 'applied/creating-project/manual.md', source: 'style-guide/applied/creating-project/manual.md' },
|
||||
{ target: 'applied/creating-project/nextjs.md', source: 'style-guide/applied/creating-project/nextjs.md' },
|
||||
{ target: 'applied/project-structure.md', source: 'style-guide/applied/project-structure.md' },
|
||||
{ target: 'applied/page-level.md', source: 'style-guide/applied/page-level.md' },
|
||||
{ target: 'applied/component.md', source: 'style-guide/applied/component.md' },
|
||||
{ target: 'applied/module.md', source: 'style-guide/applied/module.md' },
|
||||
{ target: 'applied/rest-client/index.md', source: 'style-guide/applied/rest-client/index.md' },
|
||||
{ target: 'applied/rest-client/setup/index.md', source: 'style-guide/applied/rest-client/setup/index.md' },
|
||||
{ target: 'applied/rest-client/setup/auto.md', source: 'style-guide/applied/rest-client/setup/auto.md' },
|
||||
{ target: 'applied/rest-client/setup/manual.md', source: 'style-guide/applied/rest-client/setup/manual.md' },
|
||||
{ target: 'applied/rest-client/setup/hooks.md', source: 'style-guide/applied/rest-client/setup/hooks.md' },
|
||||
{ target: 'applied/rest-client/usage.md', source: 'style-guide/applied/rest-client/usage.md' },
|
||||
{ target: 'applied/data-fetch/index.md', source: 'style-guide/applied/data-fetch/index.md' },
|
||||
{ target: 'applied/data-fetch/server-await.md', source: 'style-guide/applied/data-fetch/server-await.md' },
|
||||
{ target: 'applied/data-fetch/parallel-server-requests.md', source: 'style-guide/applied/data-fetch/parallel-server-requests.md' },
|
||||
{ target: 'applied/data-fetch/pass-promise-down.md', source: 'style-guide/applied/data-fetch/pass-promise-down.md' },
|
||||
{ target: 'applied/data-fetch/client-hooks-initial-data.md', source: 'style-guide/applied/data-fetch/client-hooks-initial-data.md' },
|
||||
{ target: 'applied/data-fetch/client-get-hook.md', source: 'style-guide/applied/data-fetch/client-get-hook.md' },
|
||||
{ target: 'applied/data-fetch/business-composition.md', source: 'style-guide/applied/data-fetch/business-composition.md' },
|
||||
{ target: 'applied/styles/styles-setup.md', source: 'style-guide/applied/styles/styles-setup.md' },
|
||||
{ target: 'applied/styles/styles-usage.md', source: 'style-guide/applied/styles/styles-usage.md' },
|
||||
{ target: 'applied/svg-sprites/svg-sprites-intro.md', source: 'style-guide/applied/svg-sprites/svg-sprites-intro.md' },
|
||||
{ target: 'applied/svg-sprites/svg-sprites-setup.md', source: 'style-guide/applied/svg-sprites/svg-sprites-setup.md' },
|
||||
{ target: 'applied/svg-sprites/svg-sprites-usage.md', source: 'style-guide/applied/svg-sprites/svg-sprites-usage.md' },
|
||||
{ target: 'applied/images.md', source: 'style-guide/applied/images.md' },
|
||||
{ target: 'applied/fonts.md', source: 'style-guide/applied/fonts.md' },
|
||||
{ target: 'applied/aliases.md', source: 'style-guide/applied/aliases.md' },
|
||||
{ target: 'applied/templates/templates-intro.md', source: 'style-guide/applied/templates/templates-intro.md' },
|
||||
{ target: 'applied/templates/templates-setup.md', source: 'style-guide/applied/templates/templates-setup.md' },
|
||||
{ target: 'applied/templates/templates-create.md', source: 'style-guide/applied/templates/templates-create.md' },
|
||||
{ target: 'applied/templates/templates-usage.md', source: 'style-guide/applied/templates/templates-usage.md' },
|
||||
{ target: 'applied/biome.md', source: 'style-guide/applied/biome.md' },
|
||||
{ target: 'applied/postcss.md', source: 'style-guide/applied/postcss.md' },
|
||||
{ target: 'applied/vscode.md', source: 'style-guide/applied/vscode.md' },
|
||||
{ target: 'applied/localization.md', source: 'style-guide/applied/localization.md' },
|
||||
{ target: 'applied/stores.md', source: 'style-guide/applied/stores.md' },
|
||||
{ target: 'applied/creating-project/from-template.md', source: 'canons/applied/creating-project/from-template.md' },
|
||||
{ target: 'applied/creating-project/manual.md', source: 'canons/applied/creating-project/manual.md' },
|
||||
{ target: 'applied/creating-project/nextjs.md', source: 'canons/applied/creating-project/nextjs.md' },
|
||||
{ target: 'applied/project-structure.md', source: 'canons/applied/project-structure.md' },
|
||||
{ target: 'applied/page-level.md', source: 'canons/applied/page-level.md' },
|
||||
{ target: 'applied/component.md', source: 'canons/applied/component.md' },
|
||||
{ target: 'applied/module.md', source: 'canons/applied/module.md' },
|
||||
{ target: 'applied/rest-client/index.md', source: 'canons/applied/rest-client/index.md' },
|
||||
{ target: 'applied/rest-client/setup/index.md', source: 'canons/applied/rest-client/setup/index.md' },
|
||||
{ target: 'applied/rest-client/setup/auto.md', source: 'canons/applied/rest-client/setup/auto.md' },
|
||||
{ target: 'applied/rest-client/setup/manual.md', source: 'canons/applied/rest-client/setup/manual.md' },
|
||||
{ target: 'applied/rest-client/setup/hooks.md', source: 'canons/applied/rest-client/setup/hooks.md' },
|
||||
{ target: 'applied/rest-client/usage.md', source: 'canons/applied/rest-client/usage.md' },
|
||||
{ target: 'applied/data-fetch/index.md', source: 'canons/applied/data-fetch/index.md' },
|
||||
{ target: 'applied/data-fetch/server-await.md', source: 'canons/applied/data-fetch/server-await.md' },
|
||||
{ target: 'applied/data-fetch/parallel-server-requests.md', source: 'canons/applied/data-fetch/parallel-server-requests.md' },
|
||||
{ target: 'applied/data-fetch/pass-promise-down.md', source: 'canons/applied/data-fetch/pass-promise-down.md' },
|
||||
{ target: 'applied/data-fetch/client-hooks-initial-data.md', source: 'canons/applied/data-fetch/client-hooks-initial-data.md' },
|
||||
{ target: 'applied/data-fetch/client-get-hook.md', source: 'canons/applied/data-fetch/client-get-hook.md' },
|
||||
{ target: 'applied/data-fetch/business-composition.md', source: 'canons/applied/data-fetch/business-composition.md' },
|
||||
{ target: 'applied/styles/styles-setup.md', source: 'canons/applied/styles/styles-setup.md' },
|
||||
{ target: 'applied/styles/styles-usage.md', source: 'canons/applied/styles/styles-usage.md' },
|
||||
{ target: 'applied/svg-sprites/svg-sprites-intro.md', source: 'canons/applied/svg-sprites/svg-sprites-intro.md' },
|
||||
{ target: 'applied/svg-sprites/svg-sprites-setup.md', source: 'canons/applied/svg-sprites/svg-sprites-setup.md' },
|
||||
{ target: 'applied/svg-sprites/svg-sprites-usage.md', source: 'canons/applied/svg-sprites/svg-sprites-usage.md' },
|
||||
{ target: 'applied/images.md', source: 'canons/applied/images.md' },
|
||||
{ target: 'applied/fonts.md', source: 'canons/applied/fonts.md' },
|
||||
{ target: 'applied/aliases.md', source: 'canons/applied/aliases.md' },
|
||||
{ target: 'applied/templates/templates-intro.md', source: 'canons/applied/templates/templates-intro.md' },
|
||||
{ target: 'applied/templates/templates-setup.md', source: 'canons/applied/templates/templates-setup.md' },
|
||||
{ target: 'applied/templates/templates-create.md', source: 'canons/applied/templates/templates-create.md' },
|
||||
{ target: 'applied/templates/templates-usage.md', source: 'canons/applied/templates/templates-usage.md' },
|
||||
{ target: 'applied/biome.md', source: 'canons/applied/biome.md' },
|
||||
{ target: 'applied/postcss.md', source: 'canons/applied/postcss.md' },
|
||||
{ target: 'applied/vscode.md', source: 'canons/applied/vscode.md' },
|
||||
{ target: 'applied/localization.md', source: 'canons/applied/localization.md' },
|
||||
{ target: 'applied/stores.md', source: 'canons/applied/stores.md' },
|
||||
];
|
||||
|
||||
export const routeRewrites = [
|
||||
5
projects/nextjs-style-guide/project.config.ts
Normal file
5
projects/nextjs-style-guide/project.config.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
slug: 'nextjs-style-guide',
|
||||
docsDir: 'docs',
|
||||
archive: true,
|
||||
} as const;
|
||||
0
projects/nextjs-style-guide/scripts/.gitkeep
Normal file
0
projects/nextjs-style-guide/scripts/.gitkeep
Normal file
20
projects/slm-design/build.ts
Normal file
20
projects/slm-design/build.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { prepareDocs } from '../_shared/lib/prepare-docs';
|
||||
import { run } from '../_shared/lib/run';
|
||||
import { writeZipFromDirectory } from '../_shared/lib/zip';
|
||||
import config from './project.config';
|
||||
|
||||
const projectDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.resolve(projectDir, '../..');
|
||||
const docsDir = path.join(projectDir, config.docsDir);
|
||||
|
||||
await prepareDocs(projectDir, config);
|
||||
run('npx', ['vitepress', 'build', docsDir], rootDir);
|
||||
|
||||
if (config.archive) {
|
||||
const zipPath = path.join(rootDir, 'public', config.slug, `${config.slug}.zip`);
|
||||
writeZipFromDirectory(path.join(docsDir, 'content'), zipPath, config.slug);
|
||||
console.log(`Собран ${path.relative(rootDir, zipPath)}`);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineConfig } from 'vitepress';
|
||||
import taskLists from 'markdown-it-task-lists';
|
||||
import llmstxt from 'vitepress-plugin-llms';
|
||||
import { themeSyncHead } from '../../shared/vitepress/themeHead';
|
||||
import { themeSyncHead } from '../../../_shared/docs/vitepress/themeHead';
|
||||
import { sidebar, site } from '../docs.config';
|
||||
|
||||
export default defineConfig({
|
||||
1
projects/slm-design/docs/.vitepress/theme/index.ts
Normal file
1
projects/slm-design/docs/.vitepress/theme/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from '../../../../_shared/docs/vitepress/theme';
|
||||
@@ -2,26 +2,26 @@ export const site = {
|
||||
title: 'SLM Design',
|
||||
description: 'Каноны архитектуры SLM Design',
|
||||
base: '/slm-design/',
|
||||
outDir: '../../public/slm-design',
|
||||
outDir: '../../../public/slm-design',
|
||||
};
|
||||
|
||||
/**
|
||||
* Карта монтирования исходных канонов в VitePress-документацию.
|
||||
*
|
||||
* `source` указывает на markdown-файл внутри `canons/`.
|
||||
* `target` задаёт путь, по которому этот файл попадёт в `docs/slm-design/content/`
|
||||
* `target` задаёт путь, по которому этот файл попадёт в `docs/content/`
|
||||
* и станет страницей итоговой документации.
|
||||
*/
|
||||
export const mounts = [
|
||||
{ target: 'index.md', source: 'slm-design/architecture/index.md' },
|
||||
{ target: 'architecture/index.md', source: 'slm-design/architecture/index.md' },
|
||||
{ target: 'architecture/layers.md', source: 'slm-design/architecture/layers.md' },
|
||||
{ target: 'architecture/modules.md', source: 'slm-design/architecture/modules.md' },
|
||||
{ target: 'architecture/segments.md', source: 'slm-design/architecture/segments.md' },
|
||||
{ target: 'architecture/monorepo.md', source: 'slm-design/architecture/monorepo.md' },
|
||||
{ target: 'examples/react/factory.md', source: 'slm-design/examples/react/factory.md' },
|
||||
{ target: 'examples/react/factory-composition.md', source: 'slm-design/examples/react/factory-composition.md' },
|
||||
{ target: 'examples/react/composition-provider.md', source: 'slm-design/examples/react/composition-provider.md' },
|
||||
{ target: 'index.md', source: 'canons/architecture/index.md' },
|
||||
{ target: 'architecture/index.md', source: 'canons/architecture/index.md' },
|
||||
{ target: 'architecture/layers.md', source: 'canons/architecture/layers.md' },
|
||||
{ target: 'architecture/modules.md', source: 'canons/architecture/modules.md' },
|
||||
{ target: 'architecture/segments.md', source: 'canons/architecture/segments.md' },
|
||||
{ target: 'architecture/monorepo.md', source: 'canons/architecture/monorepo.md' },
|
||||
{ target: 'examples/react/factory.md', source: 'canons/examples/react/factory.md' },
|
||||
{ target: 'examples/react/factory-composition.md', source: 'canons/examples/react/factory-composition.md' },
|
||||
{ target: 'examples/react/composition-provider.md', source: 'canons/examples/react/composition-provider.md' },
|
||||
];
|
||||
|
||||
export const sidebar = [
|
||||
5
projects/slm-design/project.config.ts
Normal file
5
projects/slm-design/project.config.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
slug: 'slm-design',
|
||||
docsDir: 'docs',
|
||||
archive: true,
|
||||
} as const;
|
||||
0
projects/slm-design/scripts/.gitkeep
Normal file
0
projects/slm-design/scripts/.gitkeep
Normal file
20
projects/template-sync-strategy/build.ts
Normal file
20
projects/template-sync-strategy/build.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { prepareDocs } from '../_shared/lib/prepare-docs';
|
||||
import { run } from '../_shared/lib/run';
|
||||
import { writeZipFromDirectory } from '../_shared/lib/zip';
|
||||
import config from './project.config';
|
||||
|
||||
const projectDir = path.dirname(fileURLToPath(import.meta.url));
|
||||
const rootDir = path.resolve(projectDir, '../..');
|
||||
const docsDir = path.join(projectDir, config.docsDir);
|
||||
|
||||
await prepareDocs(projectDir, config);
|
||||
run('npx', ['vitepress', 'build', docsDir], rootDir);
|
||||
|
||||
if (config.archive) {
|
||||
const zipPath = path.join(rootDir, 'public', config.slug, `${config.slug}.zip`);
|
||||
writeZipFromDirectory(path.join(docsDir, 'content'), zipPath, config.slug);
|
||||
console.log(`Собран ${path.relative(rootDir, zipPath)}`);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user