studio/src/utils/kubikonTheme.js
МИН 31adbf151b Initial public release: Студия Рублокса v1.0
Open-source веб-студия для создания игр Рублокса, двойная лицензия
AGPL-3.0 + Коммерческая.

Главное:
- Vite 5 + React 18 + Babylon 7.54.3 + Monaco Editor + Colyseus 0.16
- Самодостаточный движок ~28к строк (66 файлов): BlockManager,
  TerrainVoxelBuilder, ModelManager, DecoManager, PlayerController,
  ScriptSandboxWorker, MultiplayerSync, 30+ GD-гейммодов
- Главный редактор KubikonEditor (~37к строк) + панели, ScriptEditor (Monaco)
- Витрина игр (KubikonFeed, KubikonStudio, KubikonDocs, KubikonLearn)
- Geometry Dash sub-app (GdMenu, GdShop, GdRules, GdCoverArt)
- 10 admin-preview каталогов для дизайнеров (скины, музыка, порталы и т.д.)
- Конфигурируемый бэкенд через VITE_API_BASE — работает со staging
  (dev-api.rublox.pro) без настройки
- Standalone-режим (VITE_STANDALONE=true) — открыть пустой редактор без бэка
- Полная документация (на русском): README, ARCHITECTURE, CONTRIBUTING,
  SECURITY, CHANGELOG
- ESLint + Prettier + EditorConfig
- Legal: LICENSE (AGPL-3.0), LICENSE-COMMERCIAL.md, CLA.md, COPYRIGHT.md
- Issue templates: bug_report, feature_request, security_disclosure

Перед публикацией:
- Все импорты из minecraftia заменены на локальные
- Все хардкоды URL (minecraftia-school.ru) и внутренних IP убраны → env
- Admin-эндпоинты Kubikon3DService вырезаны (остаются в приватном репо)
- AdminKubikonModeration не публикуется (модерация — в team.rublox.pro)
- 93 МБ ассетов public/kubikon-assets вынесены в .gitignore
  (раздаются через release artifact)
2026-05-27 23:41:10 +03:00

