Skip to content

Commit e679f7b

Browse files
committed
feat: SeasonalTheme;
fix: iphone dialog
1 parent 1bb3695 commit e679f7b

16 files changed

+268
-29
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "chytanka",
3-
"version": "0.14.31",
3+
"version": "0.13.32",
44
"scripts": {
55
"ng": "ng",
66
"start": "ng serve",
Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,67 @@
11
import { isPlatformBrowser } from '@angular/common';
2-
import { Injectable, PLATFORM_ID, WritableSignal, inject, signal } from '@angular/core';
2+
import { Injectable, PLATFORM_ID, WritableSignal, computed, inject, signal } from '@angular/core';
33

44
@Injectable({
55
providedIn: 'root'
66
})
77
export class LinkParserSettingsService {
8-
autoPasteLink: WritableSignal<boolean> = signal(false);
98
platformId = inject(PLATFORM_ID)
109

10+
autoPasteLink!: WritableSignal<boolean>;
11+
1112
constructor() {
1213
this.initAutoPasteLink()
14+
this.initSeasonalTheme()
1315
}
1416

1517
initAutoPasteLink() {
16-
if(!isPlatformBrowser(this.platformId)) return;
18+
if (!isPlatformBrowser(this.platformId)) return;
1719

1820
const n = Boolean(localStorage.getItem('autoPasteLink') == 'true');
19-
this.autoPasteLink.set(n);
21+
this.autoPasteLink = signal(n);
2022
}
2123

2224
setAutoPasteLink(n: boolean) {
23-
if(!isPlatformBrowser(this.platformId)) return;
24-
25+
if (!isPlatformBrowser(this.platformId)) return;
26+
2527
this.autoPasteLink.set(n);
2628
localStorage.setItem('autoPasteLink', n.toString())
2729
}
30+
31+
/**
32+
*
33+
*/
34+
seasonalTheme!: WritableSignal<boolean>;
35+
36+
initSeasonalTheme() {
37+
if (!isPlatformBrowser(this.platformId)) return;
38+
39+
const n = localStorage.getItem('seasonalTheme') === null ? true : Boolean(localStorage.getItem('seasonalTheme') == 'true');
40+
this.seasonalTheme = signal(n);
41+
this.setSeasonalTheme(n);
42+
}
43+
44+
setSeasonalTheme(n: boolean) {
45+
if (!isPlatformBrowser(this.platformId)) return;
46+
47+
this.seasonalTheme.update(v => n);
48+
localStorage.setItem('seasonalTheme', n.toString())
49+
}
50+
51+
getSeasonalTheme(): string {
52+
const now = new Date();
53+
const month = now.getMonth(); // 0-11
54+
const day = now.getDate();
55+
56+
if (month === 5) return 'pride'; // June
57+
if (month === 9 && day > 15) return 'halloween'; // second half of Oct
58+
if (month === 11 || (month === 0 && day < 10)) return 'newyear';
59+
if (month === 1 && day <= 15) return 'valentine';
60+
return 'default';
61+
}
62+
63+
theme = computed(() => {
64+
if (!this.seasonalTheme) return '';
65+
return this.seasonalTheme() ? this.getSeasonalTheme() : ''
66+
})
2867
}

src/app/link-parser/link-parser/link-parser.component.scss

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,35 @@
2020
}
2121
}
2222

