studio/src/editor/TopRibbon.module.css
МИН 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

298 lines
6.1 KiB
CSS
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.

/* === TopRibbon — тёмный стиль Рублокс Studio === */
.ribbon {
display: flex;
flex-direction: column;
background: var(--bg-dark);
border-bottom: 1px solid var(--border);
flex-shrink: 0;
user-select: none;
width: 100%;
max-width: 100%;
overflow: hidden;
font-family: "Roboto Condensed", system-ui, -apple-system, sans-serif;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}
/* === Вкладки === */
.tabs {
display: flex;
background: var(--bg-darkest);
border-bottom: 1px solid var(--border);
padding: 0 12px;
gap: 2px;
}
.tab {
background: transparent;
border: none;
color: var(--text-dim);
padding: 10px 18px;
font-size: 13px;
font-weight: 700;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 200ms ease;
margin-right: 2px;
font-family: inherit;
letter-spacing: 0.1px;
}
.tab:hover {
color: var(--text);
background: var(--bg-mid);
}
.tabActive {
color: var(--accent-bright);
border-bottom-color: var(--accent-bright);
background: var(--bg-mid);
font-weight: 800;
}
.tabActive:hover {
background: var(--bg-mid);
}
.tabIcon {
margin-right: 6px;
}
/* === Ribbon body — лента кнопок === */
.body {
display: flex;
align-items: stretch;
gap: 0;
padding: 8px 4px;
height: 96px;
overflow-x: auto;
overflow-y: hidden;
background: var(--bg-dark);
}
/* === Группа кнопок с подписью === */
.group {
display: flex;
flex-direction: column;
padding: 0 14px;
border-right: 1px solid var(--border);
align-items: center;
justify-content: space-between;
}
.group:last-child {
border-right: none;
}
.groupBody {
display: flex;
gap: 4px;
align-items: center;
flex: 1;
}
.groupTitle {
font-size: 10px;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 1.2px;
margin-top: 4px;
text-align: center;
font-weight: 800;
}
/* === Кнопка ribbon (иконка + подпись) === */
.ribbonBtn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 4px;
padding: 6px 10px;
min-width: 60px;
height: 60px;
background: transparent;
border: 1px solid transparent;
border-radius: 10px;
color: var(--text);
cursor: pointer;
transition: all 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
font-family: inherit;
}
.ribbonBtn:hover:not(:disabled) {
background: var(--bg-light);
border-color: var(--border);
transform: translateY(-1px);
}
.ribbonBtn:disabled {
opacity: 0.35;
cursor: not-allowed;
}
.btnActive {
background: linear-gradient(135deg, var(--accent) 0%, var(--accent2) 100%) !important;
border-color: transparent !important;
color: #fff !important;
box-shadow: 0 6px 16px rgba(79, 116, 255, 0.45);
transform: translateY(-1px);
}
.btnActive:hover {
background: linear-gradient(135deg, var(--accent-bright) 0%, var(--accent2) 100%) !important;
transform: translateY(-2px);
box-shadow: 0 10px 24px rgba(79, 116, 255, 0.55);
}
.btnDanger {
color: #ff6b6b;
}
.btnDanger:hover:not(:disabled) {
background: rgba(239, 68, 68, 0.16) !important;
border-color: rgba(239, 68, 68, 0.4) !important;
color: #ff6b6b;
}
.btnIcon {
font-size: 22px;
line-height: 1;
}
.btnLabel {
font-size: 10px;
line-height: 1.2;
text-align: center;
white-space: nowrap;
font-weight: 700;
letter-spacing: 0.1px;
}
/* === Snap-секция === */
.snapBox {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
padding: 8px 0;
}
.snapLabel {
font-size: 10px;
color: var(--text-dim);
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 800;
}
.snapButtons {
display: flex;
gap: 4px;
background: var(--bg-darkest);
padding: 3px;
border-radius: 999px;
}
.snapBtn {
background: transparent;
border: none;
border-radius: 999px;
color: var(--text-dim);
font-size: 12px;
font-weight: 700;
padding: 5px 11px;
cursor: pointer;
min-width: 36px;
transition: all 200ms ease;
font-family: inherit;
}
.snapBtn:hover {
background: rgba(79, 116, 255, 0.16);
color: var(--accent-bright);
}
.snapBtnActive {
background: linear-gradient(135deg, var(--accent) 0%, var(--accent2) 100%);
color: #fff;
box-shadow: 0 4px 10px rgba(79, 116, 255, 0.36);
}
.snapBtnActive:hover {
background: linear-gradient(135deg, var(--accent) 0%, var(--accent2) 100%);
color: #fff;
}
/* === Dropdown в TopRibbon === */
.dropdownWrap {
position: relative;
display: inline-flex;
cursor: pointer;
}
.dropdownMenu {
position: fixed;
min-width: 220px;
max-width: 360px;
max-height: 320px;
overflow-y: auto;
background: var(--bg-dark);
border: 1px solid var(--border);
border-radius: 12px;
box-shadow: 0 16px 40px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(79, 116, 255, 0.12);
z-index: 9999;
padding: 6px;
font-family: inherit;
color: var(--text);
}
.dropdownList {
display: flex;
flex-direction: column;
gap: 2px;
}
.dropdownGrid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
min-width: 220px;
}
.dropdownItem {
display: block;
width: 100%;
background: transparent;
border: 1px solid transparent;
border-radius: 8px;
padding: 9px 12px;
color: var(--text);
font-size: 13px;
font-weight: 600;
text-align: left;
cursor: pointer;
transition: all 150ms ease;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-family: inherit;
}
.dropdownItem:hover {
background: var(--bg-light);
color: var(--accent-bright);
}
.dropdownItemActive {
background: linear-gradient(135deg, var(--accent) 0%, var(--accent2) 100%);
color: #fff;
font-weight: 800;
box-shadow: 0 4px 10px rgba(79, 116, 255, 0.36);
}
.dropdownItemActive:hover {
background: linear-gradient(135deg, var(--accent) 0%, var(--accent2) 100%);
color: #fff;
}