Update categories

This commit is contained in:
2026-02-03 15:25:23 +04:00
parent bc4cd21771
commit 0e174e0e34
9 changed files with 137 additions and 45 deletions

View File

@@ -6,9 +6,8 @@ backend:
base_url: https://stepanovplaton.ru base_url: https://stepanovplaton.ru
auth_endpoint: oauth auth_endpoint: oauth
# Явно указываем site_url для правильного формирования OAuth callback URL
# Это предотвращает добавление порта 8091 к OAuth ссылкам
site_url: https://stepanovplaton.ru site_url: https://stepanovplaton.ru
media_folder: "public/images" media_folder: "public/images"
public_folder: "/images" public_folder: "/images"
collections: collections:
@@ -39,7 +38,7 @@ collections:
- { label: "Title", name: "title", widget: "string" } - { label: "Title", name: "title", widget: "string" }
- { label: "Description", name: "description", widget: "text" } - { label: "Description", name: "description", widget: "text" }
- { label: "Image", name: "image", widget: "image", required: false } - { label: "Image", name: "image", widget: "image", required: false }
- { label: "Category", name: "category", widget: "select", options: ["library","ai","software","website","game"] } - { label: "Category", name: "category", widget: "select", options: ["proud","older","other"] }
- { label: "Tech Stack", name: "techStack", widget: "list", default: [] } - { label: "Tech Stack", name: "techStack", widget: "list", default: [] }
- { label: "Status", name: "status", widget: "select", options: ["completed","in-progress","planned"] } - { label: "Status", name: "status", widget: "select", options: ["completed","in-progress","planned"] }
- { label: "Live Demo", name: "liveDemo", widget: "string", required: false } - { label: "Live Demo", name: "liveDemo", widget: "string", required: false }
@@ -59,7 +58,7 @@ collections:
- { label: "Name", name: "name", widget: "string" } - { label: "Name", name: "name", widget: "string" }
- { label: "Description", name: "description", widget: "text" } - { label: "Description", name: "description", widget: "text" }
- { label: "Icon", name: "icon", widget: "string" } - { label: "Icon", name: "icon", widget: "string" }
- { label: "Category", name: "category", widget: "select", options: ["ai","backend","client","frontend","database","engines","tools","others"] } - { label: "Category", name: "category", widget: "select", options: ["ai","frontend","backend","native","devops","ide","tools","others"] }
- { label: "Level", name: "level", widget: "select", options: ["beginner","intermediate","advanced","expert"] } - { label: "Level", name: "level", widget: "select", options: ["beginner","intermediate","advanced","expert"] }
- label: "Experience" - label: "Experience"
name: "experience" name: "experience"

97
public/admin/index.html Normal file
View File

@@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Content Manager</title>
<script>
// КРИТИЧНО: Переопределяем window.location.origin ПЕРЕД загрузкой DecapCMS
// Это гарантирует, что DecapCMS будет использовать правильный URL без порта 8091
(function() {
const correctOrigin = 'https://stepanovplaton.ru';
const originalLocation = window.location;
// Сохраняем оригинальные значения
const originalOrigin = originalLocation.origin;
const originalHref = originalLocation.href;
// Переопределяем window.location.origin
try {
Object.defineProperty(window.location, 'origin', {
get: function() {
// Если origin содержит порт 8091, возвращаем правильный origin
if (originalOrigin.includes(':8091')) {
return correctOrigin;
}
// Иначе возвращаем оригинальный origin, но без порта если это стандартный порт
const origin = originalOrigin;
if (origin.startsWith('http://') && origin.endsWith(':8091')) {
return origin.replace(':8091', '');
}
if (origin.startsWith('https://') && origin.endsWith(':8091')) {
return origin.replace(':8091', '');
}
return origin;
},
configurable: true,
enumerable: true
});
// Также переопределяем host для полной совместимости
Object.defineProperty(window.location, 'host', {
get: function() {
const host = originalLocation.host;
if (host.includes(':8091')) {
return host.replace(':8091', '');
}
return host;
},
configurable: true,
enumerable: true
});
// Переопределяем hostname
Object.defineProperty(window.location, 'hostname', {
get: function() {
return 'stepanovplaton.ru';
},
configurable: true,
enumerable: true
});
// Переопределяем port
Object.defineProperty(window.location, 'port', {
get: function() {
return '';
},
configurable: true,
enumerable: true
});
// Переопределяем protocol
Object.defineProperty(window.location, 'protocol', {
get: function() {
return 'https:';
},
configurable: true,
enumerable: true
});
console.log('[DecapCMS Fix] Переопределен window.location.origin:', originalOrigin, '→', correctOrigin);
} catch (e) {
console.error('[DecapCMS Fix] Ошибка при переопределении location:', e);
}
})();
</script>
<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
</head>
<body>
<script>
// Проверка после загрузки
window.addEventListener('load', function() {
console.log('[DecapCMS Fix] Загружено. Текущий origin:', window.location.origin);
console.log('[DecapCMS Fix] Текущий host:', window.location.host);
});
</script>
</body>
</html>

