diff --git a/assets/css/style.css b/assets/css/style.css
new file mode 100644
index 0000000..f1986eb
--- /dev/null
+++ b/assets/css/style.css
@@ -0,0 +1,303 @@
+:root {
+ --bg: #f5f6fa;
+ --surface: #ffffff;
+ --text: #1c1e26;
+ --text-muted: #6b7280;
+ --accent: #4f5bd5;
+ --accent-2: #7c3aed;
+ --border: #e7e9f0;
+ --shadow: 0 10px 30px rgba(24, 28, 47, 0.06);
+ --radius: 16px;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --bg: #0f1117;
+ --surface: #171923;
+ --text: #f1f2f6;
+ --text-muted: #9ca3af;
+ --accent: #818cf8;
+ --accent-2: #a78bfa;
+ --border: #262a38;
+ --shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
+ }
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ background: var(--bg);
+ color: var(--text);
+ font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+ line-height: 1.55;
+ -webkit-font-smoothing: antialiased;
+}
+
+.container {
+ max-width: 860px;
+ margin: 0 auto;
+ padding: 0 20px 80px;
+}
+
+/* Hero */
+.hero {
+ background: linear-gradient(135deg, var(--accent), var(--accent-2));
+ padding: 64px 20px 100px;
+ color: #fff;
+}
+
+.hero-inner {
+ max-width: 860px;
+ margin: 0 auto;
+ display: flex;
+ align-items: center;
+ gap: 32px;
+ flex-wrap: wrap;
+}
+
+.avatar {
+ width: 140px;
+ height: 140px;
+ border-radius: 50%;
+ object-fit: cover;
+ border: 4px solid rgba(255, 255, 255, 0.6);
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
+ flex-shrink: 0;
+}
+
+.hero-text {
+ flex: 1;
+ min-width: 240px;
+}
+
+.hero-text h1 {
+ margin: 0 0 4px;
+ font-size: 2.1rem;
+ font-weight: 700;
+}
+
+.role {
+ font-size: 1.1rem;
+ font-weight: 500;
+ opacity: 0.92;
+ margin: 0 0 10px;
+}
+
+.meta {
+ font-size: 0.92rem;
+ opacity: 0.85;
+ margin: 0 0 18px;
+}
+
+.about {
+ max-width: 560px;
+ font-size: 0.98rem;
+ opacity: 0.95;
+ margin: 0 0 18px;
+}
+
+.contacts {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+}
+
+.contact-icon {
+ width: 42px;
+ height: 42px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0.18);
+ color: #fff;
+ text-decoration: none;
+ font-size: 1.05rem;
+ transition: background 0.15s ease, transform 0.15s ease;
+}
+
+.contact-icon:hover {
+ background: rgba(255, 255, 255, 0.32);
+ transform: translateY(-2px);
+ color: #fff;
+}
+
+/* Content cards */
+.card {
+ background: var(--surface);
+ border: 1px solid var(--border);
+ border-radius: var(--radius);
+ box-shadow: var(--shadow);
+ padding: 28px 30px;
+ margin-top: -48px;
+ position: relative;
+ z-index: 2;
+}
+
+.card + .card {
+ margin-top: 24px;
+}
+
+.card h2 {
+ font-size: 1.25rem;
+ margin: 0 0 20px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.card h2 i {
+ color: var(--accent);
+ font-size: 1.05rem;
+}
+
+/* Skills */
+.skills {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+
+.skill-group:last-child {
+ margin-bottom: 0;
+}
+
+.skill-category {
+ font-size: 0.8rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.03em;
+ color: var(--text-muted);
+ margin-bottom: 8px;
+}
+
+.skill-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.skill-tag {
+ background: color-mix(in srgb, var(--accent) 12%, transparent);
+ color: var(--accent);
+ border-radius: 999px;
+ padding: 6px 14px;
+ font-size: 0.85rem;
+ font-weight: 500;
+}
+
+/* Timeline */
+.timeline {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.timeline-item {
+ display: grid;
+ grid-template-columns: 170px 1fr;
+ gap: 16px;
+ padding: 14px 0;
+ border-bottom: 1px solid var(--border);
+}
+
+.timeline-item:last-child {
+ border-bottom: none;
+}
+
+.timeline-period {
+ color: var(--text-muted);
+ font-size: 0.85rem;
+ font-weight: 600;
+ padding-top: 2px;
+}
+
+.timeline-title {
+ font-weight: 600;
+ font-size: 0.98rem;
+}
+
+.timeline-place {
+ color: var(--text-muted);
+ font-size: 0.9rem;
+ margin-top: 2px;
+}
+
+.timeline-item.is-current .timeline-period {
+ color: var(--accent);
+}
+
+/* Projects */
+.projects {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
+ gap: 16px;
+}
+
+.project-card {
+ display: block;
+ background: var(--bg);
+ border: 1px solid var(--border);
+ border-radius: 12px;
+ padding: 18px 20px;
+ text-decoration: none;
+ color: var(--text);
+ transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
+}
+
+.project-card:hover {
+ transform: translateY(-3px);
+ box-shadow: var(--shadow);
+ border-color: var(--accent);
+}
+
+.project-title {
+ font-weight: 600;
+ margin-bottom: 6px;
+ color: var(--text);
+}
+
+.project-desc {
+ font-size: 0.88rem;
+ color: var(--text-muted);
+ margin-bottom: 10px;
+}
+
+.project-link {
+ font-size: 0.85rem;
+ font-weight: 600;
+ color: var(--accent);
+}
+
+/* Footer */
+.footer {
+ text-align: center;
+ color: var(--text-muted);
+ font-size: 0.82rem;
+ padding: 30px 20px 0;
+}
+
+@media (max-width: 600px) {
+ .hero {
+ padding: 48px 16px 90px;
+ text-align: center;
+ }
+ .hero-inner {
+ flex-direction: column;
+ text-align: center;
+ }
+ .contacts {
+ justify-content: center;
+ }
+ .card {
+ padding: 22px 18px;
+ margin-top: -40px;
+ }
+ .timeline-item {
+ grid-template-columns: 1fr;
+ gap: 4px;
+ }
+}
diff --git a/assets/js/data.js b/assets/js/data.js
new file mode 100644
index 0000000..a3f17e3
--- /dev/null
+++ b/assets/js/data.js
@@ -0,0 +1,133 @@
+/*
+ * Все данные визитки собраны здесь.
+ * Чтобы добавить новую запись — просто скопируй похожий объект внутри
+ * соответствующего массива и поменяй текст. Ничего в других файлах трогать не нужно.
+ * Поле "current: true" у опыта/образования подсветит запись как текущую.
+ */
+
+const SITE_DATA = {
+ profile: {
+ name: "Георгий Хатунцев",
+ role: "Программист",
+ avatar: "img/avatar.png",
+ gender: "Мужской",
+ birthDate: "1993-02-20", // возраст в шапке считается от этой даты автоматически
+ location: "Нижний Тагил, Россия",
+ // Короткое описание под именем. Можно оставить пустым: about: ""
+ about:
+ "Разработчик со опытом в промышленной автоматизации, системном администрировании и веб-разработке.",
+ },
+
+ // Контакты — иконка берётся из Font Awesome (класс), ссылка — куда ведёт.
+ contacts: [
+ { icon: "fas fa-phone", label: "Телефон", href: "tel:+79122161573" },
+ { icon: "fas fa-envelope", label: "Email", href: "mailto:google_12345@mail.ru" },
+ { icon: "fab fa-telegram", label: "Telegram", href: "https://t.me/google_12345" },
+ { icon: "fab fa-discord", label: "Discord", href: "https://discord.com/users/337960071940276224" },
+ { icon: "fab fa-git-alt", label: "Git", href: "https://git.khatuncev.ru/" },
+ ],
+
+ // Навыки сгруппированы по категориям. Чтобы добавить категорию — скопируй объект.
+ // Чтобы добавить навык — допиши строку в нужный items. Если весь массив пуст — секция не отображается.
+ skills: [
+ {
+ category: "Языки программирования",
+ items: ["Watcom C", "C", "C++", "C#", "Java (Spring)", "Go"],
+ },
+ {
+ category: "Frontend",
+ items: ["HTML", "CSS", "JavaScript", "Vue 3", "Bootstrap", "Bulma", "Tailwind"],
+ },
+ {
+ category: "Скриптинг",
+ items: ["Bash / Shell", "Python"],
+ },
+ {
+ category: "Администрирование и инфраструктура",
+ items: ["Nginx", "Apache", "Caddy", "Samba", "DHCPd", "Dnsmasq", "BIND (named)", "Kerberos (krb5)"],
+ },
+ ],
+
+ education: [
+ {
+ title: "Радио-технический факультет, специальность «Программная инженерия» (магистр)",
+ place: "Уральский федеральный университет имени первого Президента России Б.Н. Ельцина, Екатеринбург",
+ period: "2021",
+ },
+ {
+ title: "Радио-технический факультет, специальность «Информационные системы и технологии» (бакалавр)",
+ place: "Уральский федеральный университет имени первого Президента России Б.Н. Ельцина, Екатеринбург",
+ period: "2019",
+ },
+ ],
+
+ experience: [
+ {
+ title: "Инженер-программист",
+ place: 'ООО «Амбрелла»',
+ period: "2025 — настоящее время",
+ current: true,
+ },
+ {
+ title: "Инженер-программист",
+ place: 'ООО «Инсайрес»',
+ period: "2024 — 2025",
+ },
+ {
+ title: "Системный администратор",
+ place: 'МБУ «Централизованная бухгалтерия образовательных учреждений» г. Верхняя Салда',
+ period: "2022 — 2024",
+ },
+ {
+ title: "Программист",
+ place: "IntelliCAD Technology Consortium",
+ period: "2022 — 2024",
+ },
+ {
+ title: "Инженер-программист",
+ place: 'ООО Компания «Тензор»',
+ period: "2021 — 2022",
+ },
+ {
+ title: "Инженер-программист",
+ place: 'ПАО «Корпорация ВСМПО-АВИСМА» г. Верхняя Салда',
+ period: "2017 — 2021",
+ },
+ {
+ title: "Техник",
+ place: 'ПАО «Корпорация ВСМПО-АВИСМА» г. Верхняя Салда',
+ period: "2015 — 2017",
+ },
+ {
+ title: "Системный администратор",
+ place: 'МБУ «Централизованная бухгалтерия образовательных учреждений» г. Верхняя Салда',
+ period: "2014-2015",
+ },
+ {
+ title: "Индивидуальный предприниматель",
+ place: "",
+ period: "2012 — 2014",
+ },
+ ],
+
+ projects: [
+ {
+ title: "Текущий статус вакуумно-дуговых печей",
+ href: "https://khatuncev.ru/demo1",
+ description:
+ "Визуальное представление текущего процесса плавки в вакуумно-дуговых печах. Весь цикл представлен в виде гистограммы.",
+ },
+ {
+ title: "Рабочее место технолога",
+ href: "https://khatuncev.ru/demo2",
+ description:
+ "Визуальное представление паспортов титановых слитков и аналого-дискретных сигналов вакуумно-дуговых печей в процессе плавки.",
+ },
+ {
+ title: "AdvancedXL",
+ href: "https://advancedxl.ru/",
+ description:
+ "Аналитическая надстройка для Microsoft Excel, которая ускоряет работу с таблицами, формулами и финансовыми моделями в 5 и более раз.",
+ },
+ ],
+};
diff --git a/assets/js/main.js b/assets/js/main.js
new file mode 100644
index 0000000..5711944
--- /dev/null
+++ b/assets/js/main.js
@@ -0,0 +1,115 @@
+function el(tag, className, html) {
+ const node = document.createElement(tag);
+ if (className) node.className = className;
+ if (html !== undefined) node.innerHTML = html;
+ return node;
+}
+
+function calcAge(birthDateStr) {
+ const birth = new Date(birthDateStr);
+ const today = new Date();
+ let age = today.getFullYear() - birth.getFullYear();
+ const monthDiff = today.getMonth() - birth.getMonth();
+ if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birth.getDate())) {
+ age--;
+ }
+ return age;
+}
+
+function pluralizeYears(age) {
+ const mod10 = age % 10;
+ const mod100 = age % 100;
+ if (mod10 === 1 && mod100 !== 11) return `${age} год`;
+ if ([2, 3, 4].includes(mod10) && ![12, 13, 14].includes(mod100)) return `${age} года`;
+ return `${age} лет`;
+}
+
+function renderProfile(data) {
+ document.title = `${data.profile.role} ${data.profile.name}`;
+ document.getElementById("avatar").src = data.profile.avatar;
+ document.getElementById("avatar").alt = data.profile.name;
+ document.getElementById("name").textContent = data.profile.name;
+ document.getElementById("role").textContent = data.profile.role;
+
+ const metaParts = [];
+ if (data.profile.gender) metaParts.push(data.profile.gender);
+ if (data.profile.birthDate) metaParts.push(pluralizeYears(calcAge(data.profile.birthDate)));
+ if (data.profile.location) metaParts.push(data.profile.location);
+ document.getElementById("meta").textContent = metaParts.join(" · ");
+
+ const aboutEl = document.getElementById("about");
+ if (data.profile.about) {
+ aboutEl.textContent = data.profile.about;
+ } else {
+ aboutEl.remove();
+ }
+}
+
+function renderContacts(data) {
+ const wrap = document.getElementById("contacts");
+ data.contacts.forEach((c) => {
+ const a = el("a", "contact-icon", ` `);
+ a.href = c.href;
+ a.title = c.label;
+ a.target = c.href.startsWith("http") ? "_blank" : "_self";
+ a.rel = "noopener";
+ wrap.appendChild(a);
+ });
+}
+
+function renderSkills(data) {
+ const section = document.getElementById("skills-section");
+ const hasSkills = data.skills && data.skills.some((g) => g.items && g.items.length);
+ if (!hasSkills) {
+ section.remove();
+ return;
+ }
+ const wrap = document.getElementById("skills");
+ data.skills.forEach((group) => {
+ if (!group.items || group.items.length === 0) return;
+ const groupEl = el("div", "skill-group");
+ groupEl.appendChild(el("div", "skill-category", group.category));
+ const tags = el("div", "skill-tags");
+ group.items.forEach((item) => tags.appendChild(el("span", "skill-tag", item)));
+ groupEl.appendChild(tags);
+ wrap.appendChild(groupEl);
+ });
+}
+
+function renderTimeline(containerId, items) {
+ const wrap = document.getElementById(containerId);
+ items.forEach((item) => {
+ const entry = el("div", "timeline-item" + (item.current ? " is-current" : ""));
+ entry.appendChild(el("div", "timeline-period", item.period));
+ const body = el("div", "timeline-body");
+ body.appendChild(el("div", "timeline-title", item.title));
+ if (item.place) body.appendChild(el("div", "timeline-place", item.place));
+ entry.appendChild(body);
+ wrap.appendChild(entry);
+ });
+}
+
+function renderProjects(data) {
+ const wrap = document.getElementById("projects");
+ data.projects.forEach((p) => {
+ const card = el("a", "project-card");
+ card.href = p.href;
+ card.target = "_blank";
+ card.rel = "noopener";
+ card.appendChild(el("div", "project-title", p.title));
+ if (p.description) card.appendChild(el("div", "project-desc", p.description));
+ card.appendChild(el("div", "project-link", "Открыть проект →"));
+ wrap.appendChild(card);
+ });
+}
+
+(function init() {
+ renderProfile(SITE_DATA);
+ renderContacts(SITE_DATA);
+ renderSkills(SITE_DATA);
+ renderTimeline("education", SITE_DATA.education);
+ renderTimeline("experience", SITE_DATA.experience);
+ renderProjects(SITE_DATA);
+ document.getElementById("footer").textContent =
+ `© ${new Date().getFullYear()} ${SITE_DATA.profile.name}`;
+})();
diff --git a/index.html b/index.html
index 6d9f616..980bf10 100644
--- a/index.html
+++ b/index.html
@@ -3,80 +3,55 @@
- Программист Георгий Хатунцев
-
-
-
-
+ Визитка
+
+
+
+
-
+
-
-
-
-
-
-
-
Георгий Хатунцев
-
Пол: Мужской
-
Возраст: 30 лет
-
+
+
+
+
+
-
Образование
-
- Уральский федеральный университет имени первого Президента России Б.Н. Ельцина, Екатеринбург, Радио-технический факультет, специальность Программная Инженерия (магистр) (2021 год)
- Уральский федеральный университет имени первого Президента России Б.Н. Ельцина, Екатеринбург, Радио-технический факультет,специальность Информационные системы и технологии (бакалавр) (2019 год)
-
+
- Опыт работы
-
- МБУ "Централизованная бухгалтерия образовательны учреждений" г. Верхняя Салда (Системный администратор, 2022 - 2024)
- IntelliCAD Technology Consortium (Программист, 2022 - 2024)
- ООО Компания "Тензор" (Инженер-программист, 2021 - 2022)
- ПАО "Корпорация ВСМПО-АВИСМА" г. Верхняя Салда (Инженер-программист, 2017-2021)
- ПАО "Корпорация ВСМПО-АВИСМА" г. Верхняя Салда (Техник, 2015 - 2017)
- МБУ "Централизованная бухгалтерия образовательны учреждений" г. Верхняя Салда (Системный администратор, 2015)
- Индивидуальный предприниматель (2012 - 2014)
-
+
- Проекты
-
- Текущий статус вакуумно-дуговых печей - Визуальное представление текущего процесса плавки в вакуумно-дуговых печах. Весь цикл представлен в виде гистограммы.
- Рабочее Место Технолога - Визуальное представление паспортов титановых слитков и аналого-дискретных сигналов вакуумно-дуговых печей в процесса плавки.
-
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+