mini-profile, dark/light themes, fixes

This commit is contained in:
svensken 2022-11-04 03:45:08 +03:00
parent c068b91a73
commit 55fa46b4d4
51 changed files with 710 additions and 230 deletions

View File

@ -29,7 +29,10 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles.scss",
"src/_themes.scss",
"src/_light.scss",
"src/_dark.scss"
], ],
"scripts": [] "scripts": []
}, },
@ -97,7 +100,10 @@
"src/assets" "src/assets"
], ],
"styles": [ "styles": [
"src/styles.scss" "src/styles.scss",
"src/_themes.scss",
"src/_light.scss",
"src/_dark.scss"
], ],
"scripts": [] "scripts": []
} }

51
package-lock.json generated
View File

@ -19,8 +19,8 @@
"@angular/router": "^14.1.0", "@angular/router": "^14.1.0",
"@ng-icons/core": "^22.4.0", "@ng-icons/core": "^22.4.0",
"@ng-icons/tabler-icons": "^22.4.0", "@ng-icons/tabler-icons": "^22.4.0",
"fast-average-color": "^9.1.1",
"moment": "^2.29.4", "moment": "^2.29.4",
"ngx-webstorage": "^10.0.1",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"
@ -3103,11 +3103,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz",
"integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==" "integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w=="
}, },
"node_modules/@types/offscreencanvas": {
"version": "2019.7.0",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz",
"integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg=="
},
"node_modules/@types/parse-json": { "node_modules/@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
@ -5664,17 +5659,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/fast-average-color": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/fast-average-color/-/fast-average-color-9.1.1.tgz",
"integrity": "sha512-PJizLBcGb/jqUzrH66385te4+GcOK7wcUiCDvBUszdpzc/pvV1kwifvvsFygV3mS+7qwnWmK9/BrZniaOOC9ag==",
"dependencies": {
"@types/offscreencanvas": "^2019.7.0"
},
"engines": {
"node": ">= 12"
}
},
"node_modules/fast-deep-equal": { "node_modules/fast-deep-equal": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -7943,6 +7927,18 @@
"node": "^12.20.0 || >=14" "node": "^12.20.0 || >=14"
} }
}, },
"node_modules/ngx-webstorage": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/ngx-webstorage/-/ngx-webstorage-10.0.1.tgz",
"integrity": "sha512-OWmzAzby+/UrbRY/5d229Y4NzFn1a/u2WSEeZqzY5lwB/3d8ODZ6mlW/BZGIuuZ48Hp8tXMM3pFCz9+pEyzvDA==",
"dependencies": {
"tslib": "^2.0.0"
},
"peerDependencies": {
"@angular/common": "^14.0.0",
"@angular/core": "^14.0.0"
}
},
"node_modules/nice-napi": { "node_modules/nice-napi": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",
@ -13868,11 +13864,6 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz",
"integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==" "integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w=="
}, },
"@types/offscreencanvas": {
"version": "2019.7.0",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz",
"integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg=="
},
"@types/parse-json": { "@types/parse-json": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
@ -15710,14 +15701,6 @@
"tmp": "^0.0.33" "tmp": "^0.0.33"
} }
}, },
"fast-average-color": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/fast-average-color/-/fast-average-color-9.1.1.tgz",
"integrity": "sha512-PJizLBcGb/jqUzrH66385te4+GcOK7wcUiCDvBUszdpzc/pvV1kwifvvsFygV3mS+7qwnWmK9/BrZniaOOC9ag==",
"requires": {
"@types/offscreencanvas": "^2019.7.0"
}
},
"fast-deep-equal": { "fast-deep-equal": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -17383,6 +17366,14 @@
} }
} }
}, },
"ngx-webstorage": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/ngx-webstorage/-/ngx-webstorage-10.0.1.tgz",
"integrity": "sha512-OWmzAzby+/UrbRY/5d229Y4NzFn1a/u2WSEeZqzY5lwB/3d8ODZ6mlW/BZGIuuZ48Hp8tXMM3pFCz9+pEyzvDA==",
"requires": {
"tslib": "^2.0.0"
}
},
"nice-napi": { "nice-napi": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",

View File

@ -21,8 +21,8 @@
"@angular/router": "^14.1.0", "@angular/router": "^14.1.0",
"@ng-icons/core": "^22.4.0", "@ng-icons/core": "^22.4.0",
"@ng-icons/tabler-icons": "^22.4.0", "@ng-icons/tabler-icons": "^22.4.0",
"fast-average-color": "^9.1.1",
"moment": "^2.29.4", "moment": "^2.29.4",
"ngx-webstorage": "^10.0.1",
"rxjs": "~7.5.0", "rxjs": "~7.5.0",
"tslib": "^2.3.0", "tslib": "^2.3.0",
"zone.js": "~0.11.4" "zone.js": "~0.11.4"

View File

@ -19,19 +19,19 @@
} }
&[data-appearance="default"], &[data-appearance="primary"] { &[data-appearance="default"], &[data-appearance="primary"] {
background-color: var(--sk-primary); background-color: var(--sk-primary-accent);
color: #fff; color: #fff;
} }
&[data-appearance="secondary"] { &[data-appearance="secondary"] {
background-color: var(--sk-secondary); background-color: var(--sk-secondary-accent);
color: #fff; color: #fff;
} }
&[data-appearance="outline"] { &[data-appearance="outline"] {
color: #fff; color: #fff;
background-color: transparent; background-color: transparent;
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.1); box-shadow: 0px 0px 0px 1px var(--sk-border);
} }
&[data-appearance="flat"] { &[data-appearance="flat"] {
@ -40,3 +40,15 @@
} }
} }
} }
:host::ng-deep {
button {
&[data-appearance="default"], &[data-appearance="primary"] {
skirda-icon ng-icon {
color: #fff!important;
}
}
}
}

View File

