feat: implement theming system with persistence and add new themes

This commit is contained in:
letieu
2025-12-10 06:08:01 +07:00
parent db618b99fc
commit 2e91f3a1c1
16 changed files with 457 additions and 16 deletions

View File

@@ -835,7 +835,8 @@ ol.content li::before {
}
.progress::-webkit-progress-value {
background: var(--primary);
background: var.
--primary);
}
.progress::-moz-progress-bar {

View File

@@ -6,16 +6,14 @@
<title>terminal.css - Terminal CSS Component Library</title>
<!-- terminal.css Components (Bulma-style) -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/gh/letieu/terminal.css@v0.0.3/index.css"
/>
<link rel="stylesheet" href="index.css" />
<link rel="stylesheet" href="themes/default.css" id="theme-switcher" />
<!-- Tailwind for layout (optional) -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- terminal.css JavaScript -->
<script src="https://cdn.jsdelivr.net/gh/letieu/terminal.css@v0.0.3/index.js"></script>
<script src="index.js"></script>
</head>
<body class="min-h-screen p-0 md:p-8">
<!-- MAIN TERMINAL WINDOW -->
@@ -28,7 +26,22 @@
<div class="w-3 h-3 rounded-full bg-green-500"></div>
</div>
<div class="has-text-muted text-sm font-bold">dev@localhost:~/</div>
<div class="has-text-muted text-xs" style="opacity: 0.5">v0.0.3</div>
<div class="flex items-center gap-2">
<label for="theme-selector" class="has-text-muted text-xs">Theme:</label>
<select id="theme-selector" class="select" style="width: auto;">
<option value="default">Default</option>
<option value="dracula">Dracula</option>
<option value="light">Light</option>
<option value="gruvbox-dark">Gruvbox Dark</option>
<option value="gruvbox-light">Gruvbox Light</option>
<option value="ayu-dark">Ayu Dark</option>
<option value="ayu-light">Ayu Light</option>
<option value="rose-pine">Rosé Pine</option>
<option value="rose-pine-light">Rosé Pine Light</option>
<option value="catppuccin-mocha">Catppuccin Mocha</option>
<option value="catppuccin-latte">Catppuccin Latte</option>
</select>
</div>
</div>
<!-- BODY -->

View File

@@ -69,10 +69,40 @@ function showToast(type, title, message, duration = 5000) {
*/
function dismissToast(closeButton) {
const toast = closeButton.closest('.toast');
toast.classList.add('is-dismissing');
if (toast) {
toast.classList.add('is-dismissing');
// Remove from DOM after animation
setTimeout(() => {
toast.remove();
}, 300);
// Remove from DOM after animation
setTimeout(() => {
toast.remove();
}, 300);
}
}
function initializeThemeSwitcher() {
const themeSelector = document.getElementById("theme-selector");
const themeSwitcher = document.getElementById("theme-switcher");
if (!themeSwitcher) {
return;
}
function applyTheme(theme) {
themeSwitcher.setAttribute("href", `themes/${theme}.css`);
localStorage.setItem("theme", theme);
if (themeSelector) {
themeSelector.value = theme;
}
}
if (themeSelector) {
themeSelector.addEventListener("change", () => {
applyTheme(themeSelector.value);
});
}
const savedTheme = localStorage.getItem("theme") || "default";
applyTheme(savedTheme);
}
document.addEventListener("DOMContentLoaded", initializeThemeSwitcher);

View File

@@ -7,6 +7,7 @@
<!-- terminal.css Components (Bulma-style) -->
<link rel="stylesheet" href="./index.css" />
<link rel="stylesheet" href="themes/default.css" id="theme-switcher" />
<!-- Tailwind for layout (optional) -->
<script src="https://cdn.tailwindcss.com"></script>
@@ -27,7 +28,22 @@
<div class="has-text-muted text-sm font-bold">
dev@localhost:~/tcss/installation
</div>
<div class="has-text-muted text-xs" style="opacity: 0.5">v0.0.3</div>
<div class="flex items-center gap-2">
<label for="theme-selector" class="has-text-muted text-xs">Theme:</label>
<select id="theme-selector" class="select" style="width: auto;">
<option value="default">Default</option>
<option value="dracula">Dracula</option>
<option value="light">Light</option>
<option value="gruvbox-dark">Gruvbox Dark</option>
<option value="gruvbox-light">Gruvbox Light</option>
<option value="ayu-dark">Ayu Dark</option>
<option value="ayu-light">Ayu Light</option>
<option value="rose-pine">Rosé Pine</option>
<option value="rose-pine-light">Rosé Pine Light</option>
<option value="catppuccin-mocha">Catppuccin Mocha</option>
<option value="catppuccin-latte">Catppuccin Latte</option>
</select>
</div>
</div>
<!-- BODY -->
@@ -391,6 +407,97 @@
</div>
</section>
<!-- SECTION 4: THEMEING -->
<section class="section">
<div class="flex items-center gap-2 mb-6">
<span class="has-text-primary text-xl font-bold">04.</span>
<h2 class="text-xl font-bold">Theming</h2>
</div>
<div class="space-y-4">
<p class="has-text-muted">
terminal.css includes a theming system that allows you to easily switch between different color schemes. The selected theme is persisted across pages using the browser's <code>localStorage</code>.
</p>
<h4 class="has-text-muted text-sm mb-3">How to use themes:</h4>
<ol class="content">
<li class="mb-2">
Include the main <code>index.css</code> stylesheet and then a theme stylesheet in your <code>&lt;head&gt;</code> section. The theme stylesheet must have the ID <code>theme-switcher</code>.
</li>
</ol>
<div class="terminal-log">
<div class="terminal-log-line">
<span class="terminal-log-message has-text-muted"
>&lt;!-- In your &lt;head&gt; section --&gt;</span
>
</div>
<div class="terminal-log-line">
<span class="terminal-log-message"
>&lt;link rel="stylesheet" href="./index.css" /&gt;</span
>
</div>
<div class="terminal-log-line">
<span class="terminal-log-message"
>&lt;link rel="stylesheet" href="themes/default.css" id="theme-switcher" /&gt;</span
>
</div>
</div>
<p class="has-text-muted text-sm mt-4">
To enable theme switching and persistence, include the <code>index.js</code> script at the end of your <code>&lt;body&gt;</code> tag. This script contains the necessary logic to manage themes.
</p>
<div class="terminal-log">
<div class="terminal-log-line">
<span class="terminal-log-message has-text-muted"
>&lt;!-- Before closing &lt;/body&gt; tag --&gt;</span
>
</div>
<div class="terminal-log-line">
<span class="terminal-log-message"
>&lt;script src="./index.js"&gt;&lt;/script&gt;</span
>
</div>
</div>
<p class="has-text-muted text-sm mt-4">
You can then add a theme selector dropdown to your HTML, like this:
</p>
<div class="terminal-log">
<div class="terminal-log-line">
<span class="terminal-log-message"
>&lt;select id="theme-selector" class="select"&gt;</span
>
</div>
<div class="terminal-log-line">
<span class="terminal-log-message"
>&nbsp;&nbsp;&lt;option value="default"&gt;Default&lt;/option&gt;</span
>
</div>
<div class="terminal-log-line">
<span class="terminal-log-message"
>&nbsp;&nbsp;&lt;option value="dracula"&gt;Dracula&lt;/option&gt;</span
>
</div>
<div class="terminal-log-line">
<span class="terminal-log-message"
>&nbsp;&nbsp;&lt;option value="light"&gt;Light&lt;/option&gt;</span
>
</div>
<div class="terminal-log-line">
<span class="terminal-log-message"
>&lt;/select&gt;</span
>
</div>
</div>
<p class="has-text-muted text-sm mt-4">
The <code>value</code> attribute of each option should match the filename of the theme (e.g., <code>default</code> for <code>themes/default.css</code>).
</p>
</div>
</section>
<!-- FOOTER -->
<div class="pt-12 mt-12 border-t border-gray-800">
<div class="flex justify-between items-center">

View File

@@ -7,6 +7,7 @@
<!-- terminal.css Components (Bulma-style) -->
<link rel="stylesheet" href="./index.css" />
<link rel="stylesheet" href="themes/default.css" id="theme-switcher" />
<!-- Tailwind for layout (optional) -->
<script src="https://cdn.tailwindcss.com"></script>
@@ -59,8 +60,24 @@
<p class="subtitle is-4 mb-6">
Terminal-style components with Bulma naming conventions
</p>
<div class="flex gap-3 justify-center">
<div class="flex gap-3 justify-center items-center">
<a href="./index.html" class="button is-primary">Get Started</a>
<div class="flex items-center gap-2">
<label for="theme-selector" class="has-text-muted text-xs">Theme:</label>
<select id="theme-selector" class="select" style="width: auto;">
<option value="default">Default</option>
<option value="dracula">Dracula</option>
<option value="light">Light</option>
<option value="gruvbox-dark">Gruvbox Dark</option>
<option value="gruvbox-light">Gruvbox Light</option>
<option value="ayu-dark">Ayu Dark</option>
<option value="ayu-light">Ayu Light</option>
<option value="rose-pine">Rosé Pine</option>
<option value="rose-pine-light">Rosé Pine Light</option>
<option value="catppuccin-mocha">Catppuccin Mocha</option>
<option value="catppuccin-latte">Catppuccin Latte</option>
</select>
</div>
</div>
</div>

25
themes/ayu-dark.css Normal file
View File

@@ -0,0 +1,25 @@
:root {
--terminal-bg: #0A0E14;
--terminal-fg: #B3B1AD;
/* ANSI Palette */
--terminal-black: #01060E;
--terminal-red: #FF3333;
--terminal-green: #BAE67E;
--terminal-yellow: #FFD580;
--terminal-blue: #73D0FF;
--terminal-magenta: #D4BFFF;
--terminal-cyan: #5FD7FF;
--terminal-white: #D9D7CE;
--terminal-purple: #D4BFFF;
/* Semantic Colors */
--primary: var(--terminal-blue);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-cyan);
--border-color: #393b44;
--surface: #1F2229;
--muted: #5C6773;
}

25
themes/ayu-light.css Normal file
View File

@@ -0,0 +1,25 @@
:root {
--terminal-bg: #fafafa;
--terminal-fg: #5c6773;
/* ANSI Palette */
--terminal-black: #f0f0f0;
--terminal-red: #f51818;
--terminal-green: #5e8504;
--terminal-yellow: #f2ae00;
--terminal-blue: #36a3d9;
--terminal-magenta: #a37acc;
--terminal-cyan: #4cbf99;
--terminal-white: #5c6773;
--terminal-purple: #a37acc;
/* Semantic Colors */
--primary: var(--terminal-blue);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-cyan);
--border-color: #e6e6e6;
--surface: #f5f5f5;
--muted: #8a9199;
}

