|
22 | 22 | <!-- Custom Tailwind Config --> |
23 | 23 | <script> |
24 | 24 | tailwind.config = { |
| 25 | + darkMode: 'class', |
25 | 26 | theme: { |
26 | 27 | extend: { |
27 | 28 | fontFamily: { |
28 | 29 | sans: ['Aspekta', 'system-ui', 'sans-serif'], |
29 | 30 | serif: ['Source Serif Pro', 'Georgia', 'serif'], |
30 | 31 | }, |
31 | 32 | colors: { |
32 | | - background: 'rgb(255, 255, 255)', |
33 | | - foreground: 'rgb(22, 22, 20)', |
34 | | - card: 'rgb(249, 249, 247)', |
35 | | - 'card-foreground': 'rgb(22, 22, 20)', |
36 | | - primary: 'rgb(217, 94, 42)', |
37 | | - 'primary-foreground': 'rgb(255, 255, 255)', |
38 | | - secondary: 'rgb(249, 249, 247)', |
39 | | - 'secondary-foreground': 'rgb(22, 22, 20)', |
40 | | - muted: 'rgb(240, 240, 236)', |
41 | | - 'muted-foreground': 'rgb(127, 127, 121)', |
42 | | - accent: 'rgb(217, 94, 42)', |
43 | | - destructive: 'rgb(180, 51, 50)', |
44 | | - border: 'rgb(221, 221, 215)', |
45 | | - input: 'rgb(221, 221, 215)', |
46 | | - ring: 'rgb(217, 94, 42)', |
| 33 | + background: 'var(--color-background)', |
| 34 | + foreground: 'var(--color-foreground)', |
| 35 | + card: 'var(--color-card)', |
| 36 | + 'card-foreground': 'var(--color-card-foreground)', |
| 37 | + primary: 'var(--color-primary)', |
| 38 | + 'primary-foreground': 'var(--color-primary-foreground)', |
| 39 | + secondary: 'var(--color-secondary)', |
| 40 | + 'secondary-foreground': 'var(--color-secondary-foreground)', |
| 41 | + muted: 'var(--color-muted)', |
| 42 | + 'muted-foreground': 'var(--color-muted-foreground)', |
| 43 | + accent: 'var(--color-accent)', |
| 44 | + destructive: 'var(--color-destructive)', |
| 45 | + border: 'var(--color-border)', |
| 46 | + input: 'var(--color-input)', |
| 47 | + ring: 'var(--color-ring)', |
47 | 48 | }, |
48 | 49 | borderRadius: { |
49 | 50 | lg: '0.625rem', |
|
58 | 59 | {{block "head" .}}{{end}} |
59 | 60 |
|
60 | 61 | <style> |
| 62 | + :root { |
| 63 | + --color-background: #ffffff; |
| 64 | + --color-foreground: #161614; |
| 65 | + --color-card: #f9f9f7; |
| 66 | + --color-card-foreground: #161614; |
| 67 | + --color-primary: rgb(217, 94, 42); |
| 68 | + --color-primary-foreground: #ffffff; |
| 69 | + --color-secondary: #f9f9f7; |
| 70 | + --color-secondary-foreground: #161614; |
| 71 | + --color-muted: #f0f0ec; |
| 72 | + --color-muted-foreground: #7f7f79; |
| 73 | + --color-accent: rgb(217, 94, 42); |
| 74 | + --color-destructive: rgb(180, 51, 50); |
| 75 | + --color-border: #ddddd7; |
| 76 | + --color-input: #ddddd7; |
| 77 | + --color-ring: rgb(217, 94, 42); |
| 78 | + --color-green: #16a34a; |
| 79 | + --color-red: #dc2626; |
| 80 | + } |
| 81 | + .dark { |
| 82 | + --color-background: #141413; |
| 83 | + --color-foreground: #ededeb; |
| 84 | + --color-card: #1c1c1a; |
| 85 | + --color-card-foreground: #ededeb; |
| 86 | + --color-primary: rgb(217, 94, 42); |
| 87 | + --color-primary-foreground: #ffffff; |
| 88 | + --color-secondary: #232320; |
| 89 | + --color-secondary-foreground: #ededeb; |
| 90 | + --color-muted: #2a2a27; |
| 91 | + --color-muted-foreground: #9a9a94; |
| 92 | + --color-accent: rgb(217, 94, 42); |
| 93 | + --color-destructive: rgb(220, 80, 78); |
| 94 | + --color-border: #3a3a36; |
| 95 | + --color-input: #3a3a36; |
| 96 | + --color-ring: rgb(217, 94, 42); |
| 97 | + --color-green: #22c55e; |
| 98 | + --color-red: #ef4444; |
| 99 | + } |
61 | 100 | @font-face { font-family: 'Aspekta'; src: url('{{.Prefix}}/static/fonts/Aspekta-500.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; } |
62 | 101 | @font-face { font-family: 'Aspekta'; src: url('{{.Prefix}}/static/fonts/Aspekta-600.woff2') format('woff2'); font-weight: 600; font-style: normal; font-display: swap; } |
63 | 102 | @font-face { font-family: 'Aspekta'; src: url('{{.Prefix}}/static/fonts/Aspekta-700.woff2') format('woff2'); font-weight: 700; font-style: normal; font-display: swap; } |
|
69 | 108 | .htmx-request .htmx-indicator { display: inline-block; } |
70 | 109 | .htmx-request.htmx-indicator { display: inline-block; } |
71 | 110 | </style> |
| 111 | + |
| 112 | + <!-- Theme initialization (runs before paint to prevent flash) --> |
| 113 | + <script> |
| 114 | + (function() { |
| 115 | + var stored = localStorage.getItem('theme'); |
| 116 | + if (stored === 'dark' || (!stored && window.matchMedia('(prefers-color-scheme: dark)').matches)) { |
| 117 | + document.documentElement.classList.add('dark'); |
| 118 | + } |
| 119 | + })(); |
| 120 | + </script> |
72 | 121 | </head> |
73 | 122 |
|
74 | 123 | <body class="bg-background text-foreground min-h-screen"> |
|
77 | 126 | <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> |
78 | 127 | <div class="flex justify-between h-12"> |
79 | 128 | <a href="{{.Prefix}}/dashboard" class="flex-shrink-0 flex items-center cursor-pointer no-underline"> |
80 | | - <img src="{{.Prefix}}/static/icons/greyhaven-icon.svg" alt="Greyproxy" class="h-8 w-auto"> |
| 129 | + <img src="{{.Prefix}}/static/icons/greyhaven-icon.svg" alt="Greyproxy" class="h-8 w-auto nav-logo"> |
81 | 130 | <span class="ml-3 text-xl font-semibold font-sans text-foreground">Greyproxy</span> |
82 | 131 | </a> |
83 | 132 | <!-- Mobile menu button --> |
84 | | - <div class="flex items-center sm:hidden"> |
| 133 | + <div class="flex items-center sm:hidden space-x-1"> |
| 134 | + <button type="button" onclick="toggleTheme()" class="btn-plain p-2 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted" title="Toggle theme"> |
| 135 | + <svg class="h-5 w-5 hidden dark:block" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> |
| 136 | + <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" /> |
| 137 | + </svg> |
| 138 | + <svg class="h-5 w-5 block dark:hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> |
| 139 | + <path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" /> |
| 140 | + </svg> |
| 141 | + </button> |
85 | 142 | <button type="button" onclick="document.getElementById('mobile-menu').classList.toggle('hidden')" |
86 | 143 | class="inline-flex items-center justify-center p-2 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted focus:outline-none focus:ring-2 focus:ring-inset focus:ring-primary"> |
87 | 144 | <svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> |
|
90 | 147 | </button> |
91 | 148 | </div> |
92 | 149 | <!-- Desktop nav (right-aligned) --> |
93 | | - <div class="hidden sm:flex sm:space-x-8"> |
| 150 | + <div class="hidden sm:flex sm:space-x-8 sm:items-stretch"> |
94 | 151 | <a href="{{.Prefix}}/dashboard" |
95 | | - class="{{if contains .CurrentPath "/dashboard"}}border-primary text-foreground{{else}}border-transparent text-muted-foreground hover:border-border hover:text-foreground{{end}} inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium"> |
| 152 | + class="{{if contains .CurrentPath "/dashboard"}}border-primary text-foreground{{else}}border-transparent text-muted-foreground hover:border-border hover:text-foreground{{end}} inline-flex items-center px-1 pt-[2px] border-b-2 text-sm font-medium"> |
96 | 153 | Dashboard |
97 | 154 | </a> |
98 | 155 | <a href="{{.Prefix}}/pending" |
99 | | - class="{{if contains .CurrentPath "/pending"}}border-primary text-foreground{{else}}border-transparent text-muted-foreground hover:border-border hover:text-foreground{{end}} inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium"> |
| 156 | + class="{{if contains .CurrentPath "/pending"}}border-primary text-foreground{{else}}border-transparent text-muted-foreground hover:border-border hover:text-foreground{{end}} inline-flex items-center px-1 pt-[2px] border-b-2 text-sm font-medium"> |
100 | 157 | Pending Requests |
101 | 158 | <span id="pending-badge" class="hidden ml-1.5 inline-flex items-center justify-center px-1.5 py-0.5 text-xs font-bold leading-none text-primary-foreground bg-primary rounded-full min-w-[1.25rem]"></span> |
102 | 159 | </a> |
103 | 160 | <a href="{{.Prefix}}/rules" |
104 | | - class="{{if contains .CurrentPath "/rules"}}border-primary text-foreground{{else}}border-transparent text-muted-foreground hover:border-border hover:text-foreground{{end}} inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium"> |
| 161 | + class="{{if contains .CurrentPath "/rules"}}border-primary text-foreground{{else}}border-transparent text-muted-foreground hover:border-border hover:text-foreground{{end}} inline-flex items-center px-1 pt-[2px] border-b-2 text-sm font-medium"> |
105 | 162 | Rules |
106 | 163 | </a> |
107 | 164 | <a href="{{.Prefix}}/logs" |
108 | | - class="{{if contains .CurrentPath "/logs"}}border-primary text-foreground{{else}}border-transparent text-muted-foreground hover:border-border hover:text-foreground{{end}} inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium"> |
| 165 | + class="{{if contains .CurrentPath "/logs"}}border-primary text-foreground{{else}}border-transparent text-muted-foreground hover:border-border hover:text-foreground{{end}} inline-flex items-center px-1 pt-[2px] border-b-2 text-sm font-medium"> |
109 | 166 | Logs |
110 | 167 | </a> |
| 168 | + <button type="button" onclick="toggleTheme()" class="btn-plain ml-2 p-1.5 self-center rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors" title="Toggle theme"> |
| 169 | + <svg class="h-5 w-5 hidden dark:block" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> |
| 170 | + <path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" /> |
| 171 | + </svg> |
| 172 | + <svg class="h-5 w-5 block dark:hidden" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> |
| 173 | + <path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" /> |
| 174 | + </svg> |
| 175 | + </button> |
111 | 176 | </div> |
112 | 177 | </div> |
113 | 178 | <!-- Mobile menu dropdown --> |
|
144 | 209 | <div id="toast-container" class="fixed bottom-4 right-4 z-50 space-y-2"></div> |
145 | 210 |
|
146 | 211 | <script> |
| 212 | + function toggleTheme() { |
| 213 | + var isDark = document.documentElement.classList.toggle('dark'); |
| 214 | + localStorage.setItem('theme', isDark ? 'dark' : 'light'); |
| 215 | + } |
| 216 | + |
147 | 217 | function formatNumber(n) { |
148 | 218 | return Number(n).toLocaleString(); |
149 | 219 | } |
|
0 commit comments