23+
&.pride {
24+
--pride-red: oklch(from #e40303 0.2624 0.064157 h);
25+
--pride-ora: oklch(from #ff8c00 0.2624 0.064157 h);
26+
--pride-yel: oklch(from #ffed00 0.2624 0.064157 h);
27+
--pride-gre: oklch(from #008026 0.2624 0.064157 h);
28+
--pride-blu: oklch(from #004dff 0.2624 0.064157 h);
29+
--pride-fio: oklch(from #750787 0.2624 0.064157 h);
30+
background: linear-gradient(120deg, var(--pride-red), var(--pride-ora), var(--pride-yel), var(--pride-gre), var(--pride-blu), var(--pride-fio));
31+
}
32+
33+
&.halloween {
34+
background: #222;
35+
}
36+
2337
@media (prefers-color-scheme: light) {
2438
background: #eceff2;
39+
40+
&.pride {
41+
--pride-red: oklch(from #e40303 0.96 0.0128 h);
42+
--pride-ora: oklch(from #ff8c00 0.96 0.0128 h);
43+
--pride-yel: oklch(from #ffed00 0.96 0.0128 h);
44+
--pride-gre: oklch(from #008026 0.96 0.0128 h);
45+
--pride-blu: oklch(from #004dff 0.96 0.0128 h);
46+
--pride-fio: oklch(from #750787 0.96 0.0128 h);
47+
}
48+
49+
&.halloween {
50+
background: #f9ece5;
51+
}
2552
}
2653
}
2754

@@ -81,6 +108,7 @@ lp-header {
81108
}
82109

83110
:host:has(input[type=url]:focus) {
111+
84112
lp-footer,
85113
lp-header,
86114
#createListLink {

src/app/link-parser/link-parser/link-parser.component.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
1+
import { ChangeDetectionStrategy, Component, computed, HostBinding, inject } from '@angular/core';
22
import { LangService } from '../../shared/data-access/lang.service';
33
import { MetaTagsService } from '../../shared/data-access/meta-tags.service';
44
import { LinkParserService } from '../data-access/link-parser.service';
5+
import { LinkParserSettingsService } from '../data-access/link-parser-settings.service';
56

67
@Component({
78
selector: 'app-link-parser',
@@ -11,12 +12,16 @@ import { LinkParserService } from '../data-access/link-parser.service';
1112
'./link-parser.dual-screen.component.scss'
1213
],
1314
standalone: false,
14-
changeDetection: ChangeDetectionStrategy.OnPush
15+
changeDetection: ChangeDetectionStrategy.OnPush,
16+
host: {
17+
'[class]': 'this.setts.theme()'
18+
}
1519
})
1620
export class LinkParserComponent {
1721
private meta: MetaTagsService = inject(MetaTagsService);
1822
private lang: LangService = inject(LangService)
1923
public parser: LinkParserService = inject(LinkParserService)
24+
public setts = inject(LinkParserSettingsService)
2025

2126
constructor() {
2227
this.initMeta()

src/app/link-parser/ui/parser-form/parser-form.component.html

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<div class="form-wrapper">
2-
<h1 class="logo-text"> <app-text-embracer [text]="lang.ph().shortTitle" /> </h1>
2+
<h1 class="logo-text"> <app-text-embracer [ngClass]="setts.theme()" [text]="lang.ph().shortTitle" /> </h1>
33
<div style="display: flex; gap: 1ch; align-items: center;">
44
<form (submit)="onSubmit()">
5-
<input name="chtnk_url" type="url" required autofocus
6-
[placeholder]="lang.ph().enterLink" (input)="inputLink($event)" [value]="link()">
5+
<input name="chtnk_url" type="url" required autofocus [placeholder]="lang.ph().enterLink"
6+
(input)="inputLink($event)" [value]="link()">
77
</form>
88
</div>
99
<div style="display: flex; gap: 1ch; align-items: center;">
@@ -13,10 +13,21 @@ <h1 class="logo-text"> <app-text-embracer [text]="lang.ph().shortTitle" /> </h1>
1313
</div>
1414

1515
<div class="slogan-wrapper">
16-
<h2 class="slogan-header">{{lang.ph().slogan}}</h2>
16+
<h2 class="slogan-header">
17+
@if (setts.seasonalTheme != undefined && setts.seasonalTheme()) {
18+
@switch (setts.theme()) {
19+
@case ('pride') {<span class="slogan-rainbow"> {{lang.ph().sloganPride}}</span> 🏳️‍🌈}
20+
@case ('halloween') {<span class="slogan-halloween"> {{lang.ph().sloganHalloween}}</span> 🕷️}
21+
@case ('newyear') {<span class="slogan-newyear"> {{lang.ph().sloganNewYear}}</span> 🎇}
22+
@case ('valentine') {<span class="slogan-valentine"> {{lang.ph().sloganValentine}}</span> ❤️📖}
23+
}
24+
}
25+
@else {
26+
{{lang.ph().slogan}}
27+
}
28+
</h2>
1729
@if (linkParams()) {
18-
<a class="button primary large go-btn"
19-
[routerLink]="['',linkParams()?.site, linkParams64()?.id]">
30+
<a class="button primary large go-btn" [routerLink]="['',linkParams()?.site, linkParams64()?.id]">
2031
<span>{{lang.ph().letsgo}} </span>
2132
<img class="favicon" [src]="favicons[linkParams()?.site]" [alt]="linkParams()?.site">
2233
<small class="site-address" [title]="linkParams()?.id">{{linkParams()?.id | truncate}}</small>

src/app/link-parser/ui/parser-form/parser-form.component.scss

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,105 @@ app-text-embracer {
4242
}
4343
}
4444

45+
::ng-deep app-text-embracer.pride>span {
46+
--theme-base: #166496;
47+
--shc: oklch(from var(--theme-base) var(--avarage-l-2) c h);
48+
--border-color: oklch(from var(--theme-base) .64 0.2 h);
49+
--dot-color: oklch(from var(--theme-base) .7 0.2 h);
50+
color: oklch(from var(--theme-base) .7 0.2 h);
51+
-webkit-text-stroke: var(--shc) var(--border-width);
52+
53+
// --gl: radial-gradient(circle 1px at 0px 0px, var(--dot-color) 1px, transparent 0);
54+
55+
border-image: linear-gradient(90deg, #e40303, #ff8c00, #ffed00, #008026, #004dff, #750787);
56+
border-image-slice: 1;
57+
58+
&:nth-of-type(2),
59+
&:nth-of-type(1) {
60+
--theme-base: #e40303;
61+
}
62+
63+
&:nth-of-type(3) {
64+
--theme-base: #ff8c00;
65+
}
66+
67+
&:nth-of-type(4) {
68+
--theme-base: #ffed00;
69+
}
70+
71+
&:nth-of-type(5) {
72+
--theme-base: #008026;
73+
}
74+
75+
&:nth-of-type(6) {
76+
--theme-base: #004dff;
77+
}
78+
79+
&:nth-of-type(7) {
80+
--theme-base: #750787;
81+
}
82+
}
83+
84+
::ng-deep app-text-embracer.pride:has(span:nth-of-type(8))>span {
85+
86+
&:nth-of-type(3),
87+
&:nth-of-type(1),
88+
&:nth-of-type(2) {
89+
--theme-base: #e40303;
90+
}
91+
92+
&:nth-of-type(4) {
93+
--theme-base: #ff8c00;
94+
}
95+
96+
&:nth-of-type(5) {
97+
--theme-base: #ffed00;
98+
}
99+
100+
&:nth-of-type(6) {
101+
--theme-base: #008026;
102+
}
103+
104+
&:nth-of-type(7) {
105+
--theme-base: #004dff;
106+
}
107+
108+
&:nth-of-type(8) {
109+
--theme-base: #750787;
110+
}
111+
}
112+
113+
@property --halloween-base {
114+
syntax: "<color>";
115+
inherits: true;
116+
initial-value: #FF7518;
117+
}
118+
119+
::ng-deep app-text-embracer.halloween>span {
120+
--shc: oklch(from var(--halloween-base) var(--avarage-l-2) c h);
121+
--border-color: oklch(from var(--halloween-base) .64 0.2 h);
122+
--dot-color: oklch(from var(--halloween-base) .7 0.2 h);
123+
color: oklch(from var(--halloween-base) .7 0.2 h);
124+
-webkit-text-stroke: var(--shc) var(--border-width);
125+
126+
animation: halloween 5s steps(3) alternate infinite;
127+
}
128+
129+
@keyframes halloween {
130+
0% {
131+
--halloween-base: #A0FF00;
132+
133+
}
134+
135+
50% {
136+
--halloween-base: #FF7518;
137+
}
138+
139+
100% {
140+
--halloween-base: #6C2DC7;
141+
}
142+
}
143+
45144
.form-wrapper {
46145
grid-column: 2;
47146
display: grid;
@@ -72,7 +171,7 @@ textarea {
72171
border: 2px solid #166496;
73172
box-shadow: var(--flat-shadow-medium);
74173
border: 0;
75-
background-color: #16649680;
174+
// background-color: #16649680;
76175
color: #ffd60a;
77176

78177
@media (prefers-color-scheme: light) {
@@ -125,6 +224,22 @@ input[type=url]::placeholder {
125224
text-wrap: balance;
126225
}
127226

227+
.slogan-rainbow {
228+
background: linear-gradient(90deg, #ff826e, #ff9600, #d5c100, #54de68, #78b8ff, #f68dff);
229+
-webkit-background-clip: text;
230+
-webkit-text-fill-color: transparent;
231+
font-weight: bold;
232+
filter: brightness(1.25);
233+
234+
@media (prefers-color-scheme: light) {
235+
filter: brightness(0.8);
236+
}
237+
}
238+
239+
.slogan-halloween {
240+
color: #FF7518;
241+
}
242+
128243
.go-btn {
129244
display: flex;
130245
gap: 1ch;

src/app/link-parser/ui/parser-form/parser-form.component.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ import { ImgurLinkParser, MangadexLinkParser, TelegraphLinkParser, RedditLinkPar
88
import { ComickLinkParser } from '../../utils/comick-link-parser';
99

1010
@Component({
11-
selector: 'app-parser-form',
12-
templateUrl: './parser-form.component.html',
13-
styleUrl: './parser-form.component.scss',
14-
standalone: false,
15-
changeDetection: ChangeDetectionStrategy.OnPush
11+
selector: 'app-parser-form',
12+
templateUrl: './parser-form.component.html',
13+
styleUrl: './parser-form.component.scss',
14+
standalone: false,
15+
changeDetection: ChangeDetectionStrategy.OnPush
1616
})
1717
export class ParserFormComponent {
1818
private router: Router = inject(Router);
@@ -85,7 +85,7 @@ export class ParserFormComponent {
8585
if (queryParamUrl) {
8686
this.link.set(queryParamUrl ?? '')
8787
} else {
88-
if (this.setts.autoPasteLink()) this.initFromclipboard();
88+
if (this.setts.autoPasteLink && this.setts.autoPasteLink()) this.initFromclipboard();
8989
}
9090
}
9191

src/app/link-parser/ui/settings/settings.component.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,23 @@
4747
</div>
4848
<input type="checkbox" [checked]="setts.autoPasteLink()" (input)="setAutoPasteLink($event)" id="autoPasteLink">
4949
</section>
50+
51+
<section [class]="!setts.seasonalTheme()? 'inactive': ''">
52+
<div>
53+
<p style="display: flex; justify-content: space-between; align-items: center;">
54+
<label class="label" for="seasonalTheme">🎨 {{lang.ph().seasonalTheme}}</label>
55+
@if(setts.seasonalTheme()) {
56+
<small class="on">ON</small>
57+
} @else {
58+
<small class="off">OFF</small>
59+
}
60+
</p>
61+
<p>
62+
<small>{{lang.ph().seasonalThemeDesc}}</small>
63+
</p>
64+
</div>
65+
<input type="checkbox" [checked]="setts.seasonalTheme()" (input)="setSeasonalTheme($event)" id="seasonalTheme">
66+
</section>
5067
</fieldset>
5168

5269
<fieldset>

src/app/link-parser/ui/settings/settings.component.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ export class SettingsComponent {
2828

2929
}
3030

31+
setSeasonalTheme(e: Event) {
32+
this.setts.setSeasonalTheme((e.target as HTMLInputElement).checked)
33+
//
34+
35+
}
36+
3137
setSaveFileToHistory(e: Event) {
3238
this.fileSetts.setSaveFileToHistory((e.target as HTMLInputElement).checked)
3339

0 commit comments

Comments
 (0)