chore(canary): white-canvas frontend design layer pre-operator UI
Strip the inherited template aesthetic so the next AI/designer starts
from a true blank canvas. AI tunnel-vision pattern: when there's an
existing layout/sidebar/color palette, the model tends to redesign
in place rather than truly start fresh. Removing the visual scaffold
forces fresh-canvas thinking when operator-driven UI work begins.
Removed:
- pages/dashboard, pages/settings — template "Welcome / Available
Stores / Suggested Features" stubs that have no canary purpose.
- pages/landing/landing.module.scss, core/app/{shell,toast}.module.scss
— empty header stubs imported only for side effects.
- core/lib/shell.ui.store.ts — zustand store for sidebar open/
collapsed/theme state; entirely template-coupled. core/lib/index.ts
reduced to an empty barrel ready for canary stores.
- core/app/shell.tsx sidebar+nav+header layout; replaced with bare
ErrorBoundary > Suspense > Outlet. Keeps robustness pattern,
drops the navbar template a designer would otherwise inherit.
- App.tsx hardcoded dark Toaster theme + wrapping .app div.
- styles/_tokens.scss color palette ($bg-page, $text-default, etc.)
— biased toward a specific dark aesthetic. Spacing, typography,
weights, line heights, letter spacing, radius, z-index, transitions,
breakpoints, container widths all KEPT — neutral design primitives,
not aesthetic choices.
- styles/_reset.scss body bg-color: #fff / color: #000 defaults.
Designer chooses the palette; reset stays purely structural.
- styles.scss .app class wrapper.
- config.ts USERS endpoints, USERS query keys, STORAGE_KEYS,
HTTP_STATUS, PAGINATION — template constants with no canary
consumer. Reduced to ROUTES.HOME and QUERY_CONFIG (consumed by
query.config.ts). Designer adds back what they actually need.
Kept (logic / infrastructure / Phase 14 work):
- Full api/ and core/api/ — Zod schemas, axios client, hooks,
ApiError, QueryClient, retry strategies.
- main.tsx, index.html (already canary-titled with favicons in
public/asset).
- QueryClientProvider + RouterProvider + bare Toaster + ReactQuery
Devtools provider stack.
- Lazy-route + Suspense + ErrorBoundary pattern in shell.
- styles/_index.scss, _fonts.scss (system font stacks), _mixins.scss
(breakpoint utilities, flex helpers, sr-only, truncate, etc.) —
all neutral.
Gate: pnpm typecheck, pnpm biome check, pnpm lint:scss, pnpm build
all clean. Production bundle: 140-byte landing chunk (the <div />),
~37 KB index chunk (api/core/router/zod machinery), no leftover
template CSS.
This commit is contained in:
parent
37cdf97133
commit
1d205c1791
|
|
@ -7,29 +7,14 @@ import { QueryClientProvider } from '@tanstack/react-query'
|
||||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
||||||
import { RouterProvider } from 'react-router-dom'
|
import { RouterProvider } from 'react-router-dom'
|
||||||
import { Toaster } from 'sonner'
|
import { Toaster } from 'sonner'
|
||||||
|
|
||||||
import { queryClient } from '@/core/api'
|
import { queryClient } from '@/core/api'
|
||||||
import { router } from '@/core/app/routers'
|
import { router } from '@/core/app/routers'
|
||||||
import '@/core/app/toast.module.scss'
|
|
||||||
|
|
||||||
export default function App(): React.ReactElement {
|
export default function App(): React.ReactElement {
|
||||||
return (
|
return (
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<div className="app">
|
<RouterProvider router={router} />
|
||||||
<RouterProvider router={router} />
|
<Toaster />
|
||||||
<Toaster
|
|
||||||
position="top-right"
|
|
||||||
duration={2000}
|
|
||||||
theme="dark"
|
|
||||||
toastOptions={{
|
|
||||||
style: {
|
|
||||||
background: 'hsl(0, 0%, 12.2%)',
|
|
||||||
border: '1px solid hsl(0, 0%, 18%)',
|
|
||||||
color: 'hsl(0, 0%, 98%)',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<ReactQueryDevtools initialIsOpen={false} />
|
<ReactQueryDevtools initialIsOpen={false} />
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -2,31 +2,12 @@
|
||||||
// ©AngelaMos | 2026
|
// ©AngelaMos | 2026
|
||||||
// config.ts
|
// config.ts
|
||||||
// ===================
|
// ===================
|
||||||
const API_VERSION = 'v1'
|
|
||||||
|
|
||||||
export const API_ENDPOINTS = {
|
|
||||||
USERS: {
|
|
||||||
BASE: `/${API_VERSION}/users`,
|
|
||||||
BY_ID: (id: string) => `/${API_VERSION}/users/${id}`,
|
|
||||||
},
|
|
||||||
} as const
|
|
||||||
|
|
||||||
export const QUERY_KEYS = {
|
|
||||||
USERS: {
|
|
||||||
ALL: ['users'] as const,
|
|
||||||
BY_ID: (id: string) => [...QUERY_KEYS.USERS.ALL, 'detail', id] as const,
|
|
||||||
},
|
|
||||||
} as const
|
|
||||||
|
|
||||||
export const ROUTES = {
|
export const ROUTES = {
|
||||||
HOME: '/',
|
HOME: '/',
|
||||||
DASHBOARD: '/dashboard',
|
|
||||||
SETTINGS: '/settings',
|
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export const STORAGE_KEYS = {
|
export type Route = typeof ROUTES
|
||||||
UI: 'ui-storage',
|
|
||||||
} as const
|
|
||||||
|
|
||||||
export const QUERY_CONFIG = {
|
export const QUERY_CONFIG = {
|
||||||
STALE_TIME: {
|
STALE_TIME: {
|
||||||
|
|
@ -43,26 +24,3 @@ export const QUERY_CONFIG = {
|
||||||
NONE: 0,
|
NONE: 0,
|
||||||
},
|
},
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export const HTTP_STATUS = {
|
|
||||||
OK: 200,
|
|
||||||
CREATED: 201,
|
|
||||||
NO_CONTENT: 204,
|
|
||||||
BAD_REQUEST: 400,
|
|
||||||
UNAUTHORIZED: 401,
|
|
||||||
FORBIDDEN: 403,
|
|
||||||
NOT_FOUND: 404,
|
|
||||||
CONFLICT: 409,
|
|
||||||
TOO_MANY_REQUESTS: 429,
|
|
||||||
INTERNAL_SERVER: 500,
|
|
||||||
} as const
|
|
||||||
|
|
||||||
export const PAGINATION = {
|
|
||||||
DEFAULT_PAGE: 1,
|
|
||||||
DEFAULT_SIZE: 20,
|
|
||||||
MAX_SIZE: 100,
|
|
||||||
} as const
|
|
||||||
|
|
||||||
export type ApiEndpoint = typeof API_ENDPOINTS
|
|
||||||
export type QueryKey = typeof QUERY_KEYS
|
|
||||||
export type Route = typeof ROUTES
|
|
||||||
|
|
|
||||||
|
|
@ -8,27 +8,19 @@ import { ROUTES } from '@/config'
|
||||||
import { Shell } from './shell'
|
import { Shell } from './shell'
|
||||||
|
|
||||||
const routes: RouteObject[] = [
|
const routes: RouteObject[] = [
|
||||||
{
|
|
||||||
path: ROUTES.HOME,
|
|
||||||
lazy: () => import('@/pages/landing'),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
element: <Shell />,
|
element: <Shell />,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: ROUTES.DASHBOARD,
|
path: ROUTES.HOME,
|
||||||
lazy: () => import('@/pages/dashboard'),
|
lazy: () => import('@/pages/landing'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ROUTES.SETTINGS,
|
path: '*',
|
||||||
lazy: () => import('@/pages/settings'),
|
lazy: () => import('@/pages/landing'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '*',
|
|
||||||
lazy: () => import('@/pages/landing'),
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
export const router = createBrowserRouter(routes)
|
export const router = createBrowserRouter(routes)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
// ===================
|
|
||||||
// ©AngelaMos | 2026
|
|
||||||
// shell.module.scss
|
|
||||||
// ===================
|
|
||||||
|
|
@ -1,116 +1,22 @@
|
||||||
/**
|
// ===================
|
||||||
* ©AngelaMos | 2026
|
// ©AngelaMos | 2026
|
||||||
* shell.tsx
|
// shell.tsx
|
||||||
*/
|
// ===================
|
||||||
|
|
||||||
import { Suspense } from 'react'
|
import { Suspense } from 'react'
|
||||||
import { ErrorBoundary } from 'react-error-boundary'
|
import { ErrorBoundary } from 'react-error-boundary'
|
||||||
import { GiCardAceClubs, GiCardJoker } from 'react-icons/gi'
|
import { Outlet } from 'react-router-dom'
|
||||||
import { LuChevronLeft, LuChevronRight, LuMenu } from 'react-icons/lu'
|
|
||||||
import { NavLink, Outlet, useLocation } from 'react-router-dom'
|
|
||||||
import { ROUTES } from '@/config'
|
|
||||||
import { useUIStore } from '@/core/lib'
|
|
||||||
import styles from './shell.module.scss'
|
|
||||||
|
|
||||||
const NAV_ITEMS = [
|
|
||||||
{ path: ROUTES.DASHBOARD, label: 'Dashboard', icon: GiCardJoker },
|
|
||||||
{ path: ROUTES.SETTINGS, label: 'Settings', icon: GiCardAceClubs },
|
|
||||||
]
|
|
||||||
|
|
||||||
function ShellErrorFallback({ error }: { error: Error }): React.ReactElement {
|
function ShellErrorFallback({ error }: { error: Error }): React.ReactElement {
|
||||||
return (
|
return <pre>{error.message}</pre>
|
||||||
<div className={styles.error}>
|
|
||||||
<h2>Something went wrong</h2>
|
|
||||||
<pre>{error.message}</pre>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function ShellLoading(): React.ReactElement {
|
|
||||||
return <div className={styles.loading}>Loading...</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPageTitle(pathname: string): string {
|
|
||||||
const item = NAV_ITEMS.find((i) => i.path === pathname)
|
|
||||||
return item?.label ?? 'Dashboard'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Shell(): React.ReactElement {
|
export function Shell(): React.ReactElement {
|
||||||
const location = useLocation()
|
|
||||||
const { sidebarOpen, sidebarCollapsed, toggleSidebar, toggleSidebarCollapsed } =
|
|
||||||
useUIStore()
|
|
||||||
|
|
||||||
const pageTitle = getPageTitle(location.pathname)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.shell}>
|
<ErrorBoundary FallbackComponent={ShellErrorFallback}>
|
||||||
<aside
|
<Suspense fallback={null}>
|
||||||
className={`${styles.sidebar} ${sidebarOpen ? styles.open : ''} ${sidebarCollapsed ? styles.collapsed : ''}`}
|
<Outlet />
|
||||||
>
|
</Suspense>
|
||||||
<div className={styles.sidebarHeader}>
|
</ErrorBoundary>
|
||||||
<span className={styles.logo}>NavBar Template</span>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={styles.collapseBtn}
|
|
||||||
onClick={toggleSidebarCollapsed}
|
|
||||||
aria-label={sidebarCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
|
|
||||||
>
|
|
||||||
{sidebarCollapsed ? <LuChevronRight /> : <LuChevronLeft />}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav className={styles.nav}>
|
|
||||||
{NAV_ITEMS.map((item) => (
|
|
||||||
<NavLink
|
|
||||||
key={item.path}
|
|
||||||
to={item.path}
|
|
||||||
className={({ isActive }) =>
|
|
||||||
`${styles.navItem} ${isActive ? styles.active : ''}`
|
|
||||||
}
|
|
||||||
onClick={() => sidebarOpen && toggleSidebar()}
|
|
||||||
>
|
|
||||||
<item.icon className={styles.navIcon} />
|
|
||||||
<span className={styles.navLabel}>{item.label}</span>
|
|
||||||
</NavLink>
|
|
||||||
))}
|
|
||||||
</nav>
|
|
||||||
</aside>
|
|
||||||
|
|
||||||
{sidebarOpen && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={styles.overlay}
|
|
||||||
onClick={toggleSidebar}
|
|
||||||
onKeyDown={(e) => e.key === 'Escape' && toggleSidebar()}
|
|
||||||
aria-label="Close sidebar"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div
|
|
||||||
className={`${styles.main} ${sidebarCollapsed ? styles.collapsed : ''}`}
|
|
||||||
>
|
|
||||||
<header className={styles.header}>
|
|
||||||
<div className={styles.headerLeft}>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className={styles.menuBtn}
|
|
||||||
onClick={toggleSidebar}
|
|
||||||
aria-label="Toggle menu"
|
|
||||||
>
|
|
||||||
<LuMenu />
|
|
||||||
</button>
|
|
||||||
<h1 className={styles.pageTitle}>{pageTitle}</h1>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main className={styles.content}>
|
|
||||||
<ErrorBoundary FallbackComponent={ShellErrorFallback}>
|
|
||||||
<Suspense fallback={<ShellLoading />}>
|
|
||||||
<Outlet />
|
|
||||||
</Suspense>
|
|
||||||
</ErrorBoundary>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
// ===================
|
|
||||||
// ©AngelaMos | 2026
|
|
||||||
// toast.module.scss
|
|
||||||
// ===================
|
|
||||||
|
|
@ -2,5 +2,3 @@
|
||||||
// ©AngelaMos | 2026
|
// ©AngelaMos | 2026
|
||||||
// index.ts
|
// index.ts
|
||||||
// ===================
|
// ===================
|
||||||
|
|
||||||
export * from './shell.ui.store'
|
|
||||||
|
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
/**
|
|
||||||
* ©AngelaMos | 2026
|
|
||||||
* ui.store.ts
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { create } from 'zustand'
|
|
||||||
import { devtools, persist } from 'zustand/middleware'
|
|
||||||
|
|
||||||
type Theme = 'light' | 'dark' | 'system'
|
|
||||||
|
|
||||||
interface UIState {
|
|
||||||
theme: Theme
|
|
||||||
sidebarOpen: boolean
|
|
||||||
sidebarCollapsed: boolean
|
|
||||||
setTheme: (theme: Theme) => void
|
|
||||||
toggleSidebar: () => void
|
|
||||||
setSidebarOpen: (open: boolean) => void
|
|
||||||
toggleSidebarCollapsed: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useUIStore = create<UIState>()(
|
|
||||||
devtools(
|
|
||||||
persist(
|
|
||||||
(set) => ({
|
|
||||||
theme: 'dark',
|
|
||||||
sidebarOpen: false,
|
|
||||||
sidebarCollapsed: false,
|
|
||||||
|
|
||||||
setTheme: (theme) => set({ theme }, false, 'ui/setTheme'),
|
|
||||||
|
|
||||||
toggleSidebar: () =>
|
|
||||||
set(
|
|
||||||
(state) => ({ sidebarOpen: !state.sidebarOpen }),
|
|
||||||
false,
|
|
||||||
'ui/toggleSidebar'
|
|
||||||
),
|
|
||||||
|
|
||||||
setSidebarOpen: (open) =>
|
|
||||||
set({ sidebarOpen: open }, false, 'ui/setSidebarOpen'),
|
|
||||||
|
|
||||||
toggleSidebarCollapsed: () =>
|
|
||||||
set(
|
|
||||||
(state) => ({ sidebarCollapsed: !state.sidebarCollapsed }),
|
|
||||||
false,
|
|
||||||
'ui/toggleSidebarCollapsed'
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: 'ui-storage',
|
|
||||||
partialize: (state) => ({
|
|
||||||
theme: state.theme,
|
|
||||||
sidebarCollapsed: state.sidebarCollapsed,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
{ name: 'UIStore' }
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
export const useTheme = (): Theme => useUIStore((s) => s.theme)
|
|
||||||
export const useSidebarOpen = (): boolean => useUIStore((s) => s.sidebarOpen)
|
|
||||||
export const useSidebarCollapsed = (): boolean =>
|
|
||||||
useUIStore((s) => s.sidebarCollapsed)
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
// ===================
|
|
||||||
// ©AngelaMos | 2026
|
|
||||||
// dashboard.module.scss
|
|
||||||
// ===================
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
/**
|
|
||||||
* ©AngelaMos | 2026
|
|
||||||
* index.tsx
|
|
||||||
*/
|
|
||||||
|
|
||||||
import styles from './dashboard.module.scss'
|
|
||||||
|
|
||||||
const AVAILABLE_STORES = [
|
|
||||||
{
|
|
||||||
name: 'useUIStore()',
|
|
||||||
file: 'core/lib/shell.ui.store.ts',
|
|
||||||
description: 'Theme, sidebar open/collapsed state',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const SUGGESTED_FEATURES = [
|
|
||||||
'Stats and metrics',
|
|
||||||
'Recent activity feed',
|
|
||||||
'Quick actions',
|
|
||||||
'Charts and analytics',
|
|
||||||
'Notifications overview',
|
|
||||||
'Task/project summary',
|
|
||||||
]
|
|
||||||
|
|
||||||
export function Component(): React.ReactElement {
|
|
||||||
return (
|
|
||||||
<div className={styles.page}>
|
|
||||||
<div className={styles.container}>
|
|
||||||
<div className={styles.header}>
|
|
||||||
<h1 className={styles.title}>Welcome</h1>
|
|
||||||
<p className={styles.subtitle}>
|
|
||||||
Template page — build your dashboard here
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<section className={styles.section}>
|
|
||||||
<h2 className={styles.sectionTitle}>Available Stores</h2>
|
|
||||||
<div className={styles.grid}>
|
|
||||||
{AVAILABLE_STORES.map((store) => (
|
|
||||||
<div key={store.name} className={styles.card}>
|
|
||||||
<code className={styles.hookName}>{store.name}</code>
|
|
||||||
<p className={styles.description}>{store.description}</p>
|
|
||||||
<span className={styles.file}>{store.file}</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className={styles.section}>
|
|
||||||
<h2 className={styles.sectionTitle}>Suggested Features</h2>
|
|
||||||
<ul className={styles.list}>
|
|
||||||
{SUGGESTED_FEATURES.map((feature) => (
|
|
||||||
<li key={feature}>{feature}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.displayName = 'Dashboard'
|
|
||||||
|
|
@ -3,10 +3,8 @@
|
||||||
// index.tsx
|
// index.tsx
|
||||||
// ===================
|
// ===================
|
||||||
|
|
||||||
import styles from './landing.module.scss'
|
|
||||||
|
|
||||||
export function Component(): React.ReactElement {
|
export function Component(): React.ReactElement {
|
||||||
return <div className={styles.page} />
|
return <div />
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.displayName = 'Landing'
|
Component.displayName = 'Landing'
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
// ===================
|
|
||||||
// ©AngelaMos | 2026
|
|
||||||
// landing.module.scss
|
|
||||||
// ===================
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
/**
|
|
||||||
* ©AngelaMos | 2026
|
|
||||||
* index.tsx
|
|
||||||
*/
|
|
||||||
|
|
||||||
import styles from './settings.module.scss'
|
|
||||||
|
|
||||||
const AVAILABLE_STORES = [
|
|
||||||
{
|
|
||||||
name: 'useUIStore()',
|
|
||||||
file: 'core/lib/shell.ui.store.ts',
|
|
||||||
description: 'Theme, sidebar open/collapsed state',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export function Component(): React.ReactElement {
|
|
||||||
return (
|
|
||||||
<div className={styles.page}>
|
|
||||||
<div className={styles.container}>
|
|
||||||
<div className={styles.header}>
|
|
||||||
<h1 className={styles.title}>Settings</h1>
|
|
||||||
<p className={styles.subtitle}>
|
|
||||||
Template page — available stores for building your settings UI
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<section className={styles.section}>
|
|
||||||
<h2 className={styles.sectionTitle}>Available Stores</h2>
|
|
||||||
<div className={styles.grid}>
|
|
||||||
{AVAILABLE_STORES.map((store) => (
|
|
||||||
<div key={store.name} className={styles.card}>
|
|
||||||
<code className={styles.hookName}>{store.name}</code>
|
|
||||||
<p className={styles.description}>{store.description}</p>
|
|
||||||
<div className={styles.meta}>
|
|
||||||
<span className={styles.file}>{store.file}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className={styles.section}>
|
|
||||||
<h2 className={styles.sectionTitle}>Suggested Features</h2>
|
|
||||||
<ul className={styles.list}>
|
|
||||||
<li>Profile form</li>
|
|
||||||
<li>Theme toggle (dark/light)</li>
|
|
||||||
<li>Notification settings</li>
|
|
||||||
<li>Application preferences</li>
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.displayName = 'Settings'
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
// ===================
|
|
||||||
// ©AngelaMos | 2026
|
|
||||||
// settings.module.scss
|
|
||||||
// ===================
|
|
||||||
|
|
@ -12,12 +12,4 @@
|
||||||
#root {
|
#root {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
min-height: 100dvh;
|
min-height: 100dvh;
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,6 @@ body {
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
background-color: #fff;
|
|
||||||
color: #000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
|
|
|
||||||
|
|
@ -71,44 +71,6 @@ $tracking-normal: 0;
|
||||||
$tracking-wide: 0.025em;
|
$tracking-wide: 0.025em;
|
||||||
$tracking-wider: 0.05em;
|
$tracking-wider: 0.05em;
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// COLORS
|
|
||||||
// ============================================================================
|
|
||||||
$white: hsl(0, 0%, 100%);
|
|
||||||
$black: hsl(0, 0%, 0%);
|
|
||||||
|
|
||||||
// Auth
|
|
||||||
$bg-page: hsl(0, 0%, 10.5%);
|
|
||||||
$bg-card: hsl(0, 0%, 6.2%);
|
|
||||||
|
|
||||||
// Home/landing
|
|
||||||
$bg-landing: hsl(0, 0%, 10.8%);
|
|
||||||
|
|
||||||
$bg-default: hsl(0, 0%, 7.1%);
|
|
||||||
$bg-alternative: hsl(0, 0%, 5.9%);
|
|
||||||
$bg-surface-75: hsl(0, 0%, 9%);
|
|
||||||
$bg-surface-100: hsl(0, 0%, 12.2%);
|
|
||||||
$bg-surface-200: hsl(0, 0%, 14.1%);
|
|
||||||
$bg-surface-300: hsl(0, 0%, 16.1%);
|
|
||||||
$bg-control: hsl(0, 0%, 10%);
|
|
||||||
$bg-selection: hsl(0, 0%, 19.2%);
|
|
||||||
$bg-overlay: hsl(0, 0%, 14.1%);
|
|
||||||
$bg-overlay-hover: hsl(0, 0%, 18%);
|
|
||||||
|
|
||||||
$border-muted: hsl(0, 0%, 11.1%);
|
|
||||||
$border-default: hsl(0, 0%, 18%);
|
|
||||||
$border-strong: hsl(0, 0%, 22.4%);
|
|
||||||
$border-stronger: hsl(0, 0%, 27.1%);
|
|
||||||
$border-control: hsl(0, 0%, 22.4%);
|
|
||||||
|
|
||||||
$text-default: hsl(0, 0%, 98%);
|
|
||||||
$text-light: hsl(0, 0%, 70.6%);
|
|
||||||
$text-lighter: hsl(0, 0%, 53.7%);
|
|
||||||
$text-muted: hsl(0, 0%, 30.2%);
|
|
||||||
|
|
||||||
$error-default: hsl(0, 72%, 51%);
|
|
||||||
$error-light: hsl(0, 72%, 65%);
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// BORDER RADIUS
|
// BORDER RADIUS
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue