mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
pride gay theme yay
This commit is contained in:
+6
-1
@@ -1,4 +1,9 @@
|
|||||||
1. allow private rover replays for people who are allowed to drive them
|
1. pride month themeing (and forever probably)
|
||||||
|
1. in the background of the web UI
|
||||||
|
1. slightly wider gaps between cards
|
||||||
|
2. pride flag background, vertical stripes
|
||||||
|
3. add toggle to disable it that doesnt work or crashes the page lol
|
||||||
|
2. redo logo in inkscape, make it gay
|
||||||
2. add faster way for admins to login, like an invisible button in top left or something
|
2. add faster way for admins to login, like an invisible button in top left or something
|
||||||
3. add discord bot typing thing for when someone requests a replay
|
3. add discord bot typing thing for when someone requests a replay
|
||||||
4. change replay title for ones requested from discord, something other than "requester driving rover"
|
4. change replay title for ones requested from discord, something other than "requester driving rover"
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -11,8 +11,8 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
<meta name="apple-mobile-web-app-title" content="Roomba Rover" />
|
<meta name="apple-mobile-web-app-title" content="Roomba Rover" />
|
||||||
<title>Roomba Rover</title>
|
<title>Roomba Rover</title>
|
||||||
<script type="module" crossorigin src="/assets/index-DC5PqMFo.js"></script>
|
<script type="module" crossorigin src="/assets/index-BwoVmbyy.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CIj_suyF.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-0REyzzxs.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
+19
-18
@@ -43,6 +43,7 @@ import { useSessionSelector } from './context/SessionContext.jsx';
|
|||||||
import ButtonBoxPanel from './components/ButtonBoxPanel/index.jsx';
|
import ButtonBoxPanel from './components/ButtonBoxPanel/index.jsx';
|
||||||
import RewardRunOverlay from './components/RewardRunOverlay/index.jsx';
|
import RewardRunOverlay from './components/RewardRunOverlay/index.jsx';
|
||||||
import SocketConnectionPill from './components/SocketConnectionPill/index.jsx';
|
import SocketConnectionPill from './components/SocketConnectionPill/index.jsx';
|
||||||
|
import { pageBackgroundClass, themeGapClass, themeStackClass } from './themeFlags.js';
|
||||||
|
|
||||||
function useLayoutMode() {
|
function useLayoutMode() {
|
||||||
const [mode, setMode] = useState(() => {
|
const [mode, setMode] = useState(() => {
|
||||||
@@ -76,13 +77,13 @@ function useLayoutMode() {
|
|||||||
|
|
||||||
function DesktopLayout({ layout, onOpenHelpOverlay }) {
|
function DesktopLayout({ layout, onOpenHelpOverlay }) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full gap-0.5 overflow-hidden">
|
<div className={`flex h-full ${themeGapClass} overflow-hidden`}>
|
||||||
<div className="flex min-w-0 flex-[1.22] flex-col gap-0.5 overflow-y-auto pr-0">
|
<div className={`flex min-w-0 flex-[1.22] flex-col ${themeGapClass} overflow-y-auto pr-0`}>
|
||||||
<DriverVideo />
|
<DriverVideo />
|
||||||
<TelemetryPanel />
|
<TelemetryPanel />
|
||||||
<LogPanel />
|
<LogPanel />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex min-w-0 flex-1 flex-col gap-0.5 overflow-y-auto">
|
<div className={`flex min-w-0 flex-1 flex-col ${themeGapClass} overflow-y-auto`}>
|
||||||
<GlobalObjectiveBanner layout={layout} />
|
<GlobalObjectiveBanner layout={layout} />
|
||||||
<RightPaneTabs layout={layout} onOpenHelpOverlay={onOpenHelpOverlay} />
|
<RightPaneTabs layout={layout} onOpenHelpOverlay={onOpenHelpOverlay} />
|
||||||
{/* <SessionSnapshot /> */}
|
{/* <SessionSnapshot /> */}
|
||||||
@@ -123,7 +124,7 @@ function MobileFeatureTabs({
|
|||||||
ownAudioForward?.state === 'playing',
|
ownAudioForward?.state === 'playing',
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<section className="panel text-base">
|
<section className="text-base">
|
||||||
<Tabs defaultTab="chat" currentTab={activeTab} onTabChange={setActiveTab}>
|
<Tabs defaultTab="chat" currentTab={activeTab} onTabChange={setActiveTab}>
|
||||||
<TabList>
|
<TabList>
|
||||||
<Tab id="chat">Chat</Tab>
|
<Tab id="chat">Chat</Tab>
|
||||||
@@ -143,13 +144,13 @@ function MobileFeatureTabs({
|
|||||||
</TabList>
|
</TabList>
|
||||||
<TabPanels>
|
<TabPanels>
|
||||||
<TabPanel id="chat">
|
<TabPanel id="chat">
|
||||||
<div className="space-y-0.5">
|
<div className={themeStackClass}>
|
||||||
<ChatPanel nicknameLayout="stacked" />
|
<ChatPanel nicknameLayout="stacked" />
|
||||||
<div className="space-y-0.5">
|
<div className={themeStackClass}>
|
||||||
<div className="grid gap-0.5 md:grid-cols-[minmax(0,1.4fr)_minmax(0,1fr)]">
|
<div className={`grid ${themeGapClass} md:grid-cols-[minmax(0,1.4fr)_minmax(0,1fr)]`}>
|
||||||
<SocialButtonsGrid />
|
<SocialButtonsGrid />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-0.5 grid-cols-[minmax(0,1fr)_minmax(0,1fr)]">
|
<div className={`grid ${themeGapClass} grid-cols-[minmax(0,1fr)_minmax(0,1fr)]`}>
|
||||||
<OverseerPreferencePanel />
|
<OverseerPreferencePanel />
|
||||||
<RawUserPilePanel hideNicknameForm />
|
<RawUserPilePanel hideNicknameForm />
|
||||||
</div>
|
</div>
|
||||||
@@ -160,7 +161,7 @@ function MobileFeatureTabs({
|
|||||||
<VipPanel isActive={activeTab === 'vip'} />
|
<VipPanel isActive={activeTab === 'vip'} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel id="roomcontrols">
|
<TabPanel id="roomcontrols">
|
||||||
<div className="space-y-0.5">
|
<div className={themeStackClass}>
|
||||||
{/* {showTelemetry ? <TelemetryPanel /> : null} */}
|
{/* {showTelemetry ? <TelemetryPanel /> : null} */}
|
||||||
<HomeAssistantControls />
|
<HomeAssistantControls />
|
||||||
<ButtonBoxPanel />
|
<ButtonBoxPanel />
|
||||||
@@ -171,7 +172,7 @@ function MobileFeatureTabs({
|
|||||||
<HelpPanel layout={layout} onOpenOverlay={onOpenHelpOverlay} />
|
<HelpPanel layout={layout} onOpenOverlay={onOpenHelpOverlay} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel id="settings">
|
<TabPanel id="settings">
|
||||||
<div className="space-y-0.5">
|
<div className={themeStackClass}>
|
||||||
<SettingsPanel />
|
<SettingsPanel />
|
||||||
<LogPanel />
|
<LogPanel />
|
||||||
</div>
|
</div>
|
||||||
@@ -184,10 +185,10 @@ function MobileFeatureTabs({
|
|||||||
|
|
||||||
function MobilePortraitLayout({ onOpenHelpOverlay, swapMobileControlColumns = false }) {
|
function MobilePortraitLayout({ onOpenHelpOverlay, swapMobileControlColumns = false }) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-0.5">
|
<div className={`flex flex-col ${themeGapClass}`}>
|
||||||
<DriverVideo layoutFormat="mobile-portrait" />
|
<DriverVideo layoutFormat="mobile-portrait" />
|
||||||
<MobileControls swapColumns={swapMobileControlColumns} />
|
<MobileControls swapColumns={swapMobileControlColumns} />
|
||||||
<div className="grid gap-0.5 grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]">
|
<div className={`grid ${themeGapClass} grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]`}>
|
||||||
<ReplaySourcesPanel panelId="replay-sources-mobile-portrait" />
|
<ReplaySourcesPanel panelId="replay-sources-mobile-portrait" />
|
||||||
<RoverQueuesPanel />
|
<RoverQueuesPanel />
|
||||||
</div>
|
</div>
|
||||||
@@ -210,12 +211,12 @@ function MobileLandscapeLayout({ onOpenHelpOverlay, swapMobileControlColumns = f
|
|||||||
? <MobileActionsColumn layout="landscape" className={columnClass} />
|
? <MobileActionsColumn layout="landscape" className={columnClass} />
|
||||||
: <MobileDriveColumn layout="landscape" className={columnClass} />;
|
: <MobileDriveColumn layout="landscape" className={columnClass} />;
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-0.5">
|
<div className={`flex flex-col ${themeGapClass}`}>
|
||||||
<section className="grid min-h-screen grid-cols-[minmax(0,0.7fr)_minmax(0,2.1fr)_minmax(0,0.7fr)] gap-0.5">
|
<section className={`grid min-h-screen grid-cols-[minmax(0,0.7fr)_minmax(0,2.1fr)_minmax(0,0.7fr)] ${themeGapClass}`}>
|
||||||
{firstColumn}
|
{firstColumn}
|
||||||
<div>
|
<div>
|
||||||
<DriverVideo layoutFormat="mobile-landscape" />
|
<DriverVideo layoutFormat="mobile-landscape" />
|
||||||
<div className="grid gap-0.5 grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]">
|
<div className={`grid ${themeGapClass} grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]`}>
|
||||||
<ReplaySourcesPanel panelId="replay-sources-mobile-landscape" />
|
<ReplaySourcesPanel panelId="replay-sources-mobile-landscape" />
|
||||||
<RoverQueuesPanel />
|
<RoverQueuesPanel />
|
||||||
</div>
|
</div>
|
||||||
@@ -223,7 +224,7 @@ function MobileLandscapeLayout({ onOpenHelpOverlay, swapMobileControlColumns = f
|
|||||||
</div>
|
</div>
|
||||||
{secondColumn}
|
{secondColumn}
|
||||||
</section>
|
</section>
|
||||||
<div className="flex flex-col gap-0.5 pb-0">
|
<div className={`flex flex-col ${themeGapClass} pb-0`}>
|
||||||
<MobileFeatureTabs
|
<MobileFeatureTabs
|
||||||
layout="mobile-landscape"
|
layout="mobile-landscape"
|
||||||
onOpenHelpOverlay={onOpenHelpOverlay}
|
onOpenHelpOverlay={onOpenHelpOverlay}
|
||||||
@@ -241,7 +242,7 @@ function App() {
|
|||||||
const fullscreen = useFullscreenPrompt(layout);
|
const fullscreen = useFullscreenPrompt(layout);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`bg-black text-slate-100 ${isDesktop ? 'h-screen overflow-hidden' : 'min-h-screen'}`}>
|
<div className={`${pageBackgroundClass} text-slate-100 ${isDesktop ? 'h-screen overflow-hidden' : 'min-h-screen'}`}>
|
||||||
<AppWithProviders layout={layout} isDesktop={isDesktop} fullscreen={fullscreen} />
|
<AppWithProviders layout={layout} isDesktop={isDesktop} fullscreen={fullscreen} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -326,7 +327,7 @@ function AppWithProviders({ layout, isDesktop, fullscreen }) {
|
|||||||
<ControlSystemProvider>
|
<ControlSystemProvider>
|
||||||
<KeyboardInputManager />
|
<KeyboardInputManager />
|
||||||
<GamepadInputManager />
|
<GamepadInputManager />
|
||||||
<main className={`flex w-full flex-col gap-0.5 text-base ${isDesktop ? 'h-full overflow-hidden' : ''}`}>
|
<main className={`flex w-full flex-col ${themeGapClass} text-base ${isDesktop ? 'h-full overflow-hidden' : ''}`}>
|
||||||
{!isDesktop ? <GlobalObjectiveBanner layout={layout} /> : null}
|
{!isDesktop ? <GlobalObjectiveBanner layout={layout} /> : null}
|
||||||
{renderedLayout}
|
{renderedLayout}
|
||||||
</main>
|
</main>
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export default function CardFrame({
|
|||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
className={cx(
|
className={cx(
|
||||||
'panel-section border border-neutral-500/60 bg-neutral-900/95 shadow-[0_1px_0_rgba(255,255,255,0.05)_inset,0_10px_24px_rgba(0,0,0,0.28)]',
|
'panel-section border border-neutral-500/60 bg-neutral-900/95',
|
||||||
clipOverflow ? 'overflow-hidden' : 'overflow-visible',
|
clipOverflow ? 'overflow-hidden' : 'overflow-visible',
|
||||||
fillHeight && 'flex h-full min-h-0 flex-col',
|
fillHeight && 'flex h-full min-h-0 flex-col',
|
||||||
className,
|
className,
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import OverseerPreferencePanel from '../OverseerPreferencePanel/index.jsx';
|
|||||||
import CardFrame from '../CardFrame/index.jsx';
|
import CardFrame from '../CardFrame/index.jsx';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useManualDockAssist } from '../../features/manualDockAssist/useManualDockAssist.js';
|
import { useManualDockAssist } from '../../features/manualDockAssist/useManualDockAssist.js';
|
||||||
|
import { themeGapClass, themeStackClass } from '../../themeFlags.js';
|
||||||
|
|
||||||
function TopDownMapPanel() {
|
function TopDownMapPanel() {
|
||||||
const {
|
const {
|
||||||
@@ -75,10 +76,10 @@ function DriveDockPanel() {
|
|||||||
const cameraDisabled = Boolean(!roverId || dockAssist.cameraLocked);
|
const cameraDisabled = Boolean(!roverId || dockAssist.cameraLocked);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="panel-section grid h-full min-h-0 grid-rows-[minmax(0,1fr)_auto] gap-0.5">
|
<section className={`panel-section grid h-full min-h-0 grid-rows-[minmax(0,1fr)_auto] ${themeGapClass}`}>
|
||||||
<DriveDockAction layout="desktop" expand driveDockState={driveDockState} />
|
<DriveDockAction layout="desktop" expand driveDockState={driveDockState} />
|
||||||
{!hideInlineControls ? (
|
{!hideInlineControls ? (
|
||||||
<div className="surface space-y-0.5 p-0 text-sm text-slate-200">
|
<div className={`surface ${themeStackClass} p-0 text-sm text-slate-200`}>
|
||||||
{nightVisionAvailable && (
|
{nightVisionAvailable && (
|
||||||
<NightVisionControl
|
<NightVisionControl
|
||||||
nightVisionOn={nightVisionState?.nightVisionOn}
|
nightVisionOn={nightVisionState?.nightVisionOn}
|
||||||
@@ -107,7 +108,7 @@ function DriveDockPanel() {
|
|||||||
onChange={setServoAngle}
|
onChange={setServoAngle}
|
||||||
keyDownLabel={downLabel}
|
keyDownLabel={downLabel}
|
||||||
keyUpLabel={upLabel}
|
keyUpLabel={upLabel}
|
||||||
className="space-y-0.5 px-1 py-1"
|
className={`${themeStackClass} px-1 py-1`}
|
||||||
labelRowClass="text-xs text-slate-300"
|
labelRowClass="text-xs text-slate-300"
|
||||||
labelClass=""
|
labelClass=""
|
||||||
valueClass="font-mono text-slate-100"
|
valueClass="font-mono text-slate-100"
|
||||||
@@ -149,7 +150,7 @@ export default function RightPaneTabs({ layout, onOpenHelpOverlay }) {
|
|||||||
ownAudioForward?.state === 'playing',
|
ownAudioForward?.state === 'playing',
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<section className="panel text-base">
|
<section className="text-base">
|
||||||
<Tabs defaultTab="telemetry" currentTab={activeTab} onTabChange={setActiveTab}>
|
<Tabs defaultTab="telemetry" currentTab={activeTab} onTabChange={setActiveTab}>
|
||||||
<TabList>
|
<TabList>
|
||||||
<Tab id="telemetry">Controls</Tab>
|
<Tab id="telemetry">Controls</Tab>
|
||||||
@@ -168,19 +169,19 @@ export default function RightPaneTabs({ layout, onOpenHelpOverlay }) {
|
|||||||
</TabList>
|
</TabList>
|
||||||
<TabPanels>
|
<TabPanels>
|
||||||
<TabPanel id="telemetry">
|
<TabPanel id="telemetry">
|
||||||
<div className="space-y-0.5">
|
<div className={themeStackClass}>
|
||||||
<div className="grid items-stretch gap-0.5 grid-cols-[minmax(0,1.35fr)_minmax(0,0.95fr)]">
|
<div className={`grid items-stretch ${themeGapClass} grid-cols-[minmax(0,1.35fr)_minmax(0,0.95fr)]`}>
|
||||||
<TopDownMapPanel />
|
<TopDownMapPanel />
|
||||||
<DriveDockPanel />
|
<DriveDockPanel />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-0.5 grid-cols-[minmax(0,1fr)_minmax(0,0.9fr)_minmax(0,0.75fr)]">
|
<div className={`grid ${themeGapClass} grid-cols-[minmax(0,1fr)_minmax(0,0.9fr)_minmax(0,0.75fr)]`}>
|
||||||
<RoverQueuesPanel />
|
<RoverQueuesPanel />
|
||||||
<ReplaySourcesPanel panelId="replay-sources-desktop" fillHeight />
|
<ReplaySourcesPanel panelId="replay-sources-desktop" fillHeight />
|
||||||
<LinkButtonsPanel />
|
<LinkButtonsPanel />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid items-stretch gap-0.5 grid-cols-[minmax(0,1.3fr)_minmax(0,0.22fr)] h-[14rem]">
|
<div className={`grid items-stretch ${themeGapClass} grid-cols-[minmax(0,1.3fr)_minmax(0,0.22fr)] h-[14rem]`}>
|
||||||
<ChatPanel fillHeight />
|
<ChatPanel fillHeight />
|
||||||
<div className="grid min-h-0 gap-0.5 grid-rows-[auto_minmax(0,1fr)]">
|
<div className={`grid min-h-0 ${themeGapClass} grid-rows-[auto_minmax(0,1fr)]`}>
|
||||||
<OverseerPreferencePanel />
|
<OverseerPreferencePanel />
|
||||||
<RawUserPilePanel compact hideNicknameForm fillHeight />
|
<RawUserPilePanel compact hideNicknameForm fillHeight />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Purpose: Defines the Tabs module and the local helpers/components used in this file.
|
// Purpose: Defines the Tabs module and the local helpers/components used in this file.
|
||||||
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
// Scope: Keeps behavior unchanged while isolating this concern into a clear, single-responsibility unit.
|
||||||
import { createContext, useCallback, useContext, useMemo, useState, useEffect } from 'react';
|
import { createContext, useCallback, useContext, useMemo, useState, useEffect } from 'react';
|
||||||
import { useSessionSelector } from '../../context/SessionContext.jsx';
|
import { themeGapClass, themeStackClass } from '../../themeFlags.js';
|
||||||
|
|
||||||
const TabsContext = createContext(null);
|
const TabsContext = createContext(null);
|
||||||
|
|
||||||
@@ -34,28 +34,6 @@ function classNames(...parts) {
|
|||||||
return parts.filter(Boolean).join(' ');
|
return parts.filter(Boolean).join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
function hexToRgb(hex) {
|
|
||||||
const raw = String(hex || '').trim();
|
|
||||||
const normalized = raw.startsWith('#') ? raw.slice(1) : raw;
|
|
||||||
if (!/^[0-9a-fA-F]{3}$|^[0-9a-fA-F]{6}$/.test(normalized)) return null;
|
|
||||||
const expanded =
|
|
||||||
normalized.length === 3
|
|
||||||
? normalized
|
|
||||||
.split('')
|
|
||||||
.map((ch) => ch + ch)
|
|
||||||
.join('')
|
|
||||||
: normalized;
|
|
||||||
return {
|
|
||||||
r: Number.parseInt(expanded.slice(0, 2), 16),
|
|
||||||
g: Number.parseInt(expanded.slice(2, 4), 16),
|
|
||||||
b: Number.parseInt(expanded.slice(4, 6), 16),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function rgba(rgb, alpha) {
|
|
||||||
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Tabs({ children, defaultTab, currentTab, onTabChange, variant = DEFAULT_VARIANT }) {
|
export default function Tabs({ children, defaultTab, currentTab, onTabChange, variant = DEFAULT_VARIANT }) {
|
||||||
const [internalTab, setInternalTab] = useState(defaultTab ?? null);
|
const [internalTab, setInternalTab] = useState(defaultTab ?? null);
|
||||||
const [tabOrder, setTabOrder] = useState([]);
|
const [tabOrder, setTabOrder] = useState([]);
|
||||||
@@ -118,30 +96,14 @@ export default function Tabs({ children, defaultTab, currentTab, onTabChange, va
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function TabList({ children, className = '' }) {
|
export function TabList({ children, className = '' }) {
|
||||||
const ownRoverColor = useSessionSelector((state) => {
|
|
||||||
const roverId = String(state.session?.assignment?.roverId || '').trim();
|
|
||||||
if (!roverId) return null;
|
|
||||||
const roster = Array.isArray(state.session?.roster) ? state.session.roster : [];
|
|
||||||
const rover = roster.find((entry) => String(entry?.id) === roverId);
|
|
||||||
return rover?.color || null;
|
|
||||||
});
|
|
||||||
const accentRgb = hexToRgb(ownRoverColor);
|
|
||||||
const frameStyle = accentRgb ? { borderColor: rgba(accentRgb, 0.35) } : undefined;
|
|
||||||
const headerStyle = accentRgb
|
|
||||||
? {
|
|
||||||
backgroundImage: `linear-gradient(90deg, rgba(23,23,23,0.96) 0%, rgba(38,38,38,0.94) 58%, ${rgba(accentRgb, 0.18)} 100%)`,
|
|
||||||
}
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'panel-section overflow-hidden border border-neutral-500/60 bg-neutral-900/95 p-0.5 shadow-[0_1px_0_rgba(255,255,255,0.05)_inset,0_10px_24px_rgba(0,0,0,0.28)]',
|
'panel-section overflow-hidden border border-neutral-500/60 bg-neutral-900/95 p-0.5',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
style={frameStyle}
|
|
||||||
>
|
>
|
||||||
<div className="flex gap-0.5" style={headerStyle}>{children}</div>
|
<div className={`flex ${themeGapClass}`}>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -176,7 +138,7 @@ export function Tab({ id, children, className = '', disabled = false, highlight
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function TabPanels({ children, className = '' }) {
|
export function TabPanels({ children, className = '' }) {
|
||||||
return <div className={classNames('mt-0 space-y-0.5', className)}>{children}</div>;
|
return <div className={classNames('mt-0', themeStackClass, className)}>{children}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TabPanel({ id, children, keepMounted = false }) {
|
export function TabPanel({ id, children, keepMounted = false }) {
|
||||||
|
|||||||
@@ -59,6 +59,27 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
|
.pride-page-bg {
|
||||||
|
background-color: #050505;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(0, 0, 0, 0.24), rgba(0, 0, 0, 0.24)),
|
||||||
|
repeating-linear-gradient(
|
||||||
|
45deg,
|
||||||
|
#5bcefa 0 1.818%,
|
||||||
|
#f5a9b8 1.818% 3.636%,
|
||||||
|
#ffffff 3.636% 5.455%,
|
||||||
|
#f5a9b8 5.455% 7.273%,
|
||||||
|
#5bcefa 7.273% 9.091%,
|
||||||
|
#e40303 9.091% 10.909%,
|
||||||
|
#ff8c00 10.909% 12.727%,
|
||||||
|
#ffed00 12.727% 14.545%,
|
||||||
|
#00a651 14.545% 16.364%,
|
||||||
|
#0066ff 16.364% 18.182%,
|
||||||
|
#9b2fae 18.182% 20%
|
||||||
|
);
|
||||||
|
background-attachment: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
.panel {
|
.panel {
|
||||||
@apply bg-black text-white p-0 rounded-md;
|
@apply bg-black text-white p-0 rounded-md;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export const PRIDE_THEME_ENABLED = true;
|
||||||
|
|
||||||
|
export const pageBackgroundClass = PRIDE_THEME_ENABLED ? 'pride-page-bg' : 'bg-black';
|
||||||
|
export const themeGapClass = PRIDE_THEME_ENABLED ? 'gap-1' : 'gap-0.5';
|
||||||
|
export const themeStackClass = PRIDE_THEME_ENABLED ? 'space-y-1' : 'space-y-0.5';
|
||||||
Reference in New Issue
Block a user