@ -1,18 +1,21 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { KeyboardDirective } from './keyboard.directive'; import { KeyboardDirective } from './keyboard/keyboard.directive';
import { IsScrollingDirective } from './is-scrolling/is-scrolling.directive';
@NgModule({ @NgModule({
declarations: [ declarations: [
KeyboardDirective KeyboardDirective,
IsScrollingDirective
], ],
imports: [ imports: [
CommonModule CommonModule
], ],
exports: [ exports: [
KeyboardDirective KeyboardDirective,
IsScrollingDirective
] ]
}) })
export class DirectivesModule { } export class DirectivesModule { }

View File

@ -0,0 +1,8 @@
import { IsScrollingDirective } from './is-scrolling.directive';
describe('IsScrollingDirective', () => {
it('should create an instance', () => {
const directive = new IsScrollingDirective();
expect(directive).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Directive, ElementRef, HostBinding } from '@angular/core';
@Directive({
selector: '[skirdaIsScrolling]'
})
export class IsScrollingDirective {
constructor(
private element: ElementRef<HTMLElement>
) { }
@HostBinding('attr.data-scroll-y') get isScrollableY () {
return this.element.nativeElement.clientHeight < this.element.nativeElement.scrollHeight
}
}

View File

@ -1,10 +1,12 @@
<div class="sk-game"> <a [routerLink]="['/game/' + game.gameId]" routerLinkActive="active">
<skirda-image-icon [src]="game.image"></skirda-image-icon> <div class="sk-game">
<div class="sk-game-info"> <skirda-image-icon [src]="game.image"></skirda-image-icon>
<div class="info-game-line"> <div class="sk-game-info">
<skirda-heading size="6">{{game.title}}</skirda-heading> <div class="info-game-line">
<skirda-heading size="6">{{game.title}}</skirda-heading>
</div>
<skirda-text>description</skirda-text>
</div> </div>
<skirda-text>description</skirda-text> <skirda-icon name="play" size="24" (click)="run(game)" color="var(--sk-primary-accent)"></skirda-icon>
</div> </div>
<skirda-icon name="play" size="24" (click)="run(game)" color="var(--sk-primary)"></skirda-icon> </a>
</div>

View File

@ -1,31 +1,43 @@
:host { :host {
display: block; display: block;
.sk-game { a {
display: flex; display: block;
align-items: center; color: inherit;
gap: var(--sk-gap-l); text-decoration: none;
padding: var(--sk-gap-l);
border-radius: var(--sk-br-m);
transition: 0.1s ease;
opacity: 0.5;
cursor: pointer;
&:hover { &:hover {
opacity: 1;
background-color: rgba(255, 255, 255, 0.05); .sk-game {
opacity: 0.5;
background-color: var(--sk-item-active);
}
} }
.sk-game-info { &.active {
flex: 1;
}
}
&.active { .sk-game {
opacity: 1;
background-color: var(--sk-item-active);
}
}
.sk-game { .sk-game {
opacity: 1; display: flex;
background-color: rgba(255, 255, 255, 0.1); align-items: center;
gap: var(--sk-gap-l);
padding: var(--sk-gap-l);
border-radius: var(--sk-br-m);
transition: 0.1s ease;
opacity: 0.5;
cursor: pointer;
.sk-game-info {
flex: 1;
display: flex;
flex-direction: column;
gap: var(--sk-gap-m);
}
} }
} }
} }

View File

@ -5,6 +5,7 @@ import { ImageIconModule } from '../image-icon/image-icon.module'
import { TypographyModule } from '../typography/typography.module' import { TypographyModule } from '../typography/typography.module'
import { TagModule } from '../tag/tag.module' import { TagModule } from '../tag/tag.module'
import { IconModule } from '../icon/icon.module' import { IconModule } from '../icon/icon.module'
import { RouterModule } from '@angular/router'
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -15,7 +16,8 @@ import { IconModule } from '../icon/icon.module'
ImageIconModule, ImageIconModule,
TypographyModule, TypographyModule,
TagModule, TagModule,
IconModule IconModule,
RouterModule
], ],
exports: [ exports: [
GameComponent GameComponent

View File

@ -14,7 +14,7 @@ export class IconComponent {
@Input() name!: string; @Input() name!: string;
@Input() size: number | string = 24; @Input() size: number | string = 24;
@Input() sizeUnit: string = 'px'; @Input() sizeUnit: string = 'px';
@Input() color: string = '#fff'; @Input() color: string = 'var(--sk-text)';
get sizeWithUnit() { get sizeWithUnit() {
return this.size + this.sizeUnit; return this.size + this.sizeUnit;

View File

@ -12,6 +12,8 @@ import {
tablerDownload, tablerDownload,
tablerPlayerPlay, tablerPlayerPlay,
tablerX, tablerX,
tablerSettings,
tablerSun
} from '@ng-icons/tabler-icons'; } from '@ng-icons/tabler-icons';
const icons = { const icons = {
@ -24,6 +26,8 @@ const icons = {
tablerDownload, tablerDownload,
tablerPlayerPlay, tablerPlayerPlay,
tablerX, tablerX,
tablerSettings,
tablerSun
}; };
@NgModule({ @NgModule({

View File

@ -8,5 +8,7 @@ icons.set('friends', 'tablerUsers');
icons.set('download', 'tablerDownload'); icons.set('download', 'tablerDownload');
icons.set('play', 'tablerPlayerPlay'); icons.set('play', 'tablerPlayerPlay');
icons.set('close', 'tablerX'); icons.set('close', 'tablerX');
icons.set('settings', 'tablerSettings');
icons.set('sun', 'tablerSun');
export { icons }; export { icons };

View File

@ -7,12 +7,14 @@
gap: 0.5rem; gap: 0.5rem;
padding: var(--local-gap); padding: var(--local-gap);
cursor: text; cursor: text;
background-color: var(--sk-input); background-color: transparent;
border: 1px solid var(--sk-border);
box-sizing: border-box;
color: #fff; color: #fff;
border-radius: 8px; border-radius: 8px;
&:focus-within { &:focus-within {
background-color: var(--sk-input-focus); border: 1px solid var(--sk-border-hovered);
} }
input { input {
@ -21,11 +23,13 @@
outline: none; outline: none;
appearance: none; appearance: none;
background: transparent; background: transparent;
font-size: 0.875rem; font-size: 1rem;
color: #fff; color: var(--sk-text);
font-family: var(--font);
&::placeholder { &::placeholder {
color: rgba(255, 255, 255, 0.5); color: var(--sk-text);
opacity: 0.5;
} }
} }
} }

View File

@ -18,8 +18,12 @@ export class CountdownPipe implements PipeTransform {
let days = duration.days(), hours = duration.hours(), minutes = duration.minutes(), seconds = duration.seconds() let days = duration.days(), hours = duration.hours(), minutes = duration.minutes(), seconds = duration.seconds()
if (days > 0) if (days > 0)
return `${days} ${days == 1 ? 'day' : 'days'}` return `${days} ${days == 1 ? 'day' : 'days'}`
else else {
return `${this.pad(hours)}:${this.pad(minutes)}:${this.pad(seconds)}` if (seconds < 0)
return 'expired'
else
return `${this.pad(hours)}:${this.pad(minutes)}:${this.pad(seconds)}`
}
} }
private pad (value: number) { private pad (value: number) {

View File

@ -88,15 +88,15 @@
} }
&[data-theme="dark"] { &[data-theme="dark"] {
--local-background: #222; --local-background: var(--sk-background);
--local-color: #fff; --local-color: var(--sk-text);
--local-border: rgba(255, 255, 255, 0.125); --local-border: var(--sk-border);
background: linear-gradient(45deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.25)); background: linear-gradient(45deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.25));
} }
&[data-theme="light"] { &[data-theme="light"] {
--local-background: #fff; --local-background: var(--sk-background);
--local-color: #111; --local-color: var(--sk-text);
--local-border: rgba(0, 0, 0, 0.125); --local-border: var(--sk-border);
background: linear-gradient(45deg, rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.25)); background: linear-gradient(45deg, rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.25));
} }

View File

@ -14,8 +14,8 @@
border-radius: var(--sk-br-m); border-radius: var(--sk-br-m);
&:hover { &:hover {
opacity: 1; opacity: 0.5;
background-color: rgba(255, 255, 255, 0.05); background-color: var(--sk-item-active);
} }
} }
@ -23,7 +23,7 @@
.sk-section { .sk-section {
opacity: 1; opacity: 1;
background-color: rgba(255, 255, 255, 0.1); background-color: var(--sk-item-active);
} }
} }
} }