View File

@@ -0,0 +1,25 @@
:root {
--terminal-bg: #eff1f5;
--terminal-fg: #4c4f69;
/* ANSI Palette */
--terminal-black: #ccd0da;
--terminal-red: #d20f39;
--terminal-green: #40a02b;
--terminal-yellow: #df8e1d;
--terminal-blue: #1e66f5;
--terminal-magenta: #8839ef;
--terminal-cyan: #04a5e5;
--terminal-white: #4c4f69;
--terminal-purple: #8839ef;
/* Semantic Colors */
--primary: var(--terminal-blue);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-cyan);
--border-color: #bcc0cc;
--surface: #e6e9ef;
--muted: #acb0be;
}

View File

@@ -0,0 +1,25 @@
:root {
--terminal-bg: #1e1e2e;
--terminal-fg: #cdd6f4;
/* ANSI Palette */
--terminal-black: #45475a;
--terminal-red: #f38ba8;
--terminal-green: #a6e3a1;
--terminal-yellow: #f9e2af;
--terminal-blue: #89b4fa;
--terminal-magenta: #cba6f7;
--terminal-cyan: #89dceb;
--terminal-white: #bac2de;
--terminal-purple: #cba6f7;
/* Semantic Colors */
--primary: var(--terminal-blue);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-cyan);
--border-color: #585b70;
--surface: #313244;
--muted: #a6adc8;
}