235 lines
8.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Рублокс — современная light-тема (Roblox/Discord/Apple Music style).
*
* Палитра построена вокруг логотипа A02 — синий #3357ff.
* Используется в KubikonFeed, KubikonGamePage и связанных модалках.
*/
export const KT = {
// === Фон ===
bg: '#f5f7fb',
bgPage: '#ffffff',
bgHover: '#f1f5f9',
bgMuted: '#f3f4f6',
bgSubtle: '#fafbfd',
// Стеклянный фон (для glassmorphism)
glass: 'rgba(255, 255, 255, 0.65)',
glassDark: 'rgba(255, 255, 255, 0.85)',
// Границы
border: '#e5e7eb',
borderStrong: '#cbd5e1',
borderSoft: '#eef2f7',
// === Текст ===
text: '#0f172a',
textSecondary:'#475569',
textMuted: '#94a3b8',
// === Акцент: Рублокс синий из логотипа A02 ===
accent: '#3357ff',
accentHover: '#2540d8',
accentSoft: '#e0e8ff',
accentDeep: '#1e2da5',
// === Дополнительные цвета бренда (для градиентов и hot-меток) ===
pink: '#ec4899',
violet: '#8b5cf6',
cyan: '#06b6d4',
lime: '#84cc16',
gold: '#f59e0b',
// === Семантика ===
danger: '#ef4444',
dangerLight: '#fef2f2',
warning: '#f59e0b',
warningLight: '#fffbeb',
success: '#10b981',
successLight: '#ecfdf5',
info: '#0ea5e9',
infoLight: '#f0f9ff',
// === Тени (Apple-style мягкие) ===
shadowSm: '0 1px 2px rgba(15, 23, 42, 0.04)',
shadow: '0 1px 3px rgba(15, 23, 42, 0.06), 0 2px 6px rgba(15, 23, 42, 0.04)',
shadowMd: '0 4px 16px rgba(15, 23, 42, 0.08), 0 2px 6px rgba(15, 23, 42, 0.04)',
shadowLg: '0 12px 32px rgba(15, 23, 42, 0.12), 0 6px 12px rgba(15, 23, 42, 0.06)',
shadowXl: '0 24px 48px rgba(15, 23, 42, 0.16), 0 12px 24px rgba(15, 23, 42, 0.08)',
shadowGlow: '0 0 0 4px rgba(51, 87, 255, 0.18)',
shadowAccent: '0 8px 24px rgba(51, 87, 255, 0.32)',
// === Радиусы ===
radius: 10,
radiusLg: 14,
radiusXl: 20,
radius2xl: 28,
// === Шрифт ===
font: '"Roboto Condensed", system-ui, -apple-system, sans-serif',
// === Главные градиенты (для hero, кнопок, badges) ===
gradientBrand: 'linear-gradient(135deg, #3357ff 0%, #1e2da5 100%)',
gradientHot: 'linear-gradient(135deg, #ec4899 0%, #ef4444 50%, #f59e0b 100%)',
gradientCool: 'linear-gradient(135deg, #06b6d4 0%, #3357ff 100%)',
gradientPurple: 'linear-gradient(135deg, #8b5cf6 0%, #3357ff 100%)',
gradientHero: 'linear-gradient(135deg, #3357ff 0%, #6d28d9 50%, #ec4899 100%)',
};
/** Hover-состояние карточки игры (3D-tilt + lift). */
export const cardStyle = (hovered) => ({
background: KT.bgPage,
border: `1px solid ${hovered ? KT.accent : KT.border}`,
borderRadius: KT.radiusLg,
boxShadow: hovered ? KT.shadowLg : KT.shadow,
transform: hovered ? 'translateY(-6px) scale(1.02)' : 'translateY(0) scale(1)',
transition: 'all 280ms cubic-bezier(0.34, 1.56, 0.64, 1)',
cursor: 'pointer',
overflow: 'hidden',
willChange: 'transform',
});
/** Кнопка-первичная: синий градиент, мягкая тень, при hover — приподнимается. */
export const buttonPrimary = (hovered) => ({
padding: '12px 22px',
background: hovered
? 'linear-gradient(135deg, #2540d8 0%, #1e2da5 100%)'
: KT.gradientBrand,
color: '#fff',
border: 'none',
borderRadius: KT.radius,
fontSize: 14,
fontWeight: 700,
cursor: 'pointer',
fontFamily: KT.font,
boxShadow: hovered
? '0 12px 28px rgba(51, 87, 255, 0.40)'
: '0 4px 12px rgba(51, 87, 255, 0.24)',
transform: hovered ? 'translateY(-2px) scale(1.02)' : 'translateY(0) scale(1)',
transition: 'all 200ms cubic-bezier(0.34, 1.56, 0.64, 1)',
letterSpacing: 0.3,
});
/** Кнопка-вторичная (нейтральная белая). */
export const buttonSecondary = (hovered) => ({
padding: '10px 18px',
background: hovered ? KT.bgHover : KT.bgPage,
color: KT.text,
border: `1px solid ${hovered ? KT.borderStrong : KT.border}`,
borderRadius: KT.radius,
fontSize: 13,
fontWeight: 600,
cursor: 'pointer',
fontFamily: KT.font,
transition: 'all 150ms ease',
});
/** Чип-фильтр (pill). */
export const chipStyle = (active) => ({
padding: '8px 16px',
background: active ? KT.accent : KT.bgPage,
color: active ? '#fff' : KT.textSecondary,
border: `1px solid ${active ? KT.accent : KT.border}`,
borderRadius: 999,
fontSize: 13,
fontWeight: 600,
cursor: 'pointer',
fontFamily: KT.font,
transition: 'all 200ms cubic-bezier(0.34, 1.56, 0.64, 1)',
whiteSpace: 'nowrap',
boxShadow: active ? '0 4px 12px rgba(51, 87, 255, 0.28)' : 'none',
transform: active ? 'translateY(-1px)' : 'translateY(0)',
});
/** Глобальные keyframes — один раз на страницу. */
export const KUBIKON_KEYFRAMES = `
@keyframes kubikonFadeIn {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes kubikonFadeInScale {
from { opacity: 0; transform: scale(0.94); }
to { opacity: 1; transform: scale(1); }
}
@keyframes kubikonShimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
@keyframes kubikonPulseGlow {
0%, 100% { box-shadow: 0 8px 24px rgba(51, 87, 255, 0.32); }
50% { box-shadow: 0 8px 24px rgba(51, 87, 255, 0.32),
0 0 0 12px rgba(51, 87, 255, 0.08); }
}
@keyframes kubikonHeroSlide {
from { opacity: 0; transform: translateY(24px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes kubikonGradientShift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
@keyframes kubikonFloat {
0%, 100% { transform: translateY(0) rotate(0deg); }
33% { transform: translateY(-12px) rotate(3deg); }
66% { transform: translateY(8px) rotate(-2deg); }
}
@keyframes kubikonSpin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes kubikonHotPulse {
0%, 100% { transform: scale(1) rotate(-3deg); }
50% { transform: scale(1.08) rotate(-3deg); }
}
@keyframes kubikonFloatY {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
@keyframes kubikonFadeInUp {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes kubikonPulseRing {
0%, 100% { box-shadow: 0 0 0 0 rgba(255, 215, 0, 0.55); }
50% { box-shadow: 0 0 0 14px rgba(255, 215, 0, 0); }
}
@keyframes kubikonGlow {
0%, 100% { filter: drop-shadow(0 0 8px currentColor); }
50% { filter: drop-shadow(0 0 24px currentColor); }
}
@keyframes kubikonRotateY {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes kubikonShimmerText {
0% { background-position: 0% 50%; }
100% { background-position: 200% 50%; }
}
@keyframes kubikonBgPulse {
0%, 100% { opacity: 0.8; transform: scale(1); }
50% { opacity: 1; transform: scale(1.05); }
}
@keyframes kubikonParticleFloat {
0% { transform: translateY(0) translateX(0) rotate(0deg); opacity: 0; }
15% { opacity: 0.7; }
85% { opacity: 0.7; }
100% { transform: translateY(-120px) translateX(30px) rotate(180deg); opacity: 0; }
}
`;
/** Skeleton-блок с волной shimmer. */
export const skeletonStyle = (extra = {}) => ({
background:
`linear-gradient(90deg, ${KT.bgMuted} 0%, ${KT.bgHover} 50%, ${KT.bgMuted} 100%)`,
backgroundSize: '200% 100%',
animation: 'kubikonShimmer 1.6s ease-in-out infinite',
borderRadius: KT.radius,
...extra,
});