View File

@@ -51,7 +51,7 @@ let currentTime = $state(0);
// 歌曲总时长 // 歌曲总时长
let duration = $state(0); let duration = $state(0);
// 音量 // 音量
let volume = $state(0.5); let volume = $state(0.15);
// 是否静音 // 是否静音
let isMuted = $state(false); let isMuted = $state(false);
// 是否正在加载 // 是否正在加载

View File

@@ -70,9 +70,8 @@ enum I18nKey {
projects = "projects", projects = "projects",
projectsSubtitle = "projectsSubtitle", projectsSubtitle = "projectsSubtitle",
projectsAll = "projectsAll", projectsAll = "projectsAll",
projectsWeb = "projectsWeb", projectsProud = "projectsProud",
projectsMobile = "projectsMobile", projectsOlder = "projectsOlder",
projectsDesktop = "projectsDesktop",
projectsOther = "projectsOther", projectsOther = "projectsOther",
projectTechStack = "projectTechStack", projectTechStack = "projectTechStack",
projectLiveDemo = "projectLiveDemo", projectLiveDemo = "projectLiveDemo",
@@ -95,11 +94,11 @@ enum I18nKey {
skills = "skills", skills = "skills",
skillsSubtitle = "skillsSubtitle", skillsSubtitle = "skillsSubtitle",
skillsAI = "skillsAI", skillsAI = "skillsAI",
skillsBackend = "skillsBackend",
skillsClient = "skillsClient",
skillsFrontend = "skillsFrontend", skillsFrontend = "skillsFrontend",
skillsDatabase = "skillsDatabase", skillsBackend = "skillsBackend",
skillsEngines = "skillsEngines", skillsNative = "skillsNative",
skillsDevOps = "skillsDevOps",
skillsIDE = "skillsIDE",
skillsTools = "skillsTools", skillsTools = "skillsTools",
skillsOthers = "skillsOthers", skillsOthers = "skillsOthers",
skillLevel = "skillLevel", skillLevel = "skillLevel",

View File

@@ -73,10 +73,9 @@ export const ru: Translation = {
[Key.projects]: "Проекты", [Key.projects]: "Проекты",
[Key.projectsSubtitle]: "Мое портфолио проектов", [Key.projectsSubtitle]: "Мое портфолио проектов",
[Key.projectsAll]: "Все", [Key.projectsAll]: "Все",
[Key.projectsWeb]: "Веб-приложения", [Key.projectsProud]: "Проекты, которыми я горжусь",
[Key.projectsMobile]: "Мобильные приложения", [Key.projectsOlder]: "Более старые проекты, которые показывают мой путь",
[Key.projectsDesktop]: "Десктопные приложения", [Key.projectsOther]: "Прочие начинания",
[Key.projectsOther]: "Другое",
[Key.projectTechStack]: "Технологический стек", [Key.projectTechStack]: "Технологический стек",
[Key.projectLiveDemo]: "Живая демонстрация", [Key.projectLiveDemo]: "Живая демонстрация",
[Key.projectSourceCode]: "Исходный код", [Key.projectSourceCode]: "Исходный код",
@@ -97,14 +96,14 @@ export const ru: Translation = {
// Страница навыков // Страница навыков
[Key.skills]: "Навыки", [Key.skills]: "Навыки",
[Key.skillsSubtitle]: "Мои технические навыки и экспертиза", [Key.skillsSubtitle]: "Мои технические навыки и экспертиза",
[Key.skillsAI]: "AI разработка", [Key.skillsAI]: "ИИ",
[Key.skillsBackend]: "Backend разработка", [Key.skillsFrontend]: "Frontend",
[Key.skillsClient]: "Client разработка", [Key.skillsBackend]: "Backend",
[Key.skillsFrontend]: "Frontend разработка", [Key.skillsNative]: "Native",
[Key.skillsDatabase]: "База данных", [Key.skillsDevOps]: "DevOps",
[Key.skillsEngines]: "Движки", [Key.skillsIDE]: "IDE",
[Key.skillsTools]: "Инструменты разработки", [Key.skillsTools]: "Инструменты",
[Key.skillsOthers]: "Другие навыки", [Key.skillsOthers]: "Прочее",
[Key.skillLevel]: "Уровень владения", [Key.skillLevel]: "Уровень владения",
[Key.skillLevelBeginner]: "Начинающий", [Key.skillLevelBeginner]: "Начинающий",
[Key.skillLevelIntermediate]: "Средний", [Key.skillLevelIntermediate]: "Средний",

View File

@@ -44,12 +44,10 @@ const projectsByCategory = categories.reduce(
// 获取分类文本的国际化翻译 // 获取分类文本的国际化翻译
const getCategoryText = (category: string) => { const getCategoryText = (category: string) => {
switch (category) { switch (category) {
case "web": case "proud":
return i18n(I18nKey.projectsWeb); return i18n(I18nKey.projectsProud);
case "mobile": case "older":
return i18n(I18nKey.projectsMobile); return i18n(I18nKey.projectsOlder);
case "desktop":
return i18n(I18nKey.projectsDesktop);
case "other": case "other":
return i18n(I18nKey.projectsOther); return i18n(I18nKey.projectsOther);
case UNCATEGORIZED: case UNCATEGORIZED:

View File

@@ -45,16 +45,16 @@ const getCategoryText = (category: string) => {
switch (category) { switch (category) {
case "ai": case "ai":
return i18n(I18nKey.skillsAI); return i18n(I18nKey.skillsAI);
case "server": case "frontend":
return i18n(I18nKey.skillsBackend);
case "client":
return i18n(I18nKey.skillsClient);
case "web":
return i18n(I18nKey.skillsFrontend); return i18n(I18nKey.skillsFrontend);
case "database": case "backend":
return i18n(I18nKey.skillsDatabase); return i18n(I18nKey.skillsBackend);
case "engines": case "native":
return i18n(I18nKey.skillsEngines); return i18n(I18nKey.skillsNative);
case "devops":
return i18n(I18nKey.skillsDevOps);
case "ide":
return i18n(I18nKey.skillsIDE);
case "tools": case "tools":
return i18n(I18nKey.skillsTools); return i18n(I18nKey.skillsTools);
case "others": case "others":

View File

@@ -7,7 +7,7 @@ export interface Project {
title: string; title: string;
description: string; description: string;
image: string; image: string;
category: "library" | "ai" | "software" | "website" | "game"; category: "proud" | "older" | "other";
techStack: string[]; techStack: string[];
status: "completed" | "in-progress" | "planned"; status: "completed" | "in-progress" | "planned";
demoUrl?: string; demoUrl?: string;

View File

@@ -7,7 +7,7 @@ export interface Skill {
name: string; name: string;
description: string; description: string;
icon: string; // Iconify icon name icon: string; // Iconify icon name
category: "ai" | "backend" | "client" | "frontend" | "database" | "engines" | "tools" | "others"; category: "ai" | "frontend" | "backend" | "native" | "devops" | "ide" | "tools" | "others";
level: "beginner" | "intermediate" | "advanced" | "expert"; level: "beginner" | "intermediate" | "advanced" | "expert";
experience: { experience: {
years: number; years: number;
@@ -35,12 +35,12 @@ export const getSkillStats = () => {
}; };
const byCategory = { const byCategory = {
ai: skillsData.filter((s) => s.category === "ai").length, ai: skillsData.filter((s) => s.category === "ai").length,
backend: skillsData.filter((s) => s.category === "backend").length,
client: skillsData.filter((s) => s.category === "client").length,
frontend: skillsData.filter((s) => s.category === "frontend").length, frontend: skillsData.filter((s) => s.category === "frontend").length,
database: skillsData.filter((s) => s.category === "database").length, backend: skillsData.filter((s) => s.category === "backend").length,
native: skillsData.filter((s) => s.category === "native").length,
devops: skillsData.filter((s) => s.category === "devops").length,
ide: skillsData.filter((s) => s.category === "ide").length,
tools: skillsData.filter((s) => s.category === "tools").length, tools: skillsData.filter((s) => s.category === "tools").length,
engines: skillsData.filter((s) => s.category === "engines").length,
others: skillsData.filter((s) => s.category === "others").length, others: skillsData.filter((s) => s.category === "others").length,
}; };
return { total, byLevel, byCategory }; return { total, byLevel, byCategory };