24
themes/default.css Normal file
View File

@@ -0,0 +1,24 @@
:root {
--terminal-bg: #050505;
--terminal-fg: #cccccc;
/* ANSI Palette */
--terminal-black: #000000;
--terminal-red: #ff5555;
--terminal-green: #50fa7b;
--terminal-yellow: #f1fa8c;
--terminal-blue: #bd93f9;
--terminal-magenta: #ff79c6;
--terminal-cyan: #8be9fd;
--terminal-white: #ffffff;
/* Semantic Colors */
--primary: var(--terminal-cyan);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-blue);
--border-color: #333333;
--surface: #000000;
--muted: #666666;
}

25
themes/dracula.css Normal file
View File

@@ -0,0 +1,25 @@
:root {
--terminal-bg: #282a36;
--terminal-fg: #f8f8f2;
/* ANSI Palette */
--terminal-black: #000000;
--terminal-red: #ff5555;
--terminal-green: #50fa7b;
--terminal-yellow: #f1fa8c;
--terminal-blue: #bd93f9;
--terminal-magenta: #ff79c6;
--terminal-cyan: #8be9fd;
--terminal-white: #f8f8f2;
--terminal-purple: #bd93f9;
/* Semantic Colors */
--primary: var(--terminal-purple);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-cyan);
--border-color: #44475a;
--surface: #282a36;
--muted: #6272a4;
}

