-theme demo
All checks were successful
Build Docker Image / Build Docker Image (push) Successful in 6m57s
Build Docker Image / Restart Docker Compose (push) Successful in 1s

This commit is contained in:
x2Skyz
2025-11-29 12:54:41 +07:00
parent 07c19bd46a
commit f0f3392dbb
7 changed files with 135 additions and 4 deletions

View File

@@ -1,4 +1,5 @@
import { Component } from '@angular/core';
import { Component, OnInit } from '@angular/core';
import { ThemeService } from './services/theme.service';
@Component({
selector: 'app-root',
@@ -6,6 +7,13 @@ import { Component } from '@angular/core';
standalone: false,
styleUrl: './app.component.css'
})
export class AppComponent {
export class AppComponent implements OnInit {
constructor(private themeService: ThemeService) {}
title = 'ng-ttc-frontend';
ngOnInit(): void {
// โหลดธีมเมื่อคอมโพเนนต์เริ่มต้นทำงาน
this.themeService.getCurrentTheme();
}
}

View File

@@ -29,6 +29,7 @@ import { MainProject } from './component/main-project/main-project';
import { MainProjectContent } from './content/main-project-content/main-project-content';
import { MainProjectAdd } from './component/main-project-add/main-project-add';
import { BudgetAprovalContent } from './content/budget-aproval-content/budget-aproval-content';
import { ThemeSwitcherComponent } from './component/theme-switcher/theme-switcher';
// import { BudgetAproval } from './component/budget-aproval/budget-aproval';
// import { AccDateFormatPipe } from './pipe/dtmtodatetime.pipe';
// import { DtmtodatetimePipe } from './dtmtodatetime.pipe';
@@ -41,6 +42,7 @@ import { BudgetAprovalContent } from './content/budget-aproval-content/budget-ap
SidebarComponent,
LicensePrivacyTermsComponent,
TokenTimerComponent,
// ThemeSwitcherComponent,
// BudgetAprovalContent
// MainProjectAdd,
// MainProject,

View File

@@ -0,0 +1 @@
<p>theme-switcher works!</p>

View File

@@ -0,0 +1,44 @@
import { Component } from '@angular/core';
import { ThemeService } from '../../services/theme.service';
@Component({
selector: 'app-theme-switcher',
template: `
<div class="flex items-center gap-2 p-2 bg-white rounded-lg shadow-sm border border-gray-200">
<span class="text-sm font-medium text-gray-600">Theme:</span>
<!-- ปุ่มสีแดง -->
<button (click)="changeTheme('theme-red')"
class="w-6 h-6 rounded-full bg-red-900 border-2 border-white shadow-sm hover:scale-110 transition-transform ring-1 ring-gray-200"
[class.ring-red-500]="currentTheme === 'theme-red'">
</button>
<!-- ปุ่มสีน้ำเงิน -->
<button (click)="changeTheme('theme-blue')"
class="w-6 h-6 rounded-full bg-blue-900 border-2 border-white shadow-sm hover:scale-110 transition-transform ring-1 ring-gray-200"
[class.ring-blue-500]="currentTheme === 'theme-blue'">
</button>
<!-- ปุ่มสีเขียว -->
<button (click)="changeTheme('theme-green')"
class="w-6 h-6 rounded-full bg-green-900 border-2 border-white shadow-sm hover:scale-110 transition-transform ring-1 ring-gray-200"
[class.ring-green-500]="currentTheme === 'theme-green'">
</button>
</div>
`,
standalone: true
})
export class ThemeSwitcherComponent {
currentTheme: string;
constructor(
private themeService: ThemeService
) {
this.currentTheme = this.themeService.getCurrentTheme();
}
changeTheme(theme: string) {
this.themeService.setTheme(theme);
this.currentTheme = theme;
}
}

View File

@@ -0,0 +1,41 @@
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ThemeService {
private currentTheme: string = 'theme-red'; // ธีมเริ่มต้น
constructor() {
this.loadTheme();
}
// โหลดธีมจาก LocalStorage หรือใช้ค่าเริ่มต้น
private loadTheme() {
const savedTheme = localStorage.getItem('app-theme');
if (savedTheme) {
this.currentTheme = savedTheme;
}
this.applyTheme(this.currentTheme);
}
// ฟังก์ชันเปลี่ยนธีม
setTheme(themeName: string) {
this.currentTheme = themeName;
localStorage.setItem('app-theme', themeName);
this.applyTheme(themeName);
}
// อัปเดต Class ที่ <html> tag
private applyTheme(theme: string) {
// ลบธีมเก่าออกทั้งหมด (สมมติมี theme-red, theme-blue, theme-green)
document.documentElement.classList.remove('theme-red', 'theme-blue', 'theme-green');
// เพิ่มธีมใหม่
document.documentElement.classList.add(theme);
}
getCurrentTheme() {
return this.currentTheme;
}
}

View File

@@ -1,5 +1,40 @@
@import "tailwindcss";
/* กำหนดตัวแปรสีพื้นฐาน */
:root {
/* Default (Red Theme) */
--color-primary-50: #fef2f2;
--color-primary-100: #fee2e2;
--color-primary-500: #ef4444;
--color-primary-600: #dc2626;
--color-primary-900: #7f1d1d; /* สีแดงเข้มที่คุณใช้บ่อย */
--color-primary-950: #450a0a;
}
/* Blue Theme Override */
.theme-blue {
--color-primary-50: #eff6ff;
--color-primary-100: #dbeafe;
--color-primary-500: #3b82f6;
--color-primary-600: #2563eb;
--color-primary-900: #1e3a8a; /* สีน้ำเงินเข้ม */
--color-primary-950: #172554;
}
/* Green Theme Override */
.theme-green {
--color-primary-50: #f0fdf4;
--color-primary-100: #dcfce7;
--color-primary-500: #22c55e;
--color-primary-600: #16a34a;
--color-primary-900: #14532d;
--color-primary-950: #052e16;
}
/* ... CSS อื่นๆ ของคุณ ... */
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
/* Global base styles for the app. Keep lightweight and self-contained so
the login component can reliably fill the viewport without producing
an outer page scrollbar. */
@@ -92,7 +127,7 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Prevent the browser from showing a scroll bar for the page itself;
the login card will scroll internally if needed. */
the login card will scroll internally if needed. */
}
/* Simple utilities used by nested components in this workspace */
@@ -108,7 +143,7 @@ body {
padding: 10px;
margin: 10px;
/* Use flex centering so nested components (like the login widget)
are centered without forcing the document to scroll. */
are centered without forcing the document to scroll. */
display: flex;
align-items: center;
justify-content: center;