Skip to content

Commit 5d149e3

Browse files
authored
Update color scheme and other improvements (#44)
1 parent d2f2cf3 commit 5d149e3

3 files changed

Lines changed: 57 additions & 47 deletions

File tree

assets/screenshot_dark.png

26 KB
Loading

assets/screenshot_light.png

26.5 KB
Loading

index.html

Lines changed: 57 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<meta charset="UTF-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1.0">
77
<link rel="icon"
8-
href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' fill='%23e0e0e0' rx='16'/><text x='50%' y='45%' dominant-baseline='central' text-anchor='middle' font-size='85' font-family='Arial' font-weight='bold' fill='%231e1e1e'>白</text></svg>">
8+
href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' fill='%23edece7' rx='16'/><text x='50%' y='47%' dominant-baseline='central' text-anchor='middle' font-size='85' font-family='Arial' font-weight='bold' fill='%2317140c'>白</text></svg>">
99
<title>Shiro</title>
1010
<meta name="description" content="A clean, distraction-free text editor for focused writing.">
1111
<script>
@@ -23,22 +23,24 @@
2323
}
2424

2525
:root {
26-
--bg: #130f0c;
27-
--text: #dfe4e2;
28-
--placeholder: #7b807a;
26+
--bg: #17140c;
27+
--text: #edece7;
28+
--placeholder: rgb(from var(--text) r g b / 0.5);
2929
--transition: 0.3s ease;
30-
--hover-accent: #b9391b;
30+
--hover-accent: #c84733;
31+
--caret: rgba(from var(--hover-accent) r g b / 0.9);
3132
}
3233

3334
[data-theme="light"] {
34-
--bg: #dfe4e2;
35-
--text: #130f0c;
36-
--placeholder: #7b807a;
35+
--bg: #edece7;
36+
--text: #17140c;
37+
--placeholder: rgb(from var(--text) r g b / 0.5);
38+
--caret: var(--hover-accent);
3739
}
3840

3941
body {
4042
margin: 0;
41-
font: 18px/1.6 "Monaco", "Courier New", monospace;
43+
font: 18px/1.6 "Menlo", "DejaVu Sans Mono", "Consolas", monospace;
4244
background: var(--bg);
4345
color: var(--text);
4446
height: 100vh;
@@ -52,19 +54,20 @@
5254
#editor,
5355
.btn,
5456
#editor::placeholder {
55-
transition: background var(--transition), color var(--transition);
57+
transition: background var(--transition), color var(--transition), opacity var(--transition);
5658
}
5759

5860
#count,
5961
[data-action="theme"] {
60-
transition: opacity var(--transition);
62+
transition: opacity var(--transition), color var(--transition);
6163
}
6264

6365
.controls {
6466
display: flex;
6567
justify-content: space-between;
6668
padding: 18px 20px;
6769
gap: 20px;
70+
transition: opacity var(--transition);
6871
}
6972

7073
.controls>div {
@@ -84,8 +87,9 @@
8487
color: var(--hover-accent);
8588
}
8689

87-
.controls.hidden .btn {
90+
.controls.hidden {
8891
opacity: 0;
92+
pointer-events: none;
8993
}
9094

9195
main {
@@ -108,38 +112,39 @@
108112
border: none;
109113
outline: none;
110114
resize: none;
111-
transition: opacity var(--transition);
112115
tab-size: 4;
113-
box-sizing: border-box;
116+
caret-color: var(--caret);
114117
}
115118

116119
#editor::placeholder {
117120
color: var(--placeholder);
118121
}
119122

120123
::selection {
121-
background-color: rgba(185, 57, 27, 0.5);
124+
background-color: rgba(from var(--hover-accent) r g b / 0.5);
122125
color: inherit;
123126
}
124127

125128
.scroll-fade {
126129
position: absolute;
127-
left: 0;
128-
width: 100%;
129-
height: 100px;
130+
inset-inline: clamp(20px, 10vw, 20vh);
131+
height: 80px;
130132
pointer-events: none;
131-
transition: opacity 0.3s ease;
133+
transition: opacity var(--transition), background-color var(--transition);
132134
z-index: 1;
135+
background-color: var(--bg);
133136
}
134137