25
themes/gruvbox-dark.css Normal file
View File

@@ -0,0 +1,25 @@
:root {
--terminal-bg: #282828;
--terminal-fg: #ebdbb2;
/* ANSI Palette */
--terminal-black: #282828;
--terminal-red: #cc241d;
--terminal-green: #98971a;
--terminal-yellow: #d79921;
--terminal-blue: #458588;
--terminal-magenta: #b16286;
--terminal-cyan: #689d6a;
--terminal-white: #a89984;
--terminal-purple: #b16286;
/* Semantic Colors */
--primary: var(--terminal-blue);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-cyan);
--border-color: #504945;
--surface: #3c3836;
--muted: #928374;
}

25
themes/gruvbox-light.css Normal file
View File

@@ -0,0 +1,25 @@
:root {
--terminal-bg: #fbf1c7;
--terminal-fg: #3c3836;
/* ANSI Palette */
--terminal-black: #fbf1c7;
--terminal-red: #9d0006;
--terminal-green: #79740e;
--terminal-yellow: #b57614;
--terminal-blue: #076678;
--terminal-magenta: #8f3f71;
--terminal-cyan: #427b58;
--terminal-white: #3c3836;
--terminal-purple: #8f3f71;
/* Semantic Colors */
--primary: var(--terminal-blue);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-cyan);
--border-color: #d5c4a1;
--surface: #ebdbb2;
--muted: #7c6f64;
}

24
themes/light.css Normal file
View File

@@ -0,0 +1,24 @@
:root {
--terminal-bg: #f5f5f5;
--terminal-fg: #333333;
/* ANSI Palette */
--terminal-black: #000000;
--terminal-red: #dc3545;
--terminal-green: #28a745;
--terminal-yellow: #ffc107;
--terminal-blue: #007bff;
--terminal-magenta: #e83e8c;
--terminal-cyan: #17a2b8;
--terminal-white: #ffffff;
/* Semantic Colors */
--primary: var(--terminal-blue);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-cyan);
--border-color: #dddddd;
--surface: #ffffff;
--muted: #6c757d;
}

View File

@@ -0,0 +1,25 @@
:root {
--terminal-bg: #faf4ed;
--terminal-fg: #575279;
/* ANSI Palette */
--terminal-black: #f2e9de;
--terminal-red: #d7827e;
--terminal-green: #286983;
--terminal-yellow: #ea9d34;
--terminal-blue: #56949f;
--terminal-magenta: #907aa9;
--terminal-cyan: #d7827e;
--terminal-white: #575279;
--terminal-purple: #907aa9;
/* Semantic Colors */
--primary: var(--terminal-blue);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-cyan);
--border-color: #e4e2e0;
--surface: #fffaf3;
--muted: #9893a5;
}

25
themes/rose-pine.css Normal file
View File

@@ -0,0 +1,25 @@
:root {
--terminal-bg: #191724;
--terminal-fg: #e0def4;
/* ANSI Palette */
--terminal-black: #26233a;
--terminal-red: #eb6f92;
--terminal-green: #31748f;
--terminal-yellow: #f6c177;
--terminal-blue: #9ccfd8;
--terminal-magenta: #c4a7e7;
--terminal-cyan: #ebbcba;
--terminal-white: #e0def4;
--terminal-purple: #c4a7e7;
/* Semantic Colors */
--primary: var(--terminal-blue);
--danger: var(--terminal-red);
--success: var(--terminal-green);
--warning: var(--terminal-yellow);
--info: var(--terminal-cyan);
--border-color: #555169;
--surface: #1f1d2e;
--muted: #6e6a86;
}