style(theme): enhance M3 theme styles and integrate Tailwind CSS configuration

This commit is contained in:
4gray committed 2026-02-24 19:10:02 +01:00
1 parent fa742cbaba
commit 349fbcea47
3 files changed
+215 -41

No files matched your search

+115 -26
View File
@@ -1,39 +1,128 @@
@use 'sass:map';
@use '@angular/material' as mat;
@use 'styles' ;
@use 'styles';
@include mat.elevation-classes();
@include mat.app-background();
$my-typography: mat.m2-define-typography-config();
// ─── Typography ─────────────────────────────────────────────────────────────
$my-typography: mat.m2-define-typography-config(
$font-family: "'DM Sans', 'Inter', sans-serif",
);
@include mat.typography-hierarchy($my-typography);
// Note: Color palettes are generated from primary: #ffffff
$_palettes: (
primary: mat.$blue-palette,
tertiary: mat.$red-palette,
// ─── M3 Themes ───────────────────────────────────────────────────────────────
$light-theme: mat.define-theme(
(
color: (
theme-type: light,
primary: mat.$violet-palette,
tertiary: mat.$cyan-palette,
),
typography: (
plain-family: "'DM Sans', 'Inter', sans-serif",
brand-family: "'DM Sans', 'Inter', sans-serif",
),
)
);
$_primary: map.get($_palettes, primary);
$light-theme: mat.define-theme((
color: (
theme-type: light,
primary: $_primary,
),
));
$dark-theme: mat.define-theme((
color: (
theme-type: dark,
primary: $_primary,
),
));
$dark-theme: mat.define-theme(
(
color: (
theme-type: dark,
primary: mat.$violet-palette,
tertiary: mat.$cyan-palette,
),
typography: (
plain-family: "'DM Sans', 'Inter', sans-serif",
brand-family: "'DM Sans', 'Inter', sans-serif",
),
)
);
// ─── Apply Themes ────────────────────────────────────────────────────────────
html {
@include mat.all-component-themes($light-theme);
@include mat.all-component-themes($light-theme);
.dark-theme {
@include mat.all-component-colors($dark-theme);
}
}
// ── Light theme design tokens ─────────────────────────────────────────
--app-shell-bg: #eef0f3;
--app-rail-bg: #e8eaed;
--app-header-bg: #eef0f3;
--app-content-bg: #f5f6f8;
--app-rail-border: rgba(0, 0, 0, 0.08);
--app-search-bg: rgba(255, 255, 255, 0.7);
--app-search-border: rgba(0, 0, 0, 0.1);
// Widget surfaces — no borders, layered backgrounds
--app-widget-bg: #ffffff;
--app-widget-header-bg: #fafbfc;
--app-widget-border: transparent;
--app-widget-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 4px 12px rgba(0, 0, 0, 0.04);
--app-widget-header-border: rgba(0, 0, 0, 0.06);
--app-card-hover-bg: #f0f2f5;
// Typography — subdued, not pure black
--app-heading-color: #1a1d23;
--app-body-color: #4a5060;
--app-muted-color: #8891a4;
--app-eyebrow-color: #7c8495;
// Provider accent colors
--app-provider-xtream: #6366f1;
--app-provider-stalker: #10b981;
--app-provider-m3u: #d97706;
// Hero
--app-accent-gradient: linear-gradient(
135deg,
rgba(99, 102, 241, 0.08) 0%,
rgba(168, 85, 247, 0.05) 100%
);
--app-hero-surface: rgba(99, 102, 241, 0.04);
.dark-theme {
@include mat.all-component-colors($dark-theme);
// ── Dark graphite theme ────────────────────────────────────────────
// Inspired by both Slack (sidebar distinction) and GitButler (data density)
// Key principle: clearly distinct surface layers using graphite steps
// Darkest → lightest: #0d0f12 → #141720 → #1c2030 → #222840
// App shell & navigation
--app-shell-bg: #0d0f12;
--app-rail-bg: #111318;
--app-header-bg: #111318;
--app-content-bg: #161a22;
--app-rail-border: rgba(255, 255, 255, 0.05);
--app-search-bg: rgba(255, 255, 255, 0.05);
--app-search-border: rgba(255, 255, 255, 0.09);
// Widget surfaces — NO border, surface contrast does the work
// Widgets sit on content-bg (#161a22), so widget-bg is notably lighter
--app-widget-bg: #1e2330;
--app-widget-header-bg: #232840;
--app-widget-border: transparent;
--app-widget-shadow: none;
--app-widget-header-border: rgba(255, 255, 255, 0.05);
--app-card-hover-bg: #252b3a;
// Typography — NOT pure white. Warm graphite-tinted whites
--app-heading-color: #d8dce8; // soft off-white, not #fff
--app-body-color: #8b93a8; // muted blue-grey
--app-muted-color: #5c6478; // dimmed
--app-eyebrow-color: #6b7494; // eyebrow labels
// Provider accents (slightly brighter for dark bg)
--app-provider-xtream: #818cf8;
--app-provider-stalker: #34d399;
--app-provider-m3u: #fbbf24;
// Hero section
--app-accent-gradient: linear-gradient(
135deg,
rgba(99, 102, 241, 0.12) 0%,
rgba(168, 85, 247, 0.07) 100%
);
--app-hero-surface: rgba(30, 35, 48, 0.9);
}
}
+44 -15
View File
@@ -1,8 +1,21 @@
// @import 'themes/';
// ─── Tailwind CSS ─────────────────────────────────────────────────────────────
// Preflight is disabled in tailwind.config.js to avoid conflicts with
// Angular Material. Only components + utilities are loaded.
@tailwind base;
@tailwind components;
@tailwind utilities;
// ─── Third-party ─────────────────────────────────────────────────────────────
@import '@yangkghjh/videojs-aspect-ratio-panel/dist/videojs-aspect-ratio-panel.css';
@import '../../../libs/ui/components/src/lib/resizable/resizable.scss';
// macOS specific styles - space for traffic lights
// ─── Google Fonts ─────────────────────────────────────────────────────────────
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
// ─── Shared Components ────────────────────────────────────────────────────────
@import './nav-list.scss';
// ─── macOS specific: space for traffic lights ─────────────────────────────────
app-root.macos-platform app-header .modern-header {
padding-left: 80px;
}
@@ -15,13 +28,20 @@ app-root.macos-platform app-navigation .portal-status-container {
padding-top: 30px;
}
// ─── Base ─────────────────────────────────────────────────────────────────────
body,
html {
user-select: none;
margin: 0;
padding: 0;
height: 100%;
font-family: Roboto, 'Helvetica Neue', sans-serif;
font-family:
'Inter',
'Roboto',
'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// Re-enable context menu and text selection for input fields
@@ -37,9 +57,7 @@ textarea {
}
}
.full-width {
width: 100%;
}
// ─── Utilities ────────────────────────────────────────────────────────────────
.mat-tab-label-active {
opacity: 1 !important;
}
@@ -51,26 +69,36 @@ textarea,
outline: none;
}
// ─── Dark Theme ───────────────────────────────────────────────────────────────
.dark-theme {
background: var(--mat-sys-surface) !important;
// Refined scrollbar for dark mode
::-webkit-scrollbar {
overflow-y: scroll;
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: rgb(60 60 60);
border-radius: 10px;
background-color: var(--mat-sys-outline-variant);
border-radius: 999px;
&:hover {
background-color: var(--mat-sys-outline);
}
}
}
.mb-10 {
margin-bottom: 10px;
}
// ─── Dialogs ──────────────────────────────────────────────────────────────────
.about-dialog-overlay {
.mat-mdc-dialog-surface {
text-align: center;
background: black !important;
color: #fff !important;
background: var(--mat-sys-surface) !important;
color: var(--mat-sys-on-surface) !important;
padding: 10px;
}
}
@@ -94,3 +122,4 @@ textarea,
.global-search-overlay .mat-mdc-dialog-container {
app-region: no-drag;
}
+56
View File
@@ -0,0 +1,56 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
// Content paths scoped to the Angular web app and shared libs
content: [
'./apps/web/src/**/*.{html,ts,scss}',
'./libs/**/*.{html,ts,scss}',
],
// Match Angular Material's dark theme class strategy
darkMode: 'class',
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'Roboto', 'Helvetica Neue', 'sans-serif'],
},
colors: {
// Surface colors wired to Material sys vars so Tailwind
// utilities automatically respect the active theme
surface: 'var(--mat-sys-surface)',
'surface-low': 'var(--mat-sys-surface-container-low)',
'surface-mid': 'var(--mat-sys-surface-container)',
'surface-high': 'var(--mat-sys-surface-container-high)',
'on-surface': 'var(--mat-sys-on-surface)',
'on-surface-variant': 'var(--mat-sys-on-surface-variant)',
outline: 'var(--mat-sys-outline)',
'outline-variant': 'var(--mat-sys-outline-variant)',
primary: 'var(--mat-sys-primary)',
'on-primary': 'var(--mat-sys-on-primary)',
'primary-container': 'var(--mat-sys-primary-container)',
'on-primary-container': 'var(--mat-sys-on-primary-container)',
secondary: 'var(--mat-sys-secondary)',
'secondary-container': 'var(--mat-sys-secondary-container)',
'on-secondary-container':
'var(--mat-sys-on-secondary-container)',
tertiary: 'var(--mat-sys-tertiary)',
'tertiary-container': 'var(--mat-sys-tertiary-container)',
error: 'var(--mat-sys-error)',
'error-container': 'var(--mat-sys-error-container)',
},
borderRadius: {
widget: '14px',
pill: '999px',
card: '18px',
},
boxShadow: {
widget: '0 1px 4px rgba(0,0,0,0.12), 0 0 0 1px rgba(255,255,255,0.04)',
'widget-hover':
'0 4px 16px rgba(0,0,0,0.22), 0 0 0 1px rgba(255,255,255,0.06)',
card: '0 2px 8px rgba(0,0,0,0.15)',
},
},
},
// CRITICAL: disable preflight to avoid conflicts with Angular Material
corePlugins: {
preflight: false,
},
};