135138
.scroll-fade.top {
136139
top: 0;
137-
background: linear-gradient(to bottom, var(--bg) 50%, transparent 100%);
140+
mask-image: linear-gradient(to bottom, black 50%, transparent 100%);
141+
-webkit-mask-image: linear-gradient(to bottom, black 50%, transparent 100%);
138142
}
139143

140144
.scroll-fade.bottom {
141145
bottom: 0;
142-
background: linear-gradient(to top, var(--bg) 50%, transparent 100%);
146+
mask-image: linear-gradient(to top, black 50%, transparent 100%);
147+
-webkit-mask-image: linear-gradient(to top, black 50%, transparent 100%);
143148
}
144149
</style>
145150
</head>
@@ -151,8 +156,8 @@
151156
<span class="btn" data-action="clear">Clear</span>
152157
</div>
153158
<div>
154-
<span class="btn" data-action="fullscreen">Fullscreen</span>
155159
<span class="btn" data-action="theme">Light</span>
160+
<span class="btn" data-action="fullscreen">Fullscreen</span>
156161
</div>
157162
</div>
158163

@@ -199,10 +204,9 @@
199204

200205
init() {
201206
this.loadText();
202-
this.setTheme(this.theme);
207+
this.setTheme(this.theme, { transition: false });
203208
this.bindEvents();
204209
this.updateCount();
205-
this.updateFade();
206210
this.editor.focus();
207211
}
208212

@@ -353,7 +357,14 @@
353357
this.loadCursorPosition();
354358
editor.style.visibility = 'visible';
355359
this.updateCount();
360+
// Disable fade transitions until text is loaded to prevent flickering
361+
this.fadeTop.style.transition = 'none';
362+
this.fadeBottom.style.transition = 'none';
356363
this.updateFade();
364+
requestAnimationFrame(() => {
365+
this.fadeTop.style.transition = '';
366+
this.fadeBottom.style.transition = '';
367+
});
357368
});
358369
}
359370

@@ -431,16 +442,24 @@
431442
}
432443
}
433444

434-
setTheme(theme = this.theme) {
445+
setTheme(theme = this.theme, { transition = true } = {}) {
435446
const button = document.querySelector('[data-action="theme"]');
436-
button.style.opacity = '0';
437-
setTimeout(() => {
447+
const apply = () => {
438448
document.documentElement.setAttribute('data-theme', theme);
439449
button.textContent = theme === 'dark' ? 'Light' : 'Dark';
440-
button.style.opacity = '1';
441-
}, 150);
442-
localStorage.setItem(SHIRO_THEME, theme);
443-
this.theme = theme;
450+
localStorage.setItem(SHIRO_THEME, theme);
451+
this.theme = theme;
452+
};
453+
454+
if (transition) {
455+
button.style.opacity = '0';
456+
setTimeout(() => {
457+
apply();
458+
button.style.opacity = '1';
459+
}, 150);
460+
} else {
461+
apply();
462+
}
444463
}
445464

446465
updateFade() {
@@ -456,25 +475,16 @@
456475
// Actions
457476
download() {
458477
const timestamp = new Date().toISOString().slice(0, 16).replace(/[:T]/g, m => m === 'T' ? '_' : '-');
459-
const blob = new Blob([this.editor.value], { type: 'text/plain' });
460-
const url = URL.createObjectURL(blob);
461-
462-
Object.assign(document.createElement('a'), {
463-
href: url,
464-
download: `shiro_${timestamp}.txt`
465-
}).click();
466-
467-
URL.revokeObjectURL(url);
478+
const a = document.createElement('a');
479+
a.href = URL.createObjectURL(new Blob([this.editor.value], { type: 'text/plain' }));
480+
a.download = `shiro_${timestamp}.txt`;
481+
a.click();
482+
URL.revokeObjectURL(a.href);
468483
}
469484

470485
clearWithConfirmation() {
471-
if (this.editor.value.trim()) {
472-
if (confirm('Are you sure you want to clear all text?')) {
473-
this.clear();
474-
}
475-
} else {
476-
this.clear();
477-
}
486+
if (this.editor.value.trim() && !confirm('Are you sure you want to clear all text?')) return;
487+
this.clear();
478488
}
479489

480490
clear() {

0 commit comments

Comments
 (0)