View File

@ -1,13 +1,15 @@
<div class="sk-session"> <a [routerLink]="['/session/' + session.gameId]" routerLinkActive="active" [title]="session.status ?? 'No status'">
<skirda-image-icon [src]="session.icon"></skirda-image-icon> <div class="sk-session">
<div class="sk-session-info"> <skirda-image-icon [src]="session.icon"></skirda-image-icon>
<div class="info-heading-line"> <div class="sk-session-info">
<skirda-heading size="6">{{session.title}}</skirda-heading> <div class="info-heading-line">
<skirda-tag>{{session.expires | countdown | async}}</skirda-tag> <skirda-heading size="6">{{session.title}}</skirda-heading>
</div> </div>
<div class="info-line"> <div class="info-line">
<skirda-tag class="filled">{{session.version}}</skirda-tag> <skirda-tag class="filled" *ngIf="session.version">{{session.version}}</skirda-tag>
<skirda-text *ngIf="session.status">{{session.status}}</skirda-text> <skirda-tag>{{session.expires | countdown | async}}</skirda-tag>
</div>
</div> </div>
<skirda-icon name="play" size="24" (click)="run(session)" color="var(--sk-primary-accent)"></skirda-icon>
</div> </div>
</div> </a>

View File

@ -1,55 +1,65 @@
:host { :host {
display: block; display: block;
.sk-session { a {
display: flex; display: block;
align-items: center; color: inherit;
gap: var(--sk-gap-l); text-decoration: none;
padding: var(--sk-gap-l);
border-radius: var(--sk-br-m);
transition: 0.1s ease;
opacity: 0.5;
cursor: pointer;
&:hover { &:hover {
opacity: 1;
background-color: rgba(255, 255, 255, 0.05); .sk-session {
opacity: 0.5;
background-color: var(--sk-item-active);
}
} }
.sk-session-info { &.active {
flex: 1;
display: flex;
flex-direction: column;
gap: var(--sk-gap-s);
.info-heading-line { .sk-session {
display: flex; opacity: 1;
justify-content: space-between; background-color: var(--sk-item-active);
align-items: baseline;
} }
.info-line { }
display: flex;
align-items: baseline;
gap: var(--sk-gap-m);
max-width: 248px;
skirda-text { .sk-session {
flex: 1; display: flex;
white-space: nowrap; align-items: center;
text-overflow: ellipsis; gap: var(--sk-gap-l);
overflow: hidden; padding: var(--sk-gap-l);
display: block; border-radius: var(--sk-br-m);
transition: 0.1s ease;
opacity: 0.5;
cursor: pointer;
.sk-session-info {
flex: 1;
display: flex;
flex-direction: column;
gap: var(--sk-gap-m);
.info-heading-line {
display: flex;
align-items: baseline;
gap: var(--sk-gap-m);
}
.info-line {
display: flex;
align-items: baseline;
gap: var(--sk-gap-m);
max-width: 234px;
skirda-text {
flex: 1;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: block;
}
} }
} }
} }
} }
&.active {
.sk-session {
opacity: 1;
background-color: rgba(255, 255, 255, 0.1);
}
}
} }

View File

