Added theming
All checks were successful
Build dev on push / build-api (push) Successful in 7s
Build dev on push / build-redirector (push) Successful in 7s
Build dev on push / build-web (push) Successful in 48s

This commit is contained in:
Sven Heidemann 2025-01-10 21:57:47 +01:00
parent 581462d22a
commit 865e6465cf
11 changed files with 830 additions and 391 deletions

View File

@ -1 +1 @@
1.1.0 1.2.0

View File

@ -1,4 +1,4 @@
<main *ngIf="isLoggedIn && !hideUI; else home"> <main *ngIf="isLoggedIn && !hideUI; else home" [class]="theme">
<app-header></app-header> <app-header></app-header>
<div class="app"> <div class="app">

View File

@ -1,16 +1,17 @@
import { Component, OnDestroy } from "@angular/core"; import { Component, OnDestroy } from '@angular/core';
import { SidebarService } from "src/app/service/sidebar.service"; import { SidebarService } from 'src/app/service/sidebar.service';
import { Subject } from "rxjs"; import { Subject } from 'rxjs';
import { takeUntil } from "rxjs/operators"; import { takeUntil } from 'rxjs/operators';
import { AuthService } from "src/app/service/auth.service"; import { AuthService } from 'src/app/service/auth.service';
import { GuiService } from "src/app/service/gui.service"; import { GuiService } from 'src/app/service/gui.service';
@Component({ @Component({
selector: "app-root", selector: 'app-root',
templateUrl: "./app.component.html", templateUrl: './app.component.html',
styleUrl: "./app.component.scss", styleUrl: './app.component.scss',
}) })
export class AppComponent implements OnDestroy { export class AppComponent implements OnDestroy {
theme = 'open-redirect';
showSidebar = false; showSidebar = false;
hideUI = false; hideUI = false;
isLoggedIn = false; isLoggedIn = false;
@ -19,23 +20,27 @@ export class AppComponent implements OnDestroy {
constructor( constructor(
private sidebar: SidebarService, private sidebar: SidebarService,
private auth: AuthService, private auth: AuthService,
private gui: GuiService, private gui: GuiService
) { ) {
this.auth.loadUser(); this.auth.loadUser();
this.auth.user$.pipe(takeUntil(this.unsubscribe$)).subscribe((user) => { this.auth.user$.pipe(takeUntil(this.unsubscribe$)).subscribe(user => {
this.isLoggedIn = user !== null && user !== undefined; this.isLoggedIn = user !== null && user !== undefined;
}); });
this.sidebar.visible$ this.sidebar.visible$
.pipe(takeUntil(this.unsubscribe$)) .pipe(takeUntil(this.unsubscribe$))
.subscribe((visible) => { .subscribe(visible => {
this.showSidebar = visible; this.showSidebar = visible;
}); });
this.gui.hideGui$.pipe(takeUntil(this.unsubscribe$)).subscribe((hide) => { this.gui.hideGui$.pipe(takeUntil(this.unsubscribe$)).subscribe(hide => {
this.hideUI = hide; this.hideUI = hide;
}); });
this.gui.theme$.pipe(takeUntil(this.unsubscribe$)).subscribe(theme => {
this.theme = theme;
});
} }
ngOnDestroy() { ngOnDestroy() {

View File

@ -17,6 +17,18 @@
</div> </div>
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
<div class="flex items-center justify-center">
<p-button
type="button"
icon="pi pi-palette"
class="btn icon-btn p-button-text"
(onClick)="themeMenu.toggle($event)"></p-button>
<p-menu
#themeMenu
[popup]="true"
[model]="themeList"
class="lang-menu"></p-menu>
</div>
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
<p-button <p-button
type="button" type="button"

View File

@ -1,21 +1,24 @@
import { Component, OnDestroy, OnInit } from "@angular/core"; import { Component, OnDestroy, OnInit } from '@angular/core';
import { MenuItem, PrimeNGConfig } from "primeng/api"; import { MenuItem, PrimeNGConfig } from 'primeng/api';
import { Subject } from "rxjs"; import { Subject } from 'rxjs';
import { takeUntil } from "rxjs/operators"; import { takeUntil } from 'rxjs/operators';
import { TranslateService } from "@ngx-translate/core"; import { TranslateService } from '@ngx-translate/core';
import { GuiService } from "src/app/service/gui.service"; import { GuiService } from 'src/app/service/gui.service';
import { User } from "src/app/model/auth/user"; import { User } from 'src/app/model/auth/user';
import { AuthService } from "src/app/service/auth.service"; import { AuthService } from 'src/app/service/auth.service';
import { MenuElement } from "src/app/model/view/menu-element"; import { MenuElement } from 'src/app/model/view/menu-element';
import { SidebarService } from "src/app/service/sidebar.service"; import { SidebarService } from 'src/app/service/sidebar.service';
import { SettingsService } from 'src/app/service/settings.service';
@Component({ @Component({
selector: "app-header", selector: 'app-header',
templateUrl: "./header.component.html", templateUrl: './header.component.html',
styleUrls: ["./header.component.scss"], styleUrls: ['./header.component.scss'],
}) })
export class HeaderComponent implements OnInit, OnDestroy { export class HeaderComponent implements OnInit, OnDestroy {
langList: MenuItem[] = []; langList: MenuItem[] = [];
themeList: MenuItem[] = [];
userMenuList!: MenuItem[]; userMenuList!: MenuItem[];
user: User | null = null; user: User | null = null;
private unsubscribe$ = new Subject<void>(); private unsubscribe$ = new Subject<void>();
@ -29,22 +32,30 @@ export class HeaderComponent implements OnInit, OnDestroy {
private guiService: GuiService, private guiService: GuiService,
private auth: AuthService, private auth: AuthService,
private sidebarService: SidebarService, private sidebarService: SidebarService,
private settings: SettingsService
) { ) {
this.guiService.isMobile$ this.guiService.isMobile$
.pipe(takeUntil(this.unsubscribe$)) .pipe(takeUntil(this.unsubscribe$))
.subscribe((isMobile) => { .subscribe(isMobile => {
this.isMobile = isMobile; this.isMobile = isMobile;
if (isMobile) { if (isMobile) {
this.sidebarService.hide(); this.sidebarService.hide();
} }
}); });
this.auth.user$ this.auth.user$.pipe(takeUntil(this.unsubscribe$)).subscribe(async user => {
.pipe(takeUntil(this.unsubscribe$)) this.user = user;
.subscribe(async (user) => { await this.initMenuLists();
this.user = user; });
await this.initMenuLists();
}); this.themeList = this.settings.settings.themes.map(theme => {
return {
label: theme.label,
command: () => {
this.guiService.theme$.next(theme.name);
},
};
});
} }
async ngOnInit() { async ngOnInit() {
@ -69,17 +80,17 @@ export class HeaderComponent implements OnInit, OnDestroy {
async initLangMenuList() { async initLangMenuList() {
this.langList = [ this.langList = [
{ {
label: "English", label: 'English',
command: () => { command: () => {
this.translate("en"); this.translate('en');
this.setLang("en"); this.setLang('en');
}, },
}, },
{ {
label: "Deutsch", label: 'Deutsch',
command: () => { command: () => {
this.translate("de"); this.translate('de');
this.setLang("de"); this.setLang('de');
}, },
}, },
]; ];
@ -96,13 +107,13 @@ export class HeaderComponent implements OnInit, OnDestroy {
separator: true, separator: true,
}, },
{ {
label: this.translateService.instant("header.logout"), label: this.translateService.instant('header.logout'),
command: () => { command: () => {
this.auth.logout().then(() => { this.auth.logout().then(() => {
console.log("logout"); console.log('logout');
}); });
}, },
icon: "pi pi-sign-out", icon: 'pi pi-sign-out',
}, },
]; ];
} }
@ -110,19 +121,19 @@ export class HeaderComponent implements OnInit, OnDestroy {
translate(lang: string) { translate(lang: string) {
this.translateService.use(lang); this.translateService.use(lang);
this.translateService this.translateService
.get("primeng") .get('primeng')
.subscribe((res) => this.config.setTranslation(res)); .subscribe(res => this.config.setTranslation(res));
} }
async loadLang() { async loadLang() {
const lang = "en"; const lang = 'en';
this.setLang(lang); this.setLang(lang);
this.translate(lang); this.translate(lang);
} }
setLang(lang: string) { setLang(lang: string) {
// this.settings.setSetting(`lang`, lang); // this.settings.setSetting(`lang`, lang);
console.log("setLang", lang); console.log('setLang', lang);
} }
toggleSidebar() { toggleSidebar() {

View File

@ -3,6 +3,7 @@ import { BehaviorSubject, filter } from 'rxjs';
import { Logger } from 'src/app/service/logger.service'; import { Logger } from 'src/app/service/logger.service';
import { NavigationEnd, Router } from '@angular/router'; import { NavigationEnd, Router } from '@angular/router';
import { SidebarService } from 'src/app/service/sidebar.service'; import { SidebarService } from 'src/app/service/sidebar.service';
import { SettingsService } from 'src/app/service/settings.service';
const logger = new Logger('GuiService'); const logger = new Logger('GuiService');
@ -14,10 +15,14 @@ export class GuiService {
isTablet$ = new BehaviorSubject<boolean>(this.isTabletByWindowWith()); isTablet$ = new BehaviorSubject<boolean>(this.isTabletByWindowWith());
hideGui$ = new BehaviorSubject<boolean>(false); hideGui$ = new BehaviorSubject<boolean>(false);
theme$ = new BehaviorSubject<string>(
this.settingsService.settings.themes[0].name
);
constructor( constructor(
private router: Router, private router: Router,
private sidebarService: SidebarService private sidebarService: SidebarService,
private settingsService: SettingsService
) { ) {
this.router.events this.router.events
.pipe(filter(event => event instanceof NavigationEnd)) .pipe(filter(event => event instanceof NavigationEnd))

View File

@ -1,12 +1,12 @@
import { HttpClient } from "@angular/common/http"; import { HttpClient } from '@angular/common/http';
import { Injectable } from "@angular/core"; import { Injectable } from '@angular/core';
import { throwError } from "rxjs"; import { throwError } from 'rxjs';
import { catchError } from "rxjs/operators"; import { catchError } from 'rxjs/operators';
import { AppSettings } from "src/app/model/config/app-settings"; import { AppSettings } from 'src/app/model/config/app-settings';
import { environment } from "src/environments/environment"; import { environment } from 'src/environments/environment';
@Injectable({ @Injectable({
providedIn: "root", providedIn: 'root',
}) })
export class SettingsService { export class SettingsService {
settings!: AppSettings; settings!: AppSettings;
@ -18,13 +18,19 @@ export class SettingsService {
this.http this.http
.get<AppSettings>(`/assets/config/${environment.config}`) .get<AppSettings>(`/assets/config/${environment.config}`)
.pipe( .pipe(
catchError((error) => { catchError(error => {
reject(error); reject(error);
return throwError(() => error); return throwError(() => error);
}), })
) )
.subscribe((settings) => { .subscribe(settings => {
this.settings = settings; this.settings = settings;
if (this.settings.themes.length === 0) {
this.settings.themes.push({
label: 'Open-redirect',
name: 'open-redirect',
});
}
resolve(); resolve();
}); });
}); });

View File

@ -5,7 +5,11 @@
"themes": [ "themes": [
{ {
"label": "Open-redirect", "label": "Open-redirect",
"name": "Open-redirect" "name": "open-redirect"
},
{
"label": "Maxlan",
"name": "maxlan"
} }
], ],
"api": { "api": {

View File

@ -10,6 +10,7 @@
@import 'tailwindcss/utilities'; @import 'tailwindcss/utilities';
@import 'styles/theme'; @import 'styles/theme';
@import 'styles/theme_maxlan';
@import 'styles/tablet'; @import 'styles/tablet';
@import 'styles/mobile'; @import 'styles/mobile';
@ -58,7 +59,6 @@ body {
input, input,
.p-checkbox-box, .p-checkbox-box,
.p-dropdown { .p-dropdown {
border: 1px solid $accentColor;
padding: 10px; padding: 10px;
} }
@ -70,16 +70,6 @@ body {
} }
} }
@layer utilities {
.divider {
border-bottom: 1px solid $accentColor;
}
.v-divider {
border-left: 1px solid $accentColor;
}
}
header { header {
height: $headerHeight; height: $headerHeight;
display: flex; display: flex;
@ -129,7 +119,6 @@ main {
.component { .component {
margin: 0 10px; margin: 0 10px;
overflow: auto; overflow: auto;
background-color: $backgroundColor;
flex: 1; flex: 1;
padding: 10px; padding: 10px;
} }
@ -141,7 +130,6 @@ footer {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
color: $textColor;
} }
.btn { .btn {

View File

@ -1,406 +1,407 @@
$headerColor: #a2271f; .open-redirect {
$headerColor: #ef9d0d;
// generated with https://colorffy.com/dark-theme-generator?colors=314390-121212 // generated with https://colorffy.com/dark-theme-generator?colors=314390-121212
$textColor: #fff; $textColor: #fff;
$textColorHighlight: #314390; $textColorHighlight: #ef9d0d;
$textColorHighlight2: #a2271f; $textColorHighlight2: #b76f00;
// https://tailwindcss.com/docs/customizing-colors // https://tailwindcss.com/docs/customizing-colors
$backgroundColor: #1e293b; // slate-800 $backgroundColor: #1e293b; // slate-800
$backgroundColor2: #0f172a; // slate-900 $backgroundColor2: #0f172a; // slate-900
$backgroundColor3: #334155; // slate-700 $backgroundColor3: #334155; // slate-700
$accentColor: #475569; // slate-600 $accentColor: #475569; // slate-600
$infoColor: #1ea97c; $infoColor: #1ea97c;
$warningColor: #ffc107; $warningColor: #ffc107;
$errorColor: #ff5252; $errorColor: #ff5252;
body {
background-color: $backgroundColor2; background-color: $backgroundColor2;
}
@layer utilities {
.highlight {
color: $textColorHighlight;
}
.highlight2 { @layer utilities {
color: $textColorHighlight2 !important; .highlight {
}
.bg {
background-color: $backgroundColor;
}
.bg2 {
background-color: $backgroundColor2;
}
.bg3 {
background-color: $backgroundColor3;
}
.accent {
color: $accentColor;
}
.info {
color: $infoColor;
}
.warning {
color: $warningColor;
}
.error {
color: $errorColor;
}
.deleted {
color: $accentColor !important;
}
}
h1,
h2,
h3 {
color: $headerColor;
}
.app {
.component {
background-color: $backgroundColor;
}
}
.btn-base {
color: $textColor;
background: $textColorHighlight !important;
border: 1px solid $textColorHighlight;
&:focus {
box-shadow: none !important;
}
&:hover {
background: transparent !important;
}
}
.btn {
.p-button {
@extend .btn-base;
}
}
.icon-btn {
background-color: transparent !important;
border: none;
.p-button {
color: $textColor;
background: transparent !important;
padding: 0;
&:hover {
color: $textColorHighlight; color: $textColorHighlight;
} }
}
}
.text-btn { .highlight2 {
background-color: transparent !important; color: $textColorHighlight2 !important;
.p-button {
color: $textColor;
background: transparent !important;
border: none !important;
&:hover {
color: $textColorHighlight;
background-color: transparent !important;
} }
}
}
.icon-btn-without-hover { .bg {
&:hover {
background-color: transparent !important;
}
}
.icon-btn {
&:hover {
background-color: transparent !important;
}
}
.danger-btn,
.danger-icon-btn {
background-color: transparent !important;
.p-button {
color: $textColor;
background: transparent !important;
&:hover {
color: $errorColor;
}
}
}
.hidden-columns-select {
.active-while-panel-open {
.p-button {
color: $textColorHighlight;
}
}
}
.custom-spinner {
.p-progress-spinner-circle {
stroke: $textColorHighlight !important;
}
}
p-paginator {
.p-paginator-element {
&:hover {
color: $textColorHighlight;
}
}
}
.p-highlight {
color: $textColorHighlight2;
box-shadow: none !important;
&:hover {
color: $textColorHighlight2 !important;
}
}
.p-multiselect,
.p-paginator,
.p-dropdown,
input {
background-color: $backgroundColor;
}
.p-inputtext:enabled:focus,
.p-inputtext:enabled:hover,
.p-multiselect:not(.p-disabled):hover,
.p-multiselect:not(.p-disabled).p-focus,
.p-dropdown:not(.p-disabled):hover,
.p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box:hover,
.p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box.p-focus {
border-color: $textColorHighlight;
box-shadow: none !important;
}
.p-checkbox .p-checkbox-box.p-highlight {
border-color: $textColorHighlight;
background: $textColorHighlight;
box-shadow: none !important;
}
p-checkbox {
.p-checkbox {
.p-checkbox-box {
background-color: $backgroundColor; background-color: $backgroundColor;
} }
.p-checkbox-box.p-highlight { .bg2 {
border-color: $textColorHighlight; background-color: $backgroundColor2;
background-color: $textColorHighlight; }
.bg3 {
background-color: $backgroundColor3;
}
.accent {
color: $accentColor;
}
.info {
color: $infoColor;
}
.warning {
color: $warningColor;
}
.error {
color: $errorColor;
}
.deleted {
color: $accentColor !important;
} }
} }
}
p-inputSwitch { h1,
.p-inputswitch { h2,
&.p-focus .p-inputswitch-slider { h3 {
color: $headerColor;
}
.app {
.component {
background-color: $backgroundColor;
}
}
.btn-base {
color: $textColor;
background: $textColorHighlight !important;
border: 1px solid $textColorHighlight;
&:focus {
box-shadow: none !important; box-shadow: none !important;
} }
.p-inputswitch-slider { &:hover {
background-color: $headerColor; background: transparent !important;
}
}
&.p-highlight { .btn {
border-color: $textColorHighlight; .p-button {
background: $textColorHighlight; @extend .btn-base;
box-shadow: none !important; }
}
.icon-btn {
background-color: transparent !important;
border: none;
.p-button {
color: $textColor;
background: transparent !important;
padding: 0;
&:hover {
color: $textColorHighlight;
} }
} }
}
.text-btn {
background-color: transparent !important;
.p-button {
color: $textColor;
background: transparent !important;
border: none !important;
&:hover {
color: $textColorHighlight;
background-color: transparent !important;
}
}
}
.icon-btn-without-hover {
&:hover {
background-color: transparent !important;
}
}
.icon-btn {
&:hover {
background-color: transparent !important;
}
}
.danger-btn,
.danger-icon-btn {
background-color: transparent !important;
.p-button {
color: $textColor;
background: transparent !important;
&:hover {
color: $errorColor;
}
}
}
.hidden-columns-select {
.active-while-panel-open {
.p-button {
color: $textColorHighlight;
}
}
}
.custom-spinner {
.p-progress-spinner-circle {
stroke: $textColorHighlight !important;
}
}
p-paginator {
.p-paginator-element {
&:hover {
color: $textColorHighlight;
}
}
}
.p-highlight {
color: $textColorHighlight2;
box-shadow: none !important;
&:hover {
color: $textColorHighlight2 !important;
}
}
.p-multiselect,
.p-paginator,
.p-dropdown,
input {
background-color: $backgroundColor;
}
.p-inputtext:enabled:focus,
.p-inputtext:enabled:hover,
.p-multiselect:not(.p-disabled):hover,
.p-multiselect:not(.p-disabled).p-focus,
.p-dropdown:not(.p-disabled):hover,
.p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box:hover,
.p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box.p-focus {
border-color: $textColorHighlight;
box-shadow: none !important;
}
.p-checkbox .p-checkbox-box.p-highlight {
border-color: $textColorHighlight;
background: $textColorHighlight;
box-shadow: none !important;
}
p-checkbox {
.p-checkbox {
.p-checkbox-box {
background-color: $backgroundColor;
}
.p-checkbox-box.p-highlight {
border-color: $textColorHighlight;
background-color: $textColorHighlight;
}
}
}
p-inputSwitch {
.p-inputswitch {
&.p-focus .p-inputswitch-slider {
box-shadow: none !important;
}
&.p-inputswitch-checked {
.p-inputswitch-slider { .p-inputswitch-slider {
background-color: $headerColor; background-color: $headerColor;
&:before { &.p-highlight {
background-color: $textColor; border-color: $textColorHighlight;
background: $textColorHighlight;
box-shadow: none !important;
}
}
&.p-inputswitch-checked {
.p-inputswitch-slider {
background-color: $headerColor;
&:before {
background-color: $textColor;
}
} }
} }
} }
} }
}
p-panel-menu { p-panel-menu {
.p-panelmenu { .p-panelmenu {
.p-panelmenu-content .p-panelmenu-content
.p-menuitem:not(.p-highlight):not(.p-disabled) .p-menuitem:not(.p-highlight):not(.p-disabled)
> .p-menuitem-content:hover > .p-menuitem-content:hover
.p-menuitem-link .p-menuitem-link
.p-menuitem-text, .p-menuitem-text,
.p-panelmenu-content .p-panelmenu-content
.p-menuitem:not(.p-highlight):not(.p-disabled) .p-menuitem:not(.p-highlight):not(.p-disabled)
> .p-menuitem-content:hover > .p-menuitem-content:hover
.p-menuitem-link .p-menuitem-link
.p-menuitem-icon, .p-menuitem-icon,
.p-panelmenu .p-panelmenu
.p-panelmenu-content .p-panelmenu-content
.p-menuitem:not(.p-highlight):not(.p-disabled) .p-menuitem:not(.p-highlight):not(.p-disabled)
> .p-menuitem-content:hover > .p-menuitem-content:hover
.p-menuitem-link .p-menuitem-link
.p-submenu-icon { .p-submenu-icon {
color: $textColorHighlight; color: $textColorHighlight;
} }
.p-panelmenu-header-content { .p-panelmenu-header-content {
&:hover { &:hover {
.p-panelmenu-header-action { .p-panelmenu-header-action {
color: $textColorHighlight; color: $textColorHighlight;
}
} }
} }
} }
} }
}
p-menubar { p-menubar {
.p-menubar { .p-menubar {
background-color: $backgroundColor2; background-color: $backgroundColor2;
} }
.p-menubar-root-list { .p-menubar-root-list {
display: flex; display: flex;
gap: 10px; gap: 10px;
} }
.p-menuitem { .p-menuitem {
border-radius: 0.5rem; border-radius: 0.5rem;
&:hover { &:hover {
.p-menuitem-content .p-menuitem-link .p-menuitem-text { .p-menuitem-content .p-menuitem-link .p-menuitem-text {
color: $textColorHighlight2; color: $textColorHighlight2;
}
}
}
.p-focus {
background-color: $backgroundColor2;
.p-menuitem-content {
background-color: $backgroundColor2;
} }
} }
} }
.p-focus { p-dropdown {
background-color: $backgroundColor2; .p-dropdown:not(.p-disabled).p-focus {
box-shadow: none !important;
border-color: $headerColor !important;
}
.p-menuitem-content { .p-dropdown-panel {
background-color: $backgroundColor2; background-color: $backgroundColor2;
} }
} }
}
p-dropdown { p-multiselect {
.p-dropdown:not(.p-disabled).p-focus { .p-multiselect-panel,
box-shadow: none !important; .p-multiselect-panel .p-multiselect-header {
border-color: $headerColor !important; background-color: $backgroundColor2;
}
} }
.p-dropdown-panel { p-table {
background-color: $backgroundColor2; .p-datatable {
} .p-datatable-header,
} .p-datatable-footer,
.p-datatable-thead > tr > th,
.p-datatable-tbody > tr {
background-color: $backgroundColor;
border-bottom: 1px solid $accentColor;
}
p-multiselect { .p-sortable-column.p-highlight,
.p-multiselect-panel, .p-sortable-column:not(.p-highlight):hover {
.p-multiselect-panel .p-multiselect-header { background-color: transparent !important;
background-color: $backgroundColor2; }
}
}
p-table { .p-sortable-column:not(.p-highlight):hover,
.p-datatable { .p-sortable-column:not(.p-highlight):hover .p-sortable-column-icon {
.p-datatable-header, color: $textColorHighlight;
.p-datatable-footer, }
.p-datatable-thead > tr > th, }
.p-datatable-tbody > tr { }
p-sidebar {
.p-sidebar {
background-color: $backgroundColor; background-color: $backgroundColor;
border-bottom: 1px solid $accentColor;
}
.p-sortable-column.p-highlight,
.p-sortable-column:not(.p-highlight):hover {
background-color: transparent !important;
}
.p-sortable-column:not(.p-highlight):hover,
.p-sortable-column:not(.p-highlight):hover .p-sortable-column-icon {
color: $textColorHighlight;
} }
} }
}
p-sidebar { .p-steps .p-steps-item.p-highlight .p-steps-number {
.p-sidebar { background-color: $headerColor;
background-color: $backgroundColor; color: $textColor;
}
}
.p-steps .p-steps-item.p-highlight .p-steps-number {
background-color: $headerColor;
color: $textColor;
}
.p-dialog {
.p-dialog-header {
background-color: $backgroundColor;
} }
.p-dialog-content { .p-dialog {
background-color: $backgroundColor; .p-dialog-header {
padding-top: 1rem; background-color: $backgroundColor;
}
.p-dialog-content {
background-color: $backgroundColor;
padding-top: 1rem;
}
.p-dialog-footer {
background-color: $backgroundColor;
}
} }
.p-dialog-footer { .p-badge {
background-color: $backgroundColor; background: $headerColor;
color: $textColor;
} }
}
.p-badge { p-password {
background: $headerColor;
color: $textColor;
}
p-password {
background-color: transparent;
border: none;
.p-password-panel {
background-color: transparent; background-color: transparent;
} border: none;
}
p-slider { .p-password-panel {
.p-slider { background-color: transparent;
.p-slider-range {
background: $headerColor;
} }
}
.p-slider-handle { p-slider {
border-color: $headerColor; .p-slider {
.p-slider-range {
&:hover {
background: $headerColor; background: $headerColor;
} }
&:focus { .p-slider-handle {
box-shadow: none !important; border-color: $headerColor;
&:hover {
background: $headerColor;
}
&:focus {
box-shadow: none !important;
}
} }
} }
} }
} }

View File

@ -0,0 +1,407 @@
.maxlan {
$headerColor: #a2271f;
// generated with https://colorffy.com/dark-theme-generator?colors=314390-121212
$textColor: #fff;
$textColorHighlight: #314390;
$textColorHighlight2: #a2271f;
// https://tailwindcss.com/docs/customizing-colors
$backgroundColor: #1e293b; // slate-800
$backgroundColor2: #0f172a; // slate-900
$backgroundColor3: #334155; // slate-700
$accentColor: #475569; // slate-600
$infoColor: #1ea97c;
$warningColor: #ffc107;
$errorColor: #ff5252;
background-color: $backgroundColor2;
@layer utilities {
.highlight {
color: $textColorHighlight;
}
.highlight2 {
color: $textColorHighlight2 !important;
}
.bg {
background-color: $backgroundColor;
}
.bg2 {
background-color: $backgroundColor2;
}
.bg3 {
background-color: $backgroundColor3;
}
.accent {
color: $accentColor;
}
.info {
color: $infoColor;
}
.warning {
color: $warningColor;
}
.error {
color: $errorColor;
}
.deleted {
color: $accentColor !important;
}
}
h1,
h2,
h3 {
color: $headerColor;
}
.app {
.component {
background-color: $backgroundColor;
}
}
.btn-base {
color: $textColor;
background: $textColorHighlight !important;
border: 1px solid $textColorHighlight;
&:focus {
box-shadow: none !important;
}
&:hover {
background: transparent !important;
}
}
.btn {
.p-button {
@extend .btn-base;
}
}
.icon-btn {
background-color: transparent !important;
border: none;
.p-button {
color: $textColor;
background: transparent !important;
padding: 0;
&:hover {
color: $textColorHighlight;
}
}
}
.text-btn {
background-color: transparent !important;
.p-button {
color: $textColor;
background: transparent !important;
border: none !important;
&:hover {
color: $textColorHighlight;
background-color: transparent !important;
}
}
}
.icon-btn-without-hover {
&:hover {
background-color: transparent !important;
}
}
.icon-btn {
&:hover {
background-color: transparent !important;
}
}
.danger-btn,
.danger-icon-btn {
background-color: transparent !important;
.p-button {
color: $textColor;
background: transparent !important;
&:hover {
color: $errorColor;
}
}
}
.hidden-columns-select {
.active-while-panel-open {
.p-button {
color: $textColorHighlight;
}
}
}
.custom-spinner {
.p-progress-spinner-circle {
stroke: $textColorHighlight !important;
}
}
p-paginator {
.p-paginator-element {
&:hover {
color: $textColorHighlight;
}
}
}
.p-highlight {
color: $textColorHighlight2;
box-shadow: none !important;
&:hover {
color: $textColorHighlight2 !important;
}
}
.p-multiselect,
.p-paginator,
.p-dropdown,
input {
background-color: $backgroundColor;
}
.p-inputtext:enabled:focus,
.p-inputtext:enabled:hover,
.p-multiselect:not(.p-disabled):hover,
.p-multiselect:not(.p-disabled).p-focus,
.p-dropdown:not(.p-disabled):hover,
.p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box:hover,
.p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box.p-focus {
border-color: $textColorHighlight;
box-shadow: none !important;
}
.p-checkbox .p-checkbox-box.p-highlight {
border-color: $textColorHighlight;
background: $textColorHighlight;
box-shadow: none !important;
}
p-checkbox {
.p-checkbox {
.p-checkbox-box {
background-color: $backgroundColor;
}
.p-checkbox-box.p-highlight {
border-color: $textColorHighlight;
background-color: $textColorHighlight;
}
}
}
p-inputSwitch {
.p-inputswitch {
&.p-focus .p-inputswitch-slider {
box-shadow: none !important;
}
.p-inputswitch-slider {
background-color: $headerColor;
&.p-highlight {
border-color: $textColorHighlight;
background: $textColorHighlight;
box-shadow: none !important;
}
}
&.p-inputswitch-checked {
.p-inputswitch-slider {
background-color: $headerColor;
&:before {
background-color: $textColor;
}
}
}
}
}
p-panel-menu {
.p-panelmenu {
.p-panelmenu-content
.p-menuitem:not(.p-highlight):not(.p-disabled)
> .p-menuitem-content:hover
.p-menuitem-link
.p-menuitem-text,
.p-panelmenu-content
.p-menuitem:not(.p-highlight):not(.p-disabled)
> .p-menuitem-content:hover
.p-menuitem-link
.p-menuitem-icon,
.p-panelmenu
.p-panelmenu-content
.p-menuitem:not(.p-highlight):not(.p-disabled)
> .p-menuitem-content:hover
.p-menuitem-link
.p-submenu-icon {
color: $textColorHighlight;
}
.p-panelmenu-header-content {
&:hover {
.p-panelmenu-header-action {
color: $textColorHighlight;
}
}
}
}
}
p-menubar {
.p-menubar {
background-color: $backgroundColor2;
}
.p-menubar-root-list {
display: flex;
gap: 10px;
}
.p-menuitem {
border-radius: 0.5rem;
&:hover {
.p-menuitem-content .p-menuitem-link .p-menuitem-text {
color: $textColorHighlight2;
}
}
}
.p-focus {
background-color: $backgroundColor2;
.p-menuitem-content {
background-color: $backgroundColor2;
}
}
}
p-dropdown {
.p-dropdown:not(.p-disabled).p-focus {
box-shadow: none !important;
border-color: $headerColor !important;
}
.p-dropdown-panel {
background-color: $backgroundColor2;
}
}
p-multiselect {
.p-multiselect-panel,
.p-multiselect-panel .p-multiselect-header {
background-color: $backgroundColor2;
}
}
p-table {
.p-datatable {
.p-datatable-header,
.p-datatable-footer,
.p-datatable-thead > tr > th,
.p-datatable-tbody > tr {
background-color: $backgroundColor;
border-bottom: 1px solid $accentColor;
}
.p-sortable-column.p-highlight,
.p-sortable-column:not(.p-highlight):hover {
background-color: transparent !important;
}
.p-sortable-column:not(.p-highlight):hover,
.p-sortable-column:not(.p-highlight):hover .p-sortable-column-icon {
color: $textColorHighlight;
}
}
}
p-sidebar {
.p-sidebar {
background-color: $backgroundColor;
}
}
.p-steps .p-steps-item.p-highlight .p-steps-number {
background-color: $headerColor;
color: $textColor;
}
.p-dialog {
.p-dialog-header {
background-color: $backgroundColor;
}
.p-dialog-content {
background-color: $backgroundColor;
padding-top: 1rem;
}
.p-dialog-footer {
background-color: $backgroundColor;
}
}
.p-badge {
background: $headerColor;
color: $textColor;
}
p-password {
background-color: transparent;
border: none;
.p-password-panel {
background-color: transparent;
}
}
p-slider {
.p-slider {
.p-slider-range {
background: $headerColor;
}
.p-slider-handle {
border-color: $headerColor;
&:hover {
background: $headerColor;
}
&:focus {
box-shadow: none !important;
}
}
}
}
}