Spaces:
Running
Running
Update index.html
Browse files- index.html +256 -149
index.html
CHANGED
@@ -3,28 +3,7 @@
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8" />
|
5 |
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
6 |
-
<title>
|
7 |
-
|
8 |
-
<!-- ──────── MathJax ──────── -->
|
9 |
-
<script>
|
10 |
-
window.MathJax = {
|
11 |
-
tex: {
|
12 |
-
inlineMath: [['$', '$'], ['\\(', '\\)']],
|
13 |
-
displayMath: [['$$', '$$'], ['\\[', '\\]']],
|
14 |
-
processEscapes: true,
|
15 |
-
processEnvironments: true,
|
16 |
-
},
|
17 |
-
options: { skipHtmlTags: ['script','noscript','style','textarea','pre'] }
|
18 |
-
};
|
19 |
-
</script>
|
20 |
-
<script
|
21 |
-
id="MathJax-script"
|
22 |
-
async
|
23 |
-
src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"
|
24 |
-
></script>
|
25 |
-
|
26 |
-
<!-- marked.js for Markdown -->
|
27 |
-
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
28 |
|
29 |
<!-- Google fonts -->
|
30 |
<link
|
@@ -36,7 +15,7 @@ window.MathJax = {
|
|
36 |
/* ─────────────────────────────────────────
|
37 |
COLOR SYSTEM (light / dark via variables)
|
38 |
───────────────────────────────────────── */
|
39 |
-
:root
|
40 |
--desk-bg: #fbf9f5;
|
41 |
--desk-dot: #e2dccd;
|
42 |
|
@@ -44,18 +23,25 @@ window.MathJax = {
|
|
44 |
--paper-text: #222;
|
45 |
--shadow: rgba(0,0,0,.35);
|
46 |
|
47 |
-
--line: rgba(201,190,170,.18);
|
48 |
--perforation: #d0c6b7;
|
49 |
|
50 |
-
--
|
51 |
-
|
52 |
-
|
53 |
-
--
|
54 |
-
--
|
55 |
-
--
|
56 |
-
|
57 |
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
--desk-bg: #2c2a27;
|
60 |
--desk-dot: #3a3733;
|
61 |
|
@@ -63,15 +49,22 @@ body.dark {
|
|
63 |
--paper-text: #e9e7e2;
|
64 |
--shadow: rgba(0,0,0,.55);
|
65 |
|
66 |
-
--line: rgba(110,103,94,.28);
|
67 |
--perforation: #6d6456;
|
68 |
|
69 |
-
--
|
70 |
-
|
71 |
-
--
|
72 |
-
--
|
73 |
-
--
|
74 |
-
--
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
}
|
76 |
|
77 |
/* ─────────────────────────────────────────
|
@@ -85,17 +78,16 @@ body{
|
|
85 |
background-size:14px 14px;
|
86 |
font-family:'Crimson Text','Times New Roman',serif;
|
87 |
color:var(--paper-text);
|
88 |
-
line-height:1.8;
|
89 |
-webkit-font-smoothing:antialiased;
|
90 |
}
|
91 |
|
92 |
/* ─────────────────────────────────────────
|
93 |
-
PAPER
|
94 |
───────────────────────────────────────── */
|
95 |
.container{
|
96 |
-
max-width:
|
97 |
margin:40px auto;
|
98 |
-
padding:40px
|
99 |
background:var(--paper-bg);
|
100 |
color:var(--paper-text);
|
101 |
border:1px solid rgba(0,0,0,.05);
|
@@ -103,7 +95,6 @@ body{
|
|
103 |
position:relative;
|
104 |
box-shadow:0 18px 40px -22px var(--shadow),
|
105 |
inset 0 2px 6px rgba(0,0,0,.06);
|
106 |
-
background-size:160px 160px,100% 100%;
|
107 |
}
|
108 |
|
109 |
/* perforation holes */
|
@@ -121,77 +112,113 @@ body{
|
|
121 |
background:
|
122 |
linear-gradient(135deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,0) 42%),
|
123 |
linear-gradient(135deg,var(--paper-bg) 0%,var(--paper-bg) 50%,rgba(255,255,255,0) 51%);
|
124 |
-
background-size:100% 100%;
|
125 |
border-bottom-left-radius:12px;
|
126 |
-
transform:translate(1px,-1px);
|
127 |
pointer-events:none;
|
128 |
}
|
129 |
|
130 |
-
/*
|
131 |
-
|
132 |
-
/* ───────── theme toggle ───────── */
|
133 |
#themeToggle{
|
134 |
-
position:absolute;top:12px;right:14px;
|
135 |
font-size:20px;background:none;border:none;cursor:pointer;
|
136 |
transition:transform .25s;
|
137 |
user-select:none;
|
138 |
}
|
139 |
-
|
140 |
-
/* put this anywhere after the existing #themeToggle rule */
|
141 |
-
#themeToggle{
|
142 |
-
position:absolute; /* you already have this */
|
143 |
-
z-index:10; /* NEW – lift it above the curl */
|
144 |
-
}
|
145 |
-
|
146 |
-
|
147 |
#themeToggle:hover{transform:rotate(20deg)scale(1.15)}
|
148 |
|
149 |
-
/*
|
150 |
-
.header{text-align:center;margin-bottom:
|
151 |
-
h1{font-family:'Libre Baskerville',serif;margin:0;font-size:
|
152 |
.subtitle{font-family:'PT Mono',monospace;font-size:14px;color:#666;margin-top:6px;letter-spacing:1px}
|
153 |
|
154 |
-
/*
|
155 |
-
#
|
156 |
-
min-height:520px;
|
157 |
-
|
|
|
|
|
|
|
|
|
|
|
158 |
}
|
159 |
-
#
|
160 |
-
content:'';
|
|
|
161 |
background:repeating-linear-gradient(
|
162 |
0deg,
|
163 |
-
transparent,transparent 2.
|
164 |
-
var(--line) 2.
|
165 |
-
pointer-events:none;z-index:1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
166 |
}
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
}
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
/* lists */
|
182 |
-
ol{counter-reset:item;padding-left:0;list-style:none}
|
183 |
-
ol>li{counter-increment:item;margin:.5em 0 .5em 2em}
|
184 |
-
ol>li::before{content:counter(item)')';display:inline-block;width:1.5em;margin-left:-2em;text-align:right;font-weight:600}
|
185 |
-
ol ol>li::before{content:counter(item,lower-alpha)')'}
|
186 |
-
|
187 |
-
/* ───────── TABLES ───────── */
|
188 |
-
table{width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums;margin:1.2em 0}
|
189 |
-
thead tr{border-bottom:1px solid var(--tbl-border)}
|
190 |
-
tbody tr:not(:last-child){border-bottom:1px solid var(--tbl-border)}
|
191 |
-
th,td{padding:.55em .8em;text-align:right}
|
192 |
-
th{font-weight:600}
|
193 |
-
|
194 |
-
/* ───────── processing badge ───────── */
|
195 |
.processing{
|
196 |
position:fixed;top:20px;right:20px;background:#333;color:#fff;
|
197 |
padding:10px 20px;border-radius:6px;font-family:'PT Mono',monospace;
|
@@ -199,11 +226,14 @@ th{font-weight:600}
|
|
199 |
}
|
200 |
.processing.show{opacity:.9}
|
201 |
|
|
|
|
|
|
|
202 |
/* responsive & print */
|
203 |
@media(max-width:768px){
|
204 |
-
.container{margin:20px 16px;padding:
|
205 |
-
#content{font-size:16px}
|
206 |
h1{font-size:24px}
|
|
|
207 |
}
|
208 |
@media print{
|
209 |
body{background:#fff}
|
@@ -219,100 +249,177 @@ th{font-weight:600}
|
|
219 |
<button id="themeToggle" title="Toggle dark / light">🌙</button>
|
220 |
|
221 |
<div class="header">
|
222 |
-
<h1>
|
223 |
-
<div class="subtitle">press ctrl+v anywhere to
|
224 |
</div>
|
225 |
|
226 |
-
<div id="
|
227 |
<div class="placeholder">
|
228 |
-
Press <kbd>Ctrl</kbd>+<kbd>V</kbd> (or <kbd>⌘</kbd>+<kbd>V</kbd>) to paste
|
|
|
229 |
</div>
|
230 |
</div>
|
231 |
|
232 |
-
<div class="instructions"
|
233 |
-
Tip:
|
234 |
</div>
|
235 |
</div>
|
236 |
|
237 |
<div class="processing">Processing…</div>
|
238 |
|
239 |
<script>
|
240 |
-
/* =======
|
241 |
-
const
|
242 |
const processingNode = document.querySelector('.processing');
|
|
|
243 |
|
244 |
-
|
245 |
-
function hideProcessing(){setTimeout(()=>processingNode.classList.remove('show'),300)}
|
246 |
|
247 |
-
|
248 |
-
function
|
249 |
-
showProcessing();
|
250 |
|
251 |
-
|
252 |
-
const
|
|
|
|
|
253 |
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
|
|
|
|
|
|
|
|
259 |
|
260 |
-
|
261 |
-
|
262 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
268 |
}
|
269 |
|
270 |
/* ======= paste listener ======= */
|
271 |
-
document.addEventListener('paste',e=>{
|
272 |
-
e.
|
273 |
-
|
274 |
-
if(txt.trim())processContent(txt);
|
275 |
});
|
276 |
|
277 |
-
/*
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
ph.style.transform='scale(.97)';
|
282 |
-
ph.style.transition='transform .12s';
|
283 |
-
setTimeout(()=>ph.style.transform='scale(1)',120);
|
284 |
-
}
|
285 |
});
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
|
|
|
|
292 |
});
|
293 |
|
294 |
/* ======= theme toggler ======= */
|
295 |
-
const btn = document.getElementById('themeToggle');
|
296 |
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
|
297 |
const savedTheme = localStorage.getItem('note-theme');
|
298 |
|
299 |
initTheme();
|
300 |
-
|
301 |
document.body.classList.toggle('dark');
|
302 |
updateIcon();
|
303 |
-
localStorage.setItem('note-theme',document.body.classList.contains('dark')?'dark':'light');
|
304 |
});
|
305 |
function initTheme(){
|
306 |
if(savedTheme){
|
307 |
-
document.body.classList.toggle('dark',savedTheme==='dark');
|
308 |
}else if(prefersDark.matches){
|
309 |
document.body.classList.add('dark');
|
310 |
}
|
311 |
updateIcon();
|
312 |
}
|
313 |
function updateIcon(){
|
314 |
-
|
315 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
316 |
</script>
|
317 |
</body>
|
318 |
</html>
|
|
|
3 |
<head>
|
4 |
<meta charset="UTF-8" />
|
5 |
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
6 |
+
<title>Question Sticky Board</title>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
<!-- Google fonts -->
|
9 |
<link
|
|
|
15 |
/* ─────────────────────────────────────────
|
16 |
COLOR SYSTEM (light / dark via variables)
|
17 |
───────────────────────────────────────── */
|
18 |
+
:root{
|
19 |
--desk-bg: #fbf9f5;
|
20 |
--desk-dot: #e2dccd;
|
21 |
|
|
|
23 |
--paper-text: #222;
|
24 |
--shadow: rgba(0,0,0,.35);
|
25 |
|
|
|
26 |
--perforation: #d0c6b7;
|
27 |
|
28 |
+
--board-line: rgba(201,190,170,.18);
|
29 |
+
|
30 |
+
/* sticky colors */
|
31 |
+
--note-yellow: #fff6a8;
|
32 |
+
--note-mint: #d8f7e6;
|
33 |
+
--note-blush: #ffe3e0;
|
34 |
+
--note-blue: #e6f0ff;
|
35 |
|
36 |
+
--note-border: rgba(0,0,0,.08);
|
37 |
+
--note-bar: rgba(0,0,0,.04);
|
38 |
+
--note-text: #2b2b2b;
|
39 |
+
|
40 |
+
--btn-fg: #444;
|
41 |
+
--btn-fg-dim: #666;
|
42 |
+
--btn-bg-hover: rgba(0,0,0,.08);
|
43 |
+
}
|
44 |
+
body.dark{
|
45 |
--desk-bg: #2c2a27;
|
46 |
--desk-dot: #3a3733;
|
47 |
|
|
|
49 |
--paper-text: #e9e7e2;
|
50 |
--shadow: rgba(0,0,0,.55);
|
51 |
|
|
|
52 |
--perforation: #6d6456;
|
53 |
|
54 |
+
--board-line: rgba(110,103,94,.28);
|
55 |
+
|
56 |
+
--note-yellow: #6b6434;
|
57 |
+
--note-mint: #3f5a50;
|
58 |
+
--note-blush: #5b3f3c;
|
59 |
+
--note-blue: #3e4c63;
|
60 |
+
|
61 |
+
--note-border: rgba(0,0,0,.25);
|
62 |
+
--note-bar: rgba(255,255,255,.05);
|
63 |
+
--note-text: #f1efe9;
|
64 |
+
|
65 |
+
--btn-fg: #ddd;
|
66 |
+
--btn-fg-dim: #aaa;
|
67 |
+
--btn-bg-hover: rgba(255,255,255,.1);
|
68 |
}
|
69 |
|
70 |
/* ─────────────────────────────────────────
|
|
|
78 |
background-size:14px 14px;
|
79 |
font-family:'Crimson Text','Times New Roman',serif;
|
80 |
color:var(--paper-text);
|
|
|
81 |
-webkit-font-smoothing:antialiased;
|
82 |
}
|
83 |
|
84 |
/* ─────────────────────────────────────────
|
85 |
+
PAPER CONTAINER
|
86 |
───────────────────────────────────────── */
|
87 |
.container{
|
88 |
+
max-width:1100px;
|
89 |
margin:40px auto;
|
90 |
+
padding:34px 34px 40px 50px;
|
91 |
background:var(--paper-bg);
|
92 |
color:var(--paper-text);
|
93 |
border:1px solid rgba(0,0,0,.05);
|
|
|
95 |
position:relative;
|
96 |
box-shadow:0 18px 40px -22px var(--shadow),
|
97 |
inset 0 2px 6px rgba(0,0,0,.06);
|
|
|
98 |
}
|
99 |
|
100 |
/* perforation holes */
|
|
|
112 |
background:
|
113 |
linear-gradient(135deg,rgba(0,0,0,.08) 0%,rgba(0,0,0,0) 42%),
|
114 |
linear-gradient(135deg,var(--paper-bg) 0%,var(--paper-bg) 50%,rgba(255,255,255,0) 51%);
|
|
|
115 |
border-bottom-left-radius:12px;
|
|
|
116 |
pointer-events:none;
|
117 |
}
|
118 |
|
119 |
+
/* theme toggle */
|
|
|
|
|
120 |
#themeToggle{
|
121 |
+
position:absolute;top:12px;right:14px;z-index:10;
|
122 |
font-size:20px;background:none;border:none;cursor:pointer;
|
123 |
transition:transform .25s;
|
124 |
user-select:none;
|
125 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
#themeToggle:hover{transform:rotate(20deg)scale(1.15)}
|
127 |
|
128 |
+
/* header */
|
129 |
+
.header{text-align:center;margin-bottom:18px;padding-bottom:14px;border-bottom:1px solid rgba(0,0,0,.05)}
|
130 |
+
h1{font-family:'Libre Baskerville',serif;margin:0;font-size:28px;letter-spacing:.4px}
|
131 |
.subtitle{font-family:'PT Mono',monospace;font-size:14px;color:#666;margin-top:6px;letter-spacing:1px}
|
132 |
|
133 |
+
/* board */
|
134 |
+
#board{
|
135 |
+
min-height:520px;
|
136 |
+
position:relative;
|
137 |
+
padding:18px 6px 10px 6px;
|
138 |
+
display:grid;
|
139 |
+
grid-template-columns:repeat(auto-fill,minmax(220px,1fr));
|
140 |
+
gap:16px;
|
141 |
+
overflow:visible;
|
142 |
}
|
143 |
+
#board::before{
|
144 |
+
content:'';
|
145 |
+
position:absolute;inset:0 6px;
|
146 |
background:repeating-linear-gradient(
|
147 |
0deg,
|
148 |
+
transparent,transparent 2.8em,
|
149 |
+
var(--board-line) 2.8em,var(--board-line) 2.85em);
|
150 |
+
pointer-events:none;z-index:1;border-radius:8px;
|
151 |
+
}
|
152 |
+
#board > *{position:relative;z-index:2}
|
153 |
+
|
154 |
+
/* placeholder */
|
155 |
+
.placeholder{
|
156 |
+
color:#888;font-style:italic;text-align:center;
|
157 |
+
padding:120px 20px;user-select:none;grid-column:1/-1
|
158 |
+
}
|
159 |
+
|
160 |
+
/* sticky notes */
|
161 |
+
.sticky{
|
162 |
+
position:relative;
|
163 |
+
border:1px solid var(--note-border);
|
164 |
+
border-radius:10px;
|
165 |
+
color:var(--note-text);
|
166 |
+
box-shadow:
|
167 |
+
0 10px 26px -16px var(--shadow),
|
168 |
+
inset 0 1px 0 rgba(255,255,255,.35);
|
169 |
+
transform:rotate(var(--tilt,0deg)) scale(1);
|
170 |
+
transition:transform .12s ease, box-shadow .12s ease, opacity .16s ease;
|
171 |
+
animation:pop .18s ease-out;
|
172 |
}
|
173 |
+
.sticky:hover{
|
174 |
+
transform:rotate(var(--tilt,0deg)) translateY(-2px) scale(1.01);
|
175 |
+
box-shadow:
|
176 |
+
0 14px 32px -18px var(--shadow),
|
177 |
+
inset 0 1px 0 rgba(255,255,255,.45);
|
178 |
+
}
|
179 |
+
@keyframes pop{from{transform:scale(.96);opacity:0}to{transform:scale(1);opacity:1}}
|
180 |
+
|
181 |
+
.sticky.note-yellow{background:linear-gradient(180deg,var(--note-yellow),color-mix(in oklab,var(--note-yellow) 85%, #000 15%))}
|
182 |
+
.sticky.note-mint {background:linear-gradient(180deg,var(--note-mint), color-mix(in oklab,var(--note-mint) 85%, #000 15%))}
|
183 |
+
.sticky.note-blush {background:linear-gradient(180deg,var(--note-blush), color-mix(in oklab,var(--note-blush) 85%, #000 15%))}
|
184 |
+
.sticky.note-blue {background:linear-gradient(180deg,var(--note-blue), color-mix(in oklab,var(--note-blue) 85%, #000 15%))}
|
185 |
+
|
186 |
+
.sticky .bar{
|
187 |
+
display:flex;align-items:center;justify-content:space-between;
|
188 |
+
padding:6px 8px 4px 10px;
|
189 |
+
background:var(--note-bar);
|
190 |
+
border-top-left-radius:10px;border-top-right-radius:10px;
|
191 |
+
font-family:'PT Mono',monospace;
|
192 |
+
font-size:12px;letter-spacing:.3px
|
193 |
+
}
|
194 |
+
.badge{
|
195 |
+
background:rgba(0,0,0,.08);
|
196 |
+
padding:2px 6px;border-radius:999px;font-weight:600;
|
197 |
+
}
|
198 |
+
body.dark .badge{background:rgba(255,255,255,.12)}
|
199 |
+
|
200 |
+
.sticky img{
|
201 |
+
width:100%;height:auto;display:block;
|
202 |
+
border-bottom-left-radius:10px;border-bottom-right-radius:10px;
|
203 |
+
background:
|
204 |
+
linear-gradient(180deg,rgba(255,255,255,.25),rgba(255,255,255,0));
|
205 |
+
}
|
206 |
+
|
207 |
+
/* delete button */
|
208 |
+
.btn-del{
|
209 |
+
position:absolute;top:6px;right:6px;
|
210 |
+
width:26px;height:26px;border-radius:50%;
|
211 |
+
border:1px solid var(--note-border);
|
212 |
+
background:rgba(255,255,255,.35);
|
213 |
+
color:var(--btn-fg);font-weight:700;line-height:24px;text-align:center;
|
214 |
+
cursor:pointer;backdrop-filter:saturate(120%) blur(2px);
|
215 |
+
display:flex;align-items:center;justify-content:center;
|
216 |
+
opacity:.85;transition:background .12s, transform .12s, opacity .12s;
|
217 |
}
|
218 |
+
.btn-del:hover{background:var(--btn-bg-hover);transform:scale(1.06);opacity:1}
|
219 |
+
.btn-del:active{transform:scale(.96)}
|
220 |
+
|
221 |
+
/* processing badge */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
222 |
.processing{
|
223 |
position:fixed;top:20px;right:20px;background:#333;color:#fff;
|
224 |
padding:10px 20px;border-radius:6px;font-family:'PT Mono',monospace;
|
|
|
226 |
}
|
227 |
.processing.show{opacity:.9}
|
228 |
|
229 |
+
/* instructions */
|
230 |
+
.instructions{ text-align:center;font-family:'PT Mono',monospace;font-size:14px;color:#666;font-style:italic;margin-top:16px }
|
231 |
+
|
232 |
/* responsive & print */
|
233 |
@media(max-width:768px){
|
234 |
+
.container{margin:20px 16px;padding:24px}
|
|
|
235 |
h1{font-size:24px}
|
236 |
+
#board{grid-template-columns:repeat(auto-fill,minmax(180px,1fr))}
|
237 |
}
|
238 |
@media print{
|
239 |
body{background:#fff}
|
|
|
249 |
<button id="themeToggle" title="Toggle dark / light">🌙</button>
|
250 |
|
251 |
<div class="header">
|
252 |
+
<h1>Question Sticky Board</h1>
|
253 |
+
<div class="subtitle">press ctrl+v anywhere to paste images of questions</div>
|
254 |
</div>
|
255 |
|
256 |
+
<div id="board">
|
257 |
<div class="placeholder">
|
258 |
+
Press <kbd>Ctrl</kbd>+<kbd>V</kbd> (or <kbd>⌘</kbd>+<kbd>V</kbd>) to paste screenshots/images.<br/>
|
259 |
+
You can also drag & drop images here.
|
260 |
</div>
|
261 |
</div>
|
262 |
|
263 |
+
<div class="instructions">
|
264 |
+
Tip: each image becomes a sticky. Click the tiny × to delete.
|
265 |
</div>
|
266 |
</div>
|
267 |
|
268 |
<div class="processing">Processing…</div>
|
269 |
|
270 |
<script>
|
271 |
+
/* ======= helpers ======= */
|
272 |
+
const board = document.getElementById('board');
|
273 |
const processingNode = document.querySelector('.processing');
|
274 |
+
const themeBtn = document.getElementById('themeToggle');
|
275 |
|
276 |
+
let noteCount = 0;
|
|
|
277 |
|
278 |
+
function showProcessing(){ processingNode.classList.add('show') }
|
279 |
+
function hideProcessing(){ setTimeout(()=>processingNode.classList.remove('show'),250) }
|
|
|
280 |
|
281 |
+
function removePlaceholder(){
|
282 |
+
const ph = board.querySelector('.placeholder');
|
283 |
+
if(ph) ph.remove();
|
284 |
+
}
|
285 |
|
286 |
+
function randTilt(){
|
287 |
+
// small friendly tilt between -2.2deg and 2.2deg
|
288 |
+
const d = (Math.random()*4.4 - 2.2).toFixed(2);
|
289 |
+
return d + 'deg';
|
290 |
+
}
|
291 |
+
function pickColorClass(){
|
292 |
+
const choices = ['note-yellow','note-mint','note-blush','note-blue'];
|
293 |
+
return choices[Math.floor(Math.random()*choices.length)];
|
294 |
+
}
|
295 |
|
296 |
+
/* ======= create sticky from an image URL ======= */
|
297 |
+
function createSticky(src, isBlobUrl=false){
|
298 |
+
removePlaceholder();
|
299 |
+
noteCount++;
|
300 |
+
|
301 |
+
const wrap = document.createElement('div');
|
302 |
+
const colorClass = pickColorClass();
|
303 |
+
wrap.className = `sticky ${colorClass}`;
|
304 |
+
wrap.style.setProperty('--tilt', randTilt());
|
305 |
+
|
306 |
+
// header bar
|
307 |
+
const bar = document.createElement('div');
|
308 |
+
bar.className = 'bar';
|
309 |
+
bar.innerHTML = `<span class="badge">Q${noteCount}</span><span style="opacity:.7">pasted</span>`;
|
310 |
+
|
311 |
+
// image
|
312 |
+
const img = document.createElement('img');
|
313 |
+
img.alt = `Question ${noteCount}`;
|
314 |
+
img.src = src;
|
315 |
+
|
316 |
+
// delete button
|
317 |
+
const btn = document.createElement('button');
|
318 |
+
btn.className = 'btn-del';
|
319 |
+
btn.setAttribute('aria-label','Delete sticky');
|
320 |
+
btn.textContent = '×';
|
321 |
+
|
322 |
+
btn.addEventListener('click',()=>{
|
323 |
+
wrap.style.opacity = '0';
|
324 |
+
wrap.style.transform = 'scale(.96)';
|
325 |
+
setTimeout(()=>{
|
326 |
+
// release blob URL to avoid memory leaks
|
327 |
+
if(isBlobUrl) URL.revokeObjectURL(src);
|
328 |
+
wrap.remove();
|
329 |
+
if(!board.querySelector('.sticky')){
|
330 |
+
// restore placeholder if empty
|
331 |
+
const ph = document.createElement('div');
|
332 |
+
ph.className = 'placeholder';
|
333 |
+
ph.innerHTML = `Press <kbd>Ctrl</kbd>+<kbd>V</kbd> (or <kbd>⌘</kbd>+<kbd>V</kbd>) to paste screenshots/images.<br/>You can also drag & drop images here.`;
|
334 |
+
board.appendChild(ph);
|
335 |
+
}
|
336 |
+
},140);
|
337 |
+
});
|
338 |
+
|
339 |
+
wrap.appendChild(bar);
|
340 |
+
wrap.appendChild(img);
|
341 |
+
wrap.appendChild(btn);
|
342 |
+
board.prepend(wrap); // newest on top
|
343 |
+
}
|
344 |
|
345 |
+
/* ======= handle pasted images ======= */
|
346 |
+
function filesFromClipboard(dataTransfer){
|
347 |
+
const items = dataTransfer?.items || [];
|
348 |
+
const files = [];
|
349 |
+
for(const it of items){
|
350 |
+
if(it.kind === 'file' && it.type.startsWith('image/')){
|
351 |
+
const f = it.getAsFile();
|
352 |
+
if(f) files.push(f);
|
353 |
+
}
|
354 |
+
}
|
355 |
+
return files;
|
356 |
+
}
|
357 |
+
|
358 |
+
async function handleImages(files){
|
359 |
+
if(!files.length){
|
360 |
+
// no images, brief nudge
|
361 |
+
processingNode.textContent = 'No images found in clipboard';
|
362 |
+
showProcessing(); hideProcessing();
|
363 |
+
processingNode.textContent = 'Processing…';
|
364 |
+
return;
|
365 |
+
}
|
366 |
+
showProcessing();
|
367 |
+
for(const file of files){
|
368 |
+
const url = URL.createObjectURL(file);
|
369 |
+
createSticky(url, true);
|
370 |
+
}
|
371 |
+
hideProcessing();
|
372 |
}
|
373 |
|
374 |
/* ======= paste listener ======= */
|
375 |
+
document.addEventListener('paste', e=>{
|
376 |
+
const files = filesFromClipboard(e.clipboardData);
|
377 |
+
if(files.length){ e.preventDefault(); handleImages(files); }
|
|
|
378 |
});
|
379 |
|
380 |
+
/* ======= drag & drop (optional bonus) ======= */
|
381 |
+
board.addEventListener('dragover', e=>{
|
382 |
+
e.preventDefault();
|
383 |
+
board.style.outline = '2px dashed rgba(0,0,0,.2)';
|
|
|
|
|
|
|
|
|
384 |
});
|
385 |
+
board.addEventListener('dragleave', ()=>{
|
386 |
+
board.style.outline = 'none';
|
387 |
+
});
|
388 |
+
board.addEventListener('drop', e=>{
|
389 |
+
e.preventDefault();
|
390 |
+
board.style.outline = 'none';
|
391 |
+
const dtFiles = [...(e.dataTransfer?.files || [])].filter(f=>f.type.startsWith('image/'));
|
392 |
+
handleImages(dtFiles);
|
393 |
});
|
394 |
|
395 |
/* ======= theme toggler ======= */
|
|
|
396 |
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
|
397 |
const savedTheme = localStorage.getItem('note-theme');
|
398 |
|
399 |
initTheme();
|
400 |
+
themeBtn.addEventListener('click',()=>{
|
401 |
document.body.classList.toggle('dark');
|
402 |
updateIcon();
|
403 |
+
localStorage.setItem('note-theme', document.body.classList.contains('dark') ? 'dark' : 'light');
|
404 |
});
|
405 |
function initTheme(){
|
406 |
if(savedTheme){
|
407 |
+
document.body.classList.toggle('dark', savedTheme==='dark');
|
408 |
}else if(prefersDark.matches){
|
409 |
document.body.classList.add('dark');
|
410 |
}
|
411 |
updateIcon();
|
412 |
}
|
413 |
function updateIcon(){
|
414 |
+
themeBtn.textContent = document.body.classList.contains('dark') ? '☀️' : '🌙';
|
415 |
}
|
416 |
+
|
417 |
+
/* ======= smooth fade in ======= */
|
418 |
+
document.addEventListener('DOMContentLoaded',()=>{
|
419 |
+
const sheet=document.querySelector('.container');
|
420 |
+
sheet.style.opacity='0';
|
421 |
+
setTimeout(()=>{sheet.style.transition='opacity .6s ease';sheet.style.opacity='1'},80);
|
422 |
+
});
|
423 |
</script>
|
424 |
</body>
|
425 |
</html>
|