@ -1,5 +1,7 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { Game } from 'src/app/interfaces/game.interface'
import { Session } from 'src/app/interfaces/session.interface'; import { Session } from 'src/app/interfaces/session.interface';
import { LauncherService } from 'src/app/services/launcher.service'
@Component({ @Component({
selector: 'skirda-session[session]', selector: 'skirda-session[session]',
@ -9,7 +11,15 @@ import { Session } from 'src/app/interfaces/session.interface';
export class SessionComponent implements OnInit { export class SessionComponent implements OnInit {
@Input() session!: Session; @Input() session!: Session;
constructor() {} constructor(
private launcher: LauncherService
) {}
ngOnInit(): void {} ngOnInit(): void {}
run(session: Session) {
// TODO: run session
//console.log('Game to run ' + game.title)
// this.launcher.RunGame(game)
}
} }

View File

@ -5,10 +5,12 @@ import { ImageIconModule } from '../image-icon/image-icon.module';
import { TypographyModule } from '../typography/typography.module'; import { TypographyModule } from '../typography/typography.module';
import { TagModule } from '../tag/tag.module' import { TagModule } from '../tag/tag.module'
import { PipesModule } from '../pipes/pipes.module' import { PipesModule } from '../pipes/pipes.module'
import { RouterModule } from '@angular/router'
import { IconModule } from '../icon/icon.module'
@NgModule({ @NgModule({
declarations: [SessionComponent], declarations: [SessionComponent],
imports: [CommonModule, ImageIconModule, TypographyModule, TagModule, PipesModule], imports: [CommonModule, ImageIconModule, TypographyModule, TagModule, PipesModule, RouterModule, IconModule],
exports: [SessionComponent], exports: [SessionComponent],
}) })
export class SessionModule {} export class SessionModule {}

View File

@ -1,13 +1,14 @@
:host { :host {
&.filled .sk-tag { &.filled .sk-tag {
background-color: var(--sk-primary); background-color: var(--sk-primary-accent);
color: #fff;
} }
.sk-tag { .sk-tag {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
padding: 1px var(--sk-gap-m); padding: 2px var(--sk-gap-m);
border-radius: var(--sk-br-s); border-radius: var(--sk-br-s);
background-color: rgba(255, 255, 255, 0.05); background-color: rgba(255, 255, 255, 0.05);
} }

View File

@ -4,22 +4,22 @@
font-weight: 600; font-weight: 600;
&[data-size="1"] { &[data-size="1"] {
font-size: 32px; font-size: var(--sk-typo-h1);
} }
&[data-size="2"] { &[data-size="2"] {
font-size: 28px; font-size: var(--sk-typo-h2);
} }
&[data-size="3"] { &[data-size="3"] {
font-size: 24px; font-size: var(--sk-typo-h3);
} }
&[data-size="4"] { &[data-size="4"] {
font-size: 22px; font-size: var(--sk-typo-h4);
} }
&[data-size="5"] { &[data-size="5"] {
font-size: 18px; font-size: var(--sk-typo-h5);
} }
&[data-size="6"] { &[data-size="6"] {
font-size: 15px; font-size: var(--sk-typo-h6);
} }
} }
} }

View File

@ -1,4 +1,4 @@
:host { :host {
display: inline; display: inline;
font-size: 0.875rem; font-size: var(--sk-typo-base);
} }

29
src/_dark.scss Normal file
View File

@ -0,0 +1,29 @@
@import 'src/themes';
// modifiers
$modifier-item-hover: -1%;
$modifier-gradient-lightness: +20%;
$ui-background: #191919;
$ui-text: #ffffff;
$ui-gray-text: #959595;
$ui-foreground: #252525;
$ui-left-menu: rgba(0,0,0,0.65);
$ui-right-content: rgba(0,0,0,0.45);
$ui-shadow: rgba(95, 95, 95, 0.15);
$ui-item-active: rgba(255, 255, 255, 0.1);
$ui-primary-accent: #2698e4;
$ui-secondary-accent: #9a74e0;
$ui-secondary-accent-text: #ffffff;
$ui-border: rgba(255, 255, 255, 0.1);
$ui-negative: #ff4f4f;
$ui-positive: #3ac52b;
$ui-warning: #fd8a09;
$ui-palette: #F8505D, #DC496C, #C8449C, #E362B7, #975BEB, #7A7AF3, #5C99FA, #37B3FA, #71CBAF, #7ACB71, #A5D458, #F7B433, #F89C35, #FB5607;
$ui-overlay: rgba(22, 22, 22, 0.4);
$ui-dark-overlay: rgba(0, 0, 0, 0.2);
$ui-black: #000000;
@mixin dark {
@include theme
}

29
src/_light.scss Normal file
View File

@ -0,0 +1,29 @@
@import 'src/themes';
//modifiers
$modifier-item-hover: +30%;
$modifier-gradient-lightness: +50%;
$ui-background: #ffffff;
$ui-text: #000000;
$ui-gray-text: #8c8c8c;
$ui-foreground: #f4f4f4;
$ui-left-menu: rgba(255, 255, 255, 0.75);
$ui-right-content: rgba(255,255,255,0.35);
$ui-shadow: rgba(50, 50, 50, 0.1);
$ui-item-active: rgba(0,0,0,0.075);
$ui-secondary-accent: #715AB6;
$ui-primary-accent: #5f74ff;
$ui-secondary-accent-text: #ffffff;
$ui-border: rgba(0,0,0,0.25);
$ui-negative: #ff3939;
$ui-positive: #3ac52b;
$ui-warning: #fd8a09;
$ui-palette: #FD2B3B,#DA224E,#C11C89,#AD177A,#8338EC,#5F5FF6,#3A86FF,#0BA7FF,#54C4A2,#5FC454,#95D035,#FBA807,#FD8A09,#FB5607;
$ui-overlay: rgba(55, 55, 55, 0.35);
$ui-dark-overlay: rgba(0, 0, 0, 0.7);
$ui-black: #000000;
@mixin light {
@include theme
}

144
src/_themes.scss Normal file
View File

@ -0,0 +1,144 @@
@use 'sass:color';
@mixin gradientY ($colors) {
background: linear-gradient(to bottom, $colors);
}
@function shade ($color, $opacity) {
@return transparentize($color, $opacity);
}
@function gradient ($color, $value: +50%) {
$top: scale-color($color, $lightness: $value);
$bottom: $color;
@return #{$top}, #{$bottom};
}
@function colorsGradient ($colors) {
$line: "";
@for $i from 1 through length($colors) {
@if ($i > 1) {
$line: $line + ',';
}
$line: $line + #{nth($colors, $i)}
}
@return $line;
}
@function hovered ($color, $value: +10%) {
@return scale-color($color, $lightness: $value);
}
@mixin theme {
// base
--sk-background : #{$ui-background};
--sk-background-75 : #{shade($ui-background, 0.25)};
--sk-background-50 : #{shade($ui-background, 0.5)};
--sk-text : #{$ui-text};
--sk-gray-text : #{$ui-gray-text};
--sk-foreground : #{$ui-foreground};
--sk-foreground-hovered : #{hovered($ui-foreground)};
--sk-left-menu : #{$ui-left-menu};
--sk-right-content : #{$ui-right-content};
--sk-item-active : #{$ui-item-active};
--sk-item-hovered : #{hovered($ui-item-active, $modifier-item-hover)};
--sk-shadow : #{shade($ui-shadow, 0)};
--sk-shadow-hovered : #{shade($ui-shadow, 0)};
// primary color
--sk-primary-accent : #{$ui-primary-accent};
--sk-primary-accent-hovered : #{hovered($ui-primary-accent)};
@for $i from 9 through 1 {
--sk-primary-accent-#{10 * $i}: #{shade($ui-primary-accent, 1 - 0.1 * $i)};
}
--sk-primary-accent-5: #{shade($ui-primary-accent, 0.95)};
--sk-primary-accent-gradient: #{gradient(shade($ui-primary-accent, 0), $modifier-gradient-lightness)};
// secondary color
--sk-secondary-accent : #{$ui-secondary-accent};
--sk-secondary-accent-hovered : #{hovered($ui-secondary-accent)};
@for $i from 9 through 1 {
--sk-secondary-accent-#{10 * $i}: #{shade($ui-secondary-accent, 1 - 0.1 * $i)};
}
--sk-secondary-accent-5: #{shade($ui-secondary-accent, 0.95)};
--sk-secondary-accent-text : #{$ui-secondary-accent-text};
// border
--sk-border : #{$ui-border};
--sk-border-hovered : #{hovered($ui-border)};
// negative
--sk-negative : #{$ui-negative};
@for $i from 9 through 1 {
--sk-negative-#{10 * $i}: #{shade($ui-negative, 1 - 0.1 * $i)};
}
--sk-negative-5: #{shade($ui-negative, 0.95)};
--sk-negative-hovered : #{hovered($ui-negative)};
// positive
--sk-positive : #{$ui-positive};
@for $i from 9 through 1 {
--sk-positive-#{10 * $i}: #{shade($ui-positive, 1 - 0.1 * $i)};
}
--sk-positive-5: #{shade($ui-positive, 0.95)};
--sk-positive-hovered : #{hovered($ui-positive)};
// warning
--sk-warning : #{$ui-warning};
@for $i from 9 through 1 {
--sk-warning-#{10 * $i}: #{shade($ui-warning, 1 - 0.1 * $i)};
}
--sk-warning-5: #{shade($ui-warning, 0.95)};
--sk-warning-hovered : #{hovered($ui-warning)};
// palette colors & gradients
@for $i from 1 through length($ui-palette) {
--sk-palette-#{$i - 1}-5: #{shade(nth($ui-palette, $i), 0.95)};
--sk-palette-#{$i - 1}: #{nth($ui-palette, $i)};
--sk-palette-gradient-#{$i - 1}: #{gradient(nth($ui-palette, $i), $modifier-gradient-lightness)};
@for $j from 9 through 1 {
--sk-palette-#{$i - 1}-#{10 * $j}: #{shade(nth($ui-palette, $i), 1 - 0.1 * $j)};
--sk-palette-gradient-#{$i - 1}-#{10 * $j}: #{gradient(shade(nth($ui-palette, $i), 1 - 0.1 * $j), $modifier-gradient-lightness)};
}
--sk-palette-#{$i - 1}-5: #{shade(nth($ui-palette, $i), 0.95)};
--sk-palette-gradient-#{$i - 1}-5: #{gradient(shade(nth($ui-palette, $i), 0.95), $modifier-gradient-lightness)};
}
--sk-overlay: #{$ui-overlay};
--sk-overlay-50: #{shade($ui-overlay, 0.2)};
--sk-dark-overlay: #{$ui-dark-overlay};
// black & shades
--sk-black: #{$ui-black};
@for $i from 9 through 1 {
--sk-black-#{10 * $i}: #{shade($ui-black, 1 - 0.1 * $i)};
}
--sk-typo-base: 14px;
--sk-typo-special: 13px;
--sk-typo-title: 24px;
--sk-typo-subtitle: 12px;
--sk-typo-h1: 26px;
--sk-typo-h2: 24px;
--sk-typo-h3: 22px;
--sk-typo-h4: 20px;
--sk-typo-h5: 17px;
--sk-typo-h6: 15px;
// gaps
--sk-gap-xs: 0.125rem;
--sk-gap-s: 0.25rem;
--sk-gap-m: 0.5rem;
--sk-gap-l: 0.75rem;
--sk-gap-xl: 1rem;
// border-radius
--sk-br-s: 0.25rem;
--sk-br-m: 0.5rem;
}

View File

@ -1,5 +1,6 @@
import { Component, OnInit, AfterViewInit } from '@angular/core'; import { Component, OnInit, AfterViewInit } from '@angular/core';
import { Router, RouterEvent } from '@angular/router'; import { Router, RouterEvent } from '@angular/router';
import { LocalStorage, LocalStorageService } from 'ngx-webstorage'
import { GoWebViewInit } from './services/go'; import { GoWebViewInit } from './services/go';
@Component({ @Component({
@ -9,16 +10,30 @@ import { GoWebViewInit } from './services/go';
}) })
export class AppComponent implements OnInit{ export class AppComponent implements OnInit{
constructor(private router: Router){ } title = 'go-web';
constructor(private router: Router, private storage: LocalStorageService) { }
@LocalStorage('theme', 'dark')
public theme!: string
ngOnInit(){ ngOnInit(){
document.addEventListener('GoChangeRoute_Callback', (event:any) => { document.addEventListener('GoChangeRoute_Callback', (event:any) => {
this.router.navigate([event.detail]) this.router.navigate([event.detail])
console.log("Navigating to route:" + event.detail) console.log("Navigating to route:" + event.detail)
}) })
this.setTheme(this.theme)
this.storage.observe('theme').subscribe(value => {
this.setTheme(this.theme)
})
} }
ngAfterViewInit(){ ngAfterViewInit(){
GoWebViewInit() GoWebViewInit()
} }
title = 'go-web';
setTheme (theme: string) {
document.querySelector('html')?.setAttribute('data-theme', theme)
}
} }

View File

@ -16,6 +16,7 @@ import { SandboxModule } from './components/sandbox/sandbox.module';
import { SignInModule } from './components/sign-in/sign-in.module'; import { SignInModule } from './components/sign-in/sign-in.module';
import { LoadingScreenComponent } from './components/loading-screen/loading-screen.component'; import { LoadingScreenComponent } from './components/loading-screen/loading-screen.component';
import { UiModule } from 'projects/ui/src/lib/ui.module' import { UiModule } from 'projects/ui/src/lib/ui.module'
import { NgxWebstorageModule } from 'ngx-webstorage'
@NgModule({ @NgModule({
declarations: [AppComponent, LoadingScreenComponent], declarations: [AppComponent, LoadingScreenComponent],
@ -28,7 +29,8 @@ import { UiModule } from 'projects/ui/src/lib/ui.module'
PlaygroundModule, PlaygroundModule,
SandboxModule, SandboxModule,
SignInModule, SignInModule,
UiModule UiModule,
NgxWebstorageModule.forRoot({ prefix: 'skirda', separator: '.', caseSensitive: true })
], ],
providers: [ providers: [
{ provide: APP_BASE_HREF, useValue: '/' }, { provide: APP_BASE_HREF, useValue: '/' },

View File

@ -20,7 +20,6 @@
from { from {
opacity: 1; opacity: 1;
scale: 0; scale: 0;
background-color: #d6282800;
} }
50% { 50% {
opacity: 0.5; opacity: 0.5;
@ -28,7 +27,6 @@
to { to {
opacity: 0; opacity: 0;
scale: 3; scale: 3;
background-color: #d6282899;
} }
} }
@ -37,7 +35,7 @@
width: 140px; width: 140px;
height: 140px; height: 140px;
overflow: hidden; overflow: hidden;
background-color: rgba(255, 255, 255, 0.1); background-color: var(--sk-item-active);
mask-image: url('/assets/icon_mask.svg'); mask-image: url('/assets/icon_mask.svg');
mask-size: cover; mask-size: cover;
user-select: none; user-select: none;
@ -58,17 +56,15 @@
translate: -50% -50%; translate: -50% -50%;
width: 24px; width: 24px;
height: 24px; height: 24px;
border: 1.5px solid var(--sk-primary); border: 1.5px solid var(--sk-primary-accent);
border-radius: 50%; border-radius: 50%;
animation: loaderPulse 1.4s linear -0.7s infinite forwards; animation: loaderPulse 1.4s linear -0.7s infinite forwards;
mask-image: linear-gradient(to bottom, black 0%, black 40%, transparent 75%); mask-image: linear-gradient(to bottom, black 0%, black 40%, transparent 75%);
z-index: 0; z-index: 0;
box-shadow: inset 0px 0.25px 0px 0px rgba(255, 255, 255, 0.5);
} }
&:after { &:after {
animation-delay: 0s; animation-delay: 0s;
border: 1.5px solid var(--sk-secondary);
} }
skirda-heading { skirda-heading {

View File

@ -1,32 +1,35 @@
<menu> <menu>
<div class="sk-search-panel"> <div class="menu-search-panel">
<skirda-input [formControl]="search" size="l" placeholder="Quick search"> <skirda-input [formControl]="search" size="l" placeholder="Quick search">
<skirda-icon name="search" size="18" role="left"></skirda-icon> <skirda-icon name="search" size="18" role="left"></skirda-icon>
</skirda-input> </skirda-input>
<button> <button>
<skirda-icon name="menu-panel" color="var(--sk-primary)"></skirda-icon> <skirda-icon name="menu-panel" color="var(--sk-primary-accent)"></skirda-icon>
</button> </button>
</div> </div>
<div class="sk-sections"> <div class="menu-content" skirdaIsScrolling>
<!-- Здесь class="active" для подсвечивания активного раздела прописывается автоматически, <div class="menu-sections">
если URL после перехода соддержит routerLink (класс прописывается в routerLinkActive) --> <!-- Здесь class="active" для подсвечивания активного раздела прописывается автоматически,
<skirda-section [routerLink]="['servers']" routerLinkActive="active"> если URL после перехода соддержит routerLink (класс прописывается в routerLinkActive) -->
<skirda-icon name="server"></skirda-icon> <skirda-section [routerLink]="['servers']" routerLinkActive="active">
<skirda-heading size="6">Servers</skirda-heading> <skirda-icon name="server"></skirda-icon>
</skirda-section> <skirda-heading size="6">Servers</skirda-heading>
<skirda-section [routerLink]="['games']" routerLinkActive="active"> </skirda-section>
<skirda-icon name="library"></skirda-icon> <skirda-section [routerLink]="['games']" routerLinkActive="active">
<skirda-heading size="6">Library</skirda-heading> <skirda-icon name="library"></skirda-icon>
</skirda-section> <skirda-heading size="6">Library</skirda-heading>
<skirda-section [routerLink]="['friends']" routerLinkActive="active"> </skirda-section>
<skirda-icon name="friends"></skirda-icon> <skirda-section [routerLink]="['friends']" routerLinkActive="active">
<skirda-heading size="6">Friends</skirda-heading> <skirda-icon name="friends"></skirda-icon>
</skirda-section> <skirda-heading size="6">Friends</skirda-heading>
<skirda-section [routerLink]="['downloads']" routerLinkActive="active"> </skirda-section>
<skirda-icon name="download"></skirda-icon> <skirda-section [routerLink]="['downloads']" routerLinkActive="active">
<skirda-heading size="6">Downloads</skirda-heading> <skirda-icon name="download"></skirda-icon>
</skirda-section> <skirda-heading size="6">Downloads</skirda-heading>
</skirda-section>
</div>
<app-menu-games></app-menu-games>
<app-menu-sessions></app-menu-sessions>
</div> </div>
<app-menu-games></app-menu-games> <app-menu-profile></app-menu-profile>
<app-menu-sessions></app-menu-sessions>
</menu> </menu>

View File

@ -9,24 +9,24 @@
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%; height: 100%;
background-color: rgba(0,0,0,0.65); background-color: var(--sk-left-menu);
padding: 2rem 0.5rem 0.5rem 0.5rem; padding: 0.5rem 0.5rem 0.5rem 0.5rem;
box-sizing: border-box; box-sizing: border-box;
backdrop-filter: blur(64px); backdrop-filter: blur(64px);
overflow-y: auto; overflow-y: auto;
gap: 1rem;
.sk-search-panel { .menu-search-panel {
display: flex; display: flex;
gap: 0.625rem; gap: 0.625rem;
flex-shrink: 0;
skirda-input { skirda-input {
flex: 1; flex: 1;
} }
button { button {
height: 100%; height: 42px;
aspect-ratio: 1/1; width: 42px;
padding: 0; padding: 0;
margin: 0; margin: 0;
outline: none; outline: none;
@ -37,17 +37,37 @@
border-radius: var(--sk-br-m); border-radius: var(--sk-br-m);
cursor: pointer; cursor: pointer;
flex-shrink: 0; flex-shrink: 0;
color: var(--sk-primary-accent);
&:hover { &:hover {
background-color: rgba(255, 255, 255, 0.05); background-color: var(--sk-primary-accent-20);
} }
} }
} }
.sk-sections { .menu-content {
flex: 1;
overflow-y: auto;
padding: 1.25rem 0rem;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.1875rem; gap: var(--sk-gap-l);
&[data-scroll-y="true"] {
mask-image: linear-gradient(to bottom, transparent 0%, black 1.25rem, black calc(100% - 1.25rem), transparent);
padding-right: 0.5rem;
}
.menu-sections {
display: grid;
grid-template-columns: 1fr 1fr;
flex-direction: column;
gap: 0.1875rem;
}
}
app-menu-profile {
flex-shrink: 0;
} }
} }
} }

View File

@ -3,7 +3,6 @@
</skirda-section-label> </skirda-section-label>
<div class="games"> <div class="games">
<skirda-game <skirda-game
[routerLink]="['/game/' + game.gameId]" routerLinkActive="active"
*ngFor="let game of games; index as i" *ngFor="let game of games; index as i"
[game]="game" [game]="game"
></skirda-game> ></skirda-game>

View File

@ -0,0 +1,11 @@
<skirda-avatar [username]="profile.username" size="small"></skirda-avatar>
<div class="profile-info">
<skirda-heading size="6">{{profile.username}}</skirda-heading>
<skirda-text>online</skirda-text>
</div>
<div class="theme-toggle" (click)="toggleTheme()" [ngClass]="{'active': theme === 'light'}">
<skirda-icon name="sun" color="var(--sk-primary-accent)"></skirda-icon>
</div>
<a [routerLink]="['settings']">
<skirda-icon name="settings" color="var(--sk-primary-accent)"></skirda-icon>
</a>

View File

@ -0,0 +1,36 @@
:host {
display: flex;
gap: var(--sk-gap-l);
padding: var(--sk-gap-l);
align-items: center;
.profile-info {
flex: 1;
display: flex;
flex-direction: column;
gap: var(--sk-gap-s);
skirda-text {
opacity: 0.5;
}
}
skirda-icon {
cursor: pointer;
}
}
:host::ng-deep {
.theme-toggle {
padding: var(--sk-gap-s);
border-radius: 2rem;
&.active {
background-color: var(--sk-primary-accent);
skirda-icon ng-icon {
color: #fff!important;
}
}
}
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MenuProfileComponent } from './menu-profile.component';
describe('MenuProfileComponent', () => {
let component: MenuProfileComponent;
let fixture: ComponentFixture<MenuProfileComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ MenuProfileComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(MenuProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,25 @@
import { Component, OnInit } from '@angular/core';
import { LocalStorage } from 'ngx-webstorage'
import { Profile } from 'src/app/interfaces/profile.interface'
@Component({
selector: 'app-menu-profile',
templateUrl: './menu-profile.component.html',
styleUrls: ['./menu-profile.component.scss']
})
export class MenuProfileComponent implements OnInit {
@LocalStorage('profile', <Profile>{username: 'username'})
public profile!: Profile
@LocalStorage('theme', 'dark')
public theme!: string
constructor() { }
ngOnInit(): void {
}
toggleTheme () {
this.theme = this.theme == 'light' ? 'dark' : 'light'
}
}

View File

@ -3,7 +3,6 @@
</skirda-section-label> </skirda-section-label>
<div class="sessions"> <div class="sessions">
<skirda-session <skirda-session
[routerLink]="['/session/' + session.gameId]" routerLinkActive="active"
*ngFor="let session of sessions; index as i" *ngFor="let session of sessions; index as i"
[session]="session" [session]="session"
></skirda-session> ></skirda-session>

View File

@ -23,7 +23,7 @@
.content { .content {
flex: 1; flex: 1;
background-color: rgba(0,0,0,0.15); background-color: var(--sk-right-content);
display: flex; display: flex;
backdrop-filter: blur(2rem); backdrop-filter: blur(2rem);
// overflow-y: auto; // overflow-y: auto;

View File

@ -12,11 +12,9 @@ import { GamesPageComponent } from './sections/games-page/games-page.component';
import { SessionPageComponent } from './sections/session-page/session-page.component'; import { SessionPageComponent } from './sections/session-page/session-page.component';
import { GamePageComponent } from './sections/game-page/game-page.component'; import { GamePageComponent } from './sections/game-page/game-page.component';
import { MainRoutingModule } from './routing.module'; import { MainRoutingModule } from './routing.module';
import { ButtonModule } from 'projects/ui/src/lib/button/button.module';
import { TypographyModule } from 'projects/ui/src/lib/typography/typography.module';
import { IconModule } from 'projects/ui/src/lib/icon/icon.module';
import { DownloadsPageComponent } from './sections/downloads-page/downloads-page.component'; import { DownloadsPageComponent } from './sections/downloads-page/downloads-page.component';
import { PopupModule } from 'projects/ui/src/public-api'; import { MenuProfileComponent } from './main-menu/menu-profile/menu-profile.component'
import { SettingsPageComponent } from './sections/settings-page/settings-page.component'
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -30,17 +28,15 @@ import { PopupModule } from 'projects/ui/src/public-api';
SessionPageComponent, SessionPageComponent,
GamePageComponent, GamePageComponent,
DownloadsPageComponent, DownloadsPageComponent,
SettingsPageComponent,
MenuProfileComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
UiModule, UiModule,
ReactiveFormsModule, ReactiveFormsModule,
FormsModule, FormsModule,
MainRoutingModule, MainRoutingModule
TypographyModule,
ButtonModule,
IconModule,
PopupModule,
], ],
exports: [ exports: [
MainRootComponent, MainRootComponent,
@ -53,6 +49,8 @@ import { PopupModule } from 'projects/ui/src/public-api';
SessionPageComponent, SessionPageComponent,
GamePageComponent, GamePageComponent,
DownloadsPageComponent, DownloadsPageComponent,
SettingsPageComponent,
MenuProfileComponent
], ],
}) })
export class MainModule {} export class MainModule {}

View File

@ -7,6 +7,7 @@ import { GamePageComponent } from './sections/game-page/game-page.component';
import { GamesPageComponent } from './sections/games-page/games-page.component'; import { GamesPageComponent } from './sections/games-page/games-page.component';
import { ServersPageComponent } from './sections/servers-page/servers-page.component'; import { ServersPageComponent } from './sections/servers-page/servers-page.component';
import { SessionPageComponent } from './sections/session-page/session-page.component'; import { SessionPageComponent } from './sections/session-page/session-page.component';
import { SettingsPageComponent } from './sections/settings-page/settings-page.component'
const routes: Routes = [ const routes: Routes = [
{ {
@ -29,6 +30,10 @@ const routes: Routes = [
path: 'downloads', path: 'downloads',
component: DownloadsPageComponent, component: DownloadsPageComponent,
}, },
{
path: 'settings',
component: SettingsPageComponent,
},
{ {
path: 'session/:id', path: 'session/:id',
component: SessionPageComponent, component: SessionPageComponent,

View File

@ -0,0 +1,8 @@
<div class="section">
<div class="section-head">
<div class="head-title">
<skirda-heading size="1">Settings</skirda-heading>
</div>
<div class="head-subtitle">Settings page will be here</div>
</div>
</div>

View File

@ -0,0 +1,7 @@
@use '../global';
:host {
display: block;
@include global.page();
}

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SettingsPageComponent } from './settings-page.component';
describe('SettingsPageComponent', () => {
let component: SettingsPageComponent;
let fixture: ComponentFixture<SettingsPageComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ SettingsPageComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(SettingsPageComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-settings-page',
templateUrl: './settings-page.component.html',
styleUrls: ['./settings-page.component.scss']
})
export class SettingsPageComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,3 @@
export interface Profile {
username: string
}

View File

@ -1,9 +1,8 @@
export interface Session { export interface Session {
gameId: string; gameId: string;
icon: string; icon: string;
title: string; title: string;
status?: string; status?: string;
version: string; version: string;
expires: Date; expires: Date;
} }

View File

@ -1,5 +1,5 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en" data-theme="dark">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>GoWeb</title> <title>GoWeb</title>

View File

@ -1,9 +1,11 @@
@use 'src/light';
@use 'src/dark';
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap');
html, body { html, body {
background-color: #222; background-color: var(--sk-background);
color: #fff; color: var(--sk-text);
font-size: 16px; font-size: var(--sk-typo-base);
margin: 0; margin: 0;
font-family: var(--font); font-family: var(--font);
line-height: 90%; line-height: 90%;
@ -14,29 +16,28 @@ button, input, textarea {
font-family: var(--font); font-family: var(--font);
} }
@media (prefers-color-scheme: dark) {
html:root {
@include dark.theme;
}
}
@media (prefers-color-scheme: light) {
html:root {
@include light.theme;
}
}
html[data-theme="light"]:root {
@include light.theme;
}
html[data-theme="dark"]:root {
@include dark.theme;
}
:root { :root {
--font: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; --font: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
--sk-gap-xs: 0.125rem;
--sk-gap-s: 0.25rem;
--sk-gap-m: 0.5rem;
--sk-gap-l: 0.75rem;
--sk-gap-xl: 1rem;
// colors
--sk-input: rgba(18,18,18,0.5);
--sk-input-focus: rgba(18,18,18,0.9);
--sk-primary: #d62828ff;
--sk-secondary: #f77f00ff;
// border-radius
--sk-br-s: 0.25rem;
--sk-br-m: 0.5rem;
--sk-palette-1: #ffbe0b;
--sk-palette-2: #fb5607;
--sk-palette-3: #ff006e;
--sk-palette-4: #8338ec;
--sk-palette-5: #3a86ff;
--sk-overlay: rgba(0,0,0,0.5);
} }
/* Works on Firefox */ /* Works on Firefox */