@rk-web/create 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/create.js +3 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +47 -0
- package/dist/cli.js.map +1 -0
- package/dist/create.d.ts +2 -0
- package/dist/create.d.ts.map +1 -0
- package/dist/create.js +179 -0
- package/dist/create.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
- package/templates/blog/config.json +27 -0
- package/templates/blog/src/assets/styles/main.css +182 -0
- package/templates/blog/src/components/footer.html +10 -0
- package/templates/blog/src/components/header.html +10 -0
- package/templates/blog/src/components/post-card.html +11 -0
- package/templates/blog/src/data/posts.json +28 -0
- package/templates/blog/src/layouts/base.html +24 -0
- package/templates/blog/src/pages/blog/index.html +22 -0
- package/templates/blog/src/pages/blog/post.html +20 -0
- package/templates/blog/src/pages/index.html +29 -0
- package/templates/landing/config.json +28 -0
- package/templates/landing/src/assets/styles/main.css +474 -0
- package/templates/landing/src/components/cta.html +13 -0
- package/templates/landing/src/components/features.html +17 -0
- package/templates/landing/src/components/footer.html +18 -0
- package/templates/landing/src/components/header.html +11 -0
- package/templates/landing/src/components/hero.html +26 -0
- package/templates/landing/src/components/pricing.html +28 -0
- package/templates/landing/src/components/testimonials.html +24 -0
- package/templates/landing/src/data/landing.json +93 -0
- package/templates/landing/src/layouts/base.html +22 -0
- package/templates/landing/src/pages/index.html +12 -0
- package/templates/minimal/config.json +24 -0
- package/templates/minimal/src/assets/styles/main.css +50 -0
- package/templates/minimal/src/components/footer.html +6 -0
- package/templates/minimal/src/components/header.html +8 -0
- package/templates/minimal/src/layouts/base.html +20 -0
- package/templates/minimal/src/pages/index.html +13 -0
- package/templates/minimal/src/scripts/main.ts +2 -0
- package/templates/portfolio/config.json +27 -0
- package/templates/portfolio/src/assets/styles/main.css +289 -0
- package/templates/portfolio/src/components/footer.html +10 -0
- package/templates/portfolio/src/components/header.html +10 -0
- package/templates/portfolio/src/components/project-card.html +24 -0
- package/templates/portfolio/src/data/projects.json +40 -0
- package/templates/portfolio/src/layouts/base.html +23 -0
- package/templates/portfolio/src/pages/index.html +62 -0
package/bin/create.js
ADDED
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import pc from 'picocolors';
|
|
3
|
+
import prompts from 'prompts';
|
|
4
|
+
import { createProject } from './create.js';
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.name('create-my-static-builder')
|
|
8
|
+
.description(pc.bold('Создание нового проекта статического сайта'))
|
|
9
|
+
.version('0.0.1');
|
|
10
|
+
program
|
|
11
|
+
.argument('[project-name]', 'Имя проекта')
|
|
12
|
+
.option('-t, --template <name>', 'Шаблон (minimal|blog|portfolio|landing)')
|
|
13
|
+
.action(async (projectName, options) => {
|
|
14
|
+
let name = projectName;
|
|
15
|
+
if (!name) {
|
|
16
|
+
const response = await prompts({
|
|
17
|
+
type: 'text',
|
|
18
|
+
name: 'name',
|
|
19
|
+
message: 'Введите имя проекта:',
|
|
20
|
+
initial: 'my-site'
|
|
21
|
+
});
|
|
22
|
+
name = response.name;
|
|
23
|
+
}
|
|
24
|
+
if (!name) {
|
|
25
|
+
console.error(pc.red('Имя проекта не указано'));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
let template = options.template;
|
|
29
|
+
if (!template) {
|
|
30
|
+
const response = await prompts({
|
|
31
|
+
type: 'select',
|
|
32
|
+
name: 'template',
|
|
33
|
+
message: 'Выберите шаблон:',
|
|
34
|
+
choices: [
|
|
35
|
+
{ title: 'Минимальный', value: 'minimal', description: 'Базовая структура' },
|
|
36
|
+
{ title: 'Блог', value: 'blog', description: 'Шаблон для блога' },
|
|
37
|
+
{ title: 'Портфолио', value: 'portfolio', description: 'Шаблон портфолио' },
|
|
38
|
+
{ title: 'Лендинг', value: 'landing', description: 'Одностраничный сайт' }
|
|
39
|
+
],
|
|
40
|
+
initial: 0
|
|
41
|
+
});
|
|
42
|
+
template = response.template;
|
|
43
|
+
}
|
|
44
|
+
await createProject(name, template || 'minimal');
|
|
45
|
+
});
|
|
46
|
+
program.parse();
|
|
47
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,OAAO,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAA;AAE7B,OAAO;KACJ,IAAI,CAAC,0BAA0B,CAAC;KAChC,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;KAClE,OAAO,CAAC,OAAO,CAAC,CAAA;AAEnB,OAAO;KACJ,QAAQ,CAAC,gBAAgB,EAAE,aAAa,CAAC;KACzC,MAAM,CAAC,uBAAuB,EAAE,yCAAyC,CAAC;KAC1E,MAAM,CAAC,KAAK,EAAE,WAA+B,EAAE,OAA8B,EAAE,EAAE;IAChF,IAAI,IAAI,GAAG,WAAW,CAAA;IAEtB,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC;YAC7B,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,sBAAsB;YAC/B,OAAO,EAAE,SAAS;SACnB,CAAC,CAAA;QACF,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAA;IACtB,CAAC;IAED,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAA;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAA;IAE/B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC;YAC7B,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE;gBACP,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,mBAAmB,EAAE;gBAC5E,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,kBAAkB,EAAE;gBACjE,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE;gBAC3E,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,qBAAqB,EAAE;aAC3E;YACD,OAAO,EAAE,CAAC;SACX,CAAC,CAAA;QACF,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAA;IAC9B,CAAC;IAED,MAAM,aAAa,CAAC,IAAI,EAAE,QAAQ,IAAI,SAAS,CAAC,CAAA;AAClD,CAAC,CAAC,CAAA;AAEJ,OAAO,CAAC,KAAK,EAAE,CAAA"}
|
package/dist/create.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"AAQA,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,iBA6KjE"}
|
package/dist/create.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
export async function createProject(name, template) {
|
|
8
|
+
console.log(pc.blue(`\nСоздание проекта: ${pc.bold(name)}`));
|
|
9
|
+
console.log(pc.blue(`Шаблон: ${pc.bold(template)}\n`));
|
|
10
|
+
const targetDir = path.resolve(process.cwd(), name);
|
|
11
|
+
// Проверка существования директории
|
|
12
|
+
if (await fs.pathExists(targetDir)) {
|
|
13
|
+
const files = await fs.readdir(targetDir);
|
|
14
|
+
if (files.length > 0) {
|
|
15
|
+
console.error(pc.red(`\nОшибка: Директория "${name}" уже существует и не пуста`));
|
|
16
|
+
console.error(pc.gray('Удалите директорию или выберите другое имя'));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Создание директории
|
|
21
|
+
await fs.ensureDir(targetDir);
|
|
22
|
+
// Копирование шаблона
|
|
23
|
+
const templateDir = await resolveTemplateDir(template);
|
|
24
|
+
if (!templateDir) {
|
|
25
|
+
console.error(pc.red(`\nОшибка: Шаблон "${template}" не найден`));
|
|
26
|
+
console.error(pc.gray(`Доступные шаблоны: minimal, blog, portfolio, landing`));
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
await fs.copy(templateDir, targetDir, {
|
|
30
|
+
overwrite: true,
|
|
31
|
+
errorOnExist: false
|
|
32
|
+
});
|
|
33
|
+
// Создание package.json
|
|
34
|
+
const packageJson = {
|
|
35
|
+
name,
|
|
36
|
+
version: '0.0.1',
|
|
37
|
+
private: true,
|
|
38
|
+
type: 'module',
|
|
39
|
+
scripts: {
|
|
40
|
+
dev: 'my-static-builder dev',
|
|
41
|
+
build: 'my-static-builder build',
|
|
42
|
+
preview: 'my-static-builder preview',
|
|
43
|
+
validate: 'my-static-builder validate'
|
|
44
|
+
},
|
|
45
|
+
devDependencies: {
|
|
46
|
+
'@rk-web/core': 'latest',
|
|
47
|
+
vite: '^6.4.1'
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
await fs.writeJson(path.join(targetDir, 'package.json'), packageJson, { spaces: 2 });
|
|
51
|
+
// Создание базового config.json если его нет
|
|
52
|
+
const configPath = path.join(targetDir, 'config.json');
|
|
53
|
+
if (!await fs.pathExists(configPath)) {
|
|
54
|
+
const configJson = {
|
|
55
|
+
site: {
|
|
56
|
+
title: name,
|
|
57
|
+
description: 'Описание сайта',
|
|
58
|
+
lang: 'ru',
|
|
59
|
+
url: 'https://example.com'
|
|
60
|
+
},
|
|
61
|
+
navigation: [
|
|
62
|
+
{ label: 'Главная', url: '/' }
|
|
63
|
+
],
|
|
64
|
+
footer: {
|
|
65
|
+
copyright: new Date().getFullYear().toString()
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
await fs.writeJson(configPath, configJson, { spaces: 2 });
|
|
69
|
+
}
|
|
70
|
+
// Создание vite.config.ts если его нет
|
|
71
|
+
const viteConfigPath = path.join(targetDir, 'vite.config.ts');
|
|
72
|
+
if (!await fs.pathExists(viteConfigPath)) {
|
|
73
|
+
const viteConfig = `import { defineConfig } from 'vite'
|
|
74
|
+
import { staticBuilder } from '@rk-web/core'
|
|
75
|
+
|
|
76
|
+
export default defineConfig({
|
|
77
|
+
plugins: [
|
|
78
|
+
staticBuilder({
|
|
79
|
+
template: {
|
|
80
|
+
includePath: 'src/components',
|
|
81
|
+
layoutPath: 'src/layouts',
|
|
82
|
+
dataPath: 'src/data',
|
|
83
|
+
configFile: 'config.json'
|
|
84
|
+
},
|
|
85
|
+
images: {
|
|
86
|
+
formats: ['avif', 'webp', 'jpg'],
|
|
87
|
+
quality: { avif: 50, webp: 80, jpg: 85 },
|
|
88
|
+
sizes: [320, 640, 960, 1280, 1920],
|
|
89
|
+
placeholder: 'blur',
|
|
90
|
+
lazyLoad: true,
|
|
91
|
+
decoding: 'async'
|
|
92
|
+
},
|
|
93
|
+
fonts: {
|
|
94
|
+
formats: ['woff2', 'woff'],
|
|
95
|
+
subsets: ['cyrillic', 'latin'],
|
|
96
|
+
preload: true,
|
|
97
|
+
display: 'swap'
|
|
98
|
+
},
|
|
99
|
+
seo: {
|
|
100
|
+
sitemap: true,
|
|
101
|
+
robots: true,
|
|
102
|
+
manifest: true,
|
|
103
|
+
rss: false,
|
|
104
|
+
ogImage: true
|
|
105
|
+
},
|
|
106
|
+
validate: {
|
|
107
|
+
html: true,
|
|
108
|
+
accessibility: true,
|
|
109
|
+
lighthouse: true
|
|
110
|
+
},
|
|
111
|
+
critical: {
|
|
112
|
+
enabled: true,
|
|
113
|
+
inline: true
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
]
|
|
117
|
+
})
|
|
118
|
+
`;
|
|
119
|
+
await fs.writeFile(viteConfigPath, viteConfig);
|
|
120
|
+
}
|
|
121
|
+
// Создание структуры директорий
|
|
122
|
+
const dirs = [
|
|
123
|
+
'src/pages',
|
|
124
|
+
'src/components',
|
|
125
|
+
'src/layouts',
|
|
126
|
+
'src/data',
|
|
127
|
+
'src/assets/images',
|
|
128
|
+
'src/assets/styles',
|
|
129
|
+
'src/assets/fonts',
|
|
130
|
+
'src/scripts',
|
|
131
|
+
'public/images',
|
|
132
|
+
'public/fonts'
|
|
133
|
+
];
|
|
134
|
+
for (const dir of dirs) {
|
|
135
|
+
await fs.ensureDir(path.join(targetDir, dir));
|
|
136
|
+
}
|
|
137
|
+
// Создание .gitignore
|
|
138
|
+
const gitignore = `# Dependencies
|
|
139
|
+
node_modules/
|
|
140
|
+
|
|
141
|
+
# Builds
|
|
142
|
+
dist/
|
|
143
|
+
|
|
144
|
+
# Environment
|
|
145
|
+
.env
|
|
146
|
+
.env.*
|
|
147
|
+
|
|
148
|
+
# IDE
|
|
149
|
+
.vscode/
|
|
150
|
+
.idea/
|
|
151
|
+
|
|
152
|
+
# OS
|
|
153
|
+
.DS_Store
|
|
154
|
+
Thumbs.db
|
|
155
|
+
|
|
156
|
+
# Cache
|
|
157
|
+
.cache/
|
|
158
|
+
.vite/
|
|
159
|
+
.sharp-cache/
|
|
160
|
+
`;
|
|
161
|
+
await fs.writeFile(path.join(targetDir, '.gitignore'), gitignore);
|
|
162
|
+
console.log(pc.green('\n✓ Проект успешно создан!\n'));
|
|
163
|
+
console.log(pc.cyan(` cd ${name}`));
|
|
164
|
+
console.log(pc.cyan(' npm install # или pnpm install / yarn install'));
|
|
165
|
+
console.log(pc.cyan(' npm run dev # запустить режим разработки\n'));
|
|
166
|
+
}
|
|
167
|
+
async function resolveTemplateDir(template) {
|
|
168
|
+
const candidates = [
|
|
169
|
+
path.resolve(__dirname, '../templates', template),
|
|
170
|
+
path.resolve(__dirname, '../../../templates', template)
|
|
171
|
+
];
|
|
172
|
+
for (const candidate of candidates) {
|
|
173
|
+
if (await fs.pathExists(candidate)) {
|
|
174
|
+
return candidate;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../src/create.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rk-web/create",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "CLI для создания новых проектов",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"bin": {
|
|
18
|
+
"create-my-static-builder": "./bin/create.js"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"bin",
|
|
23
|
+
"templates"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "pnpm run copy:templates && tsc",
|
|
27
|
+
"copy:templates": "node ./scripts/copy-templates.mjs",
|
|
28
|
+
"dev": "tsc --watch",
|
|
29
|
+
"lint": "eslint src --ext .ts",
|
|
30
|
+
"typecheck": "tsc --noEmit",
|
|
31
|
+
"clean": "rimraf dist"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"create",
|
|
35
|
+
"cli",
|
|
36
|
+
"static-site"
|
|
37
|
+
],
|
|
38
|
+
"author": "",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"commander": "^12.0.0",
|
|
42
|
+
"picocolors": "^1.0.0",
|
|
43
|
+
"prompts": "^2.4.2",
|
|
44
|
+
"fs-extra": "^11.2.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^20.11.0",
|
|
48
|
+
"@types/prompts": "^2.4.9",
|
|
49
|
+
"@types/fs-extra": "^11.0.4",
|
|
50
|
+
"typescript": "^5.4.0"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=18.0.0"
|
|
54
|
+
},
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"site": {
|
|
3
|
+
"title": "Мой блог",
|
|
4
|
+
"description": "Персональный блог о разработке и технологиях",
|
|
5
|
+
"lang": "ru",
|
|
6
|
+
"url": "https://myblog.com",
|
|
7
|
+
"author": "Имя автора",
|
|
8
|
+
"email": "author@myblog.com"
|
|
9
|
+
},
|
|
10
|
+
"seo": {
|
|
11
|
+
"ogImage": "images/og-default.jpg",
|
|
12
|
+
"ogType": "article",
|
|
13
|
+
"twitterCard": "summary_large_image"
|
|
14
|
+
},
|
|
15
|
+
"navigation": [
|
|
16
|
+
{ "label": "Главная", "url": "/" },
|
|
17
|
+
{ "label": "Блог", "url": "/blog/" },
|
|
18
|
+
{ "label": "Обо мне", "url": "/about/" }
|
|
19
|
+
],
|
|
20
|
+
"footer": {
|
|
21
|
+
"copyright": "2024",
|
|
22
|
+
"links": [
|
|
23
|
+
{ "label": "Telegram", "url": "https://t.me/author" },
|
|
24
|
+
{ "label": "GitHub", "url": "https://github.com/author" }
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/* Blog styles */
|
|
2
|
+
:root {
|
|
3
|
+
--color-primary: #2563eb;
|
|
4
|
+
--color-text: #1f2937;
|
|
5
|
+
--color-text-light: #6b7280;
|
|
6
|
+
--color-bg: #ffffff;
|
|
7
|
+
--color-bg-light: #f9fafb;
|
|
8
|
+
--max-width: 800px;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
* {
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding: 0;
|
|
14
|
+
box-sizing: border-box;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
body {
|
|
18
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, sans-serif;
|
|
19
|
+
line-height: 1.6;
|
|
20
|
+
color: var(--color-text);
|
|
21
|
+
background: var(--color-bg);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.container {
|
|
25
|
+
max-width: var(--max-width);
|
|
26
|
+
margin: 0 auto;
|
|
27
|
+
padding: 0 1rem;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Header */
|
|
31
|
+
.site-header {
|
|
32
|
+
padding: 1.5rem 0;
|
|
33
|
+
border-bottom: 1px solid #e5e7eb;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.site-header .container {
|
|
37
|
+
display: flex;
|
|
38
|
+
justify-content: space-between;
|
|
39
|
+
align-items: center;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.logo {
|
|
43
|
+
font-size: 1.5rem;
|
|
44
|
+
font-weight: bold;
|
|
45
|
+
text-decoration: none;
|
|
46
|
+
color: var(--color-text);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.nav-link {
|
|
50
|
+
margin-left: 1.5rem;
|
|
51
|
+
text-decoration: none;
|
|
52
|
+
color: var(--color-text-light);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.nav-link:hover {
|
|
56
|
+
color: var(--color-primary);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Hero */
|
|
60
|
+
.hero {
|
|
61
|
+
text-align: center;
|
|
62
|
+
padding: 4rem 0;
|
|
63
|
+
background: var(--color-bg-light);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.hero h1 {
|
|
67
|
+
font-size: 2.5rem;
|
|
68
|
+
margin-bottom: 1rem;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.hero p {
|
|
72
|
+
font-size: 1.25rem;
|
|
73
|
+
color: var(--color-text-light);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Posts */
|
|
77
|
+
.recent-posts, .blog-list {
|
|
78
|
+
padding: 2rem 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.recent-posts h2, .blog-list h1 {
|
|
82
|
+
margin-bottom: 2rem;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.post-card {
|
|
86
|
+
margin-bottom: 2rem;
|
|
87
|
+
padding-bottom: 2rem;
|
|
88
|
+
border-bottom: 1px solid #e5e7eb;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.post-title {
|
|
92
|
+
margin-bottom: 0.5rem;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.post-title a {
|
|
96
|
+
text-decoration: none;
|
|
97
|
+
color: var(--color-primary);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.post-title a:hover {
|
|
101
|
+
text-decoration: underline;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.post-meta {
|
|
105
|
+
font-size: 0.875rem;
|
|
106
|
+
color: var(--color-text-light);
|
|
107
|
+
margin-bottom: 1rem;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.post-meta time {
|
|
111
|
+
margin-right: 1rem;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.post-excerpt {
|
|
115
|
+
margin-bottom: 1rem;
|
|
116
|
+
color: var(--color-text-light);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.read-more {
|
|
120
|
+
text-decoration: none;
|
|
121
|
+
color: var(--color-primary);
|
|
122
|
+
font-weight: 500;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.read-more:hover {
|
|
126
|
+
text-decoration: underline;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* Blog post */
|
|
130
|
+
.blog-post {
|
|
131
|
+
padding: 2rem 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.post-header {
|
|
135
|
+
margin-bottom: 2rem;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.post-header h1 {
|
|
139
|
+
font-size: 2rem;
|
|
140
|
+
margin-bottom: 1rem;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.post-content {
|
|
144
|
+
line-height: 1.8;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.post-content p {
|
|
148
|
+
margin-bottom: 1.5rem;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.post-footer {
|
|
152
|
+
margin-top: 3rem;
|
|
153
|
+
padding-top: 2rem;
|
|
154
|
+
border-top: 1px solid #e5e7eb;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.back-link {
|
|
158
|
+
text-decoration: none;
|
|
159
|
+
color: var(--color-primary);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Footer */
|
|
163
|
+
.site-footer {
|
|
164
|
+
padding: 2rem 0;
|
|
165
|
+
border-top: 1px solid #e5e7eb;
|
|
166
|
+
text-align: center;
|
|
167
|
+
color: var(--color-text-light);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.footer-links {
|
|
171
|
+
margin-top: 1rem;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.footer-links a {
|
|
175
|
+
margin: 0 0.5rem;
|
|
176
|
+
text-decoration: none;
|
|
177
|
+
color: var(--color-text-light);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.footer-links a:hover {
|
|
181
|
+
color: var(--color-primary);
|
|
182
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<footer class="site-footer">
|
|
2
|
+
<div class="container">
|
|
3
|
+
<p>© {{ footer.copyright }} {{ site.author }}</p>
|
|
4
|
+
<div class="footer-links">
|
|
5
|
+
<!-- for: link in footer.links -->
|
|
6
|
+
<a href="{{ link.url }}" target="_blank" rel="noopener">{{ link.label }}</a>
|
|
7
|
+
<!-- endfor -->
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</footer>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<header class="site-header">
|
|
2
|
+
<div class="container">
|
|
3
|
+
<a href="/" class="logo">{{ site.title }}</a>
|
|
4
|
+
<nav>
|
|
5
|
+
<!-- for: item in site.navigation -->
|
|
6
|
+
<a href="{{ item.url }}" class="nav-link">{{ item.label }}</a>
|
|
7
|
+
<!-- endfor -->
|
|
8
|
+
</nav>
|
|
9
|
+
</div>
|
|
10
|
+
</header>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<article class="post-card">
|
|
2
|
+
<h2 class="post-title">
|
|
3
|
+
<a href="/blog/{{ slug }}">{{ title }}</a>
|
|
4
|
+
</h2>
|
|
5
|
+
<div class="post-meta">
|
|
6
|
+
<time datetime="{{ date }}">{{ date }}</time>
|
|
7
|
+
<span class="post-tags">{{ tags }}</span>
|
|
8
|
+
</div>
|
|
9
|
+
<p class="post-excerpt">{{ excerpt }}</p>
|
|
10
|
+
<a href="/blog/{{ slug }}" class="read-more">Читать далее →</a>
|
|
11
|
+
</article>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"posts": [
|
|
3
|
+
{
|
|
4
|
+
"title": "Первый пост: Начало работы",
|
|
5
|
+
"slug": "first-post",
|
|
6
|
+
"date": "2024-01-15",
|
|
7
|
+
"tags": "введение, начало",
|
|
8
|
+
"excerpt": "Это первый пост в моём новом блоге. Расскажу о планах и целях этого проекта.",
|
|
9
|
+
"content": "<p>Добро пожаловать в мой блог!</p><p>Здесь я буду публиковать статьи о разработке и технологиях.</p>"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"title": "Как я начал использовать статические сайты",
|
|
13
|
+
"slug": "static-sites-journey",
|
|
14
|
+
"date": "2024-01-20",
|
|
15
|
+
"tags": "статические сайты, веб-разработка",
|
|
16
|
+
"excerpt": "История о том, почему я выбрал статические генераторы сайтов вместо традиционных CMS.",
|
|
17
|
+
"content": "<p>Долгое время я использовал WordPress для своих проектов.</p><p>Но затем открыл для мир статических генераторов.</p>"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"title": "Оптимизация производительности веб-приложений",
|
|
21
|
+
"slug": "performance-optimization",
|
|
22
|
+
"date": "2024-02-01",
|
|
23
|
+
"tags": "производительность, оптимизация",
|
|
24
|
+
"excerpt": "Практические советы по ускорению загрузки страниц и улучшению Core Web Vitals.",
|
|
25
|
+
"content": "<p>Производительность — ключевой фактор пользовательского опыта.</p><p>Расскажу о методах оптимизации.</p>"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="{{ site.lang }}">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>{{ site.title }}</title>
|
|
7
|
+
<meta name="description" content="{{ site.description }}">
|
|
8
|
+
<meta name="author" content="{{ site.author }}">
|
|
9
|
+
|
|
10
|
+
<!-- SEO -->
|
|
11
|
+
<meta property="og:title" content="{{ site.title }}">
|
|
12
|
+
<meta property="og:description" content="{{ site.description }}">
|
|
13
|
+
<meta property="og:image" content="{{ seo.ogImage }}">
|
|
14
|
+
<meta property="og:type" content="{{ seo.ogType }}">
|
|
15
|
+
<link rel="canonical" href="{{ site.url }}">
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<!-- include: components/header.html -->
|
|
19
|
+
|
|
20
|
+
<!-- slot: content -->
|
|
21
|
+
|
|
22
|
+
<!-- include: components/footer.html -->
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!-- layout: layouts/base.html -->
|
|
2
|
+
|
|
3
|
+
<!-- slot: content -->
|
|
4
|
+
<main class="blog-list">
|
|
5
|
+
<h1>Все публикации</h1>
|
|
6
|
+
|
|
7
|
+
<!-- for: post in blog.posts -->
|
|
8
|
+
<article class="post-card">
|
|
9
|
+
<h2 class="post-title">
|
|
10
|
+
<a href="/blog/{{ post.slug }}">{{ post.title }}</a>
|
|
11
|
+
</h2>
|
|
12
|
+
<div class="post-meta">
|
|
13
|
+
<time datetime="{{ post.date }}">{{ post.date }}</time>
|
|
14
|
+
<span class="post-tags">{{ post.tags }}</span>
|
|
15
|
+
</div>
|
|
16
|
+
<p class="post-excerpt">{{ post.excerpt }}</p>
|
|
17
|
+
<a href="/blog/{{ post.slug }}" class="read-more">Читать далее →</a>
|
|
18
|
+
</article>
|
|
19
|
+
<!-- endfor -->
|
|
20
|
+
</main>
|
|
21
|
+
|
|
22
|
+
<!-- data-define: blog = src/data/posts.json -->
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!-- layout: layouts/base.html -->
|
|
2
|
+
|
|
3
|
+
<!-- slot: content -->
|
|
4
|
+
<article class="blog-post">
|
|
5
|
+
<header class="post-header">
|
|
6
|
+
<h1>{{ blog.title }}</h1>
|
|
7
|
+
<div class="post-meta">
|
|
8
|
+
<time datetime="{{ blog.date }}">{{ blog.date }}</time>
|
|
9
|
+
<span class="post-tags">{{ blog.tags }}</span>
|
|
10
|
+
</div>
|
|
11
|
+
</header>
|
|
12
|
+
|
|
13
|
+
<div class="post-content">
|
|
14
|
+
{{ blog.content }}
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<footer class="post-footer">
|
|
18
|
+
<a href="/blog/" class="back-link">← Все публикации</a>
|
|
19
|
+
</footer>
|
|
20
|
+
</article>
|