@atom.io/template-react-realtime-text-editor 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@atom.io/template-react-realtime-text-editor",
3
+ "version": "0.0.1",
4
+ "description": "A realtime text editor built with atom.io, React, and Lasertag.",
5
+ "license": "Apache-2.0",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/jeremybanka/atom.io.git",
12
+ "directory": "templates/react-realtime-text-editor"
13
+ },
14
+ "type": "module",
15
+ "engines": {
16
+ "node": ">=24.12.0"
17
+ },
18
+ "scripts": {
19
+ "dev": "concurrently vite \"node --watch node/server.ts\"",
20
+ "build": "tsc -b && vite build",
21
+ "lint": "npm run lint:eslint && npm run lint:lasertag && npm run lint:types",
22
+ "lint:eslint": "eslint .",
23
+ "lint:lasertag": "lasertag check \"src/**/*.module.css\"",
24
+ "lint:types": "tsc -b",
25
+ "preview": "concurrently \"vite preview\" \"node node/server.ts\"",
26
+ "test": "vitest run",
27
+ "test:once": "vitest run"
28
+ },
29
+ "dependencies": {
30
+ "atom.io": "workspace:*",
31
+ "react": "19.2.8",
32
+ "react-dom": "19.2.8",
33
+ "socket.io": "4.8.3",
34
+ "socket.io-client": "4.8.3",
35
+ "zod": "4.4.3"
36
+ },
37
+ "devDependencies": {
38
+ "@testing-library/dom": "10.4.1",
39
+ "@testing-library/react": "16.3.2",
40
+ "@types/node": "26.2.0",
41
+ "@types/react": "19.2.18",
42
+ "@types/react-dom": "19.2.4",
43
+ "@typescript-eslint/parser": "8.67.0",
44
+ "@vitejs/plugin-react": "6.0.5",
45
+ "concurrently": "10.0.4",
46
+ "eslint": "10.8.1",
47
+ "happy-dom": "20.11.2",
48
+ "lasertag": "0.7.0",
49
+ "typescript": "7.0.2",
50
+ "vite": "8.2.1",
51
+ "vitest": "4.1.10"
52
+ }
53
+ }
@@ -0,0 +1,539 @@
1
+ markdown-workspace.class {
2
+ --accent: #6d50ea;
3
+ --border: #dfdce8;
4
+ --ink: #292936;
5
+ --muted: #817e90;
6
+ --paper: #fffefa;
7
+ --panel: #faf9fc;
8
+ display: grid;
9
+ grid-template-rows: auto minmax(0, 1fr) auto;
10
+ min-height: 100svh;
11
+ background:
12
+ radial-gradient(circle at 80% 0%, #eee9ff 0, transparent 28rem),
13
+ #f3f2f7;
14
+
15
+ > header {
16
+ display: grid;
17
+ grid-template-columns:
18
+ minmax(11rem, 1fr) minmax(15rem, 1.5fr) minmax(18rem, 1fr);
19
+ align-items: center;
20
+ gap: 1.25rem;
21
+ z-index: 3;
22
+ min-height: 5.4rem;
23
+ padding: 0.75rem 1.5rem;
24
+ border-bottom: 1px solid #e5e2ec;
25
+ background: color-mix(in srgb, #fbfaff 90%, transparent);
26
+ box-shadow: 0 0.25rem 1.8rem #3023510a;
27
+ backdrop-filter: blur(1.5rem);
28
+
29
+ > brand-lockup {
30
+ display: flex;
31
+ align-items: center;
32
+ gap: 0.75rem;
33
+
34
+ > mark {
35
+ display: grid;
36
+ place-items: center;
37
+ width: 2.65rem;
38
+ aspect-ratio: 1;
39
+ border-radius: 0.9rem;
40
+ color: white;
41
+ background: linear-gradient(145deg, #8c70ff, #5f3edf);
42
+ box-shadow: 0 0.5rem 1rem #6749dc38;
43
+ font-family: "Newsreader", serif;
44
+ font-size: 1.45rem;
45
+ font-weight: 650;
46
+ }
47
+
48
+ > label-set {
49
+ display: flex;
50
+ flex-flow: column;
51
+ line-height: 1.15;
52
+
53
+ > strong {
54
+ font-family: "Newsreader", serif;
55
+ font-size: 1.35rem;
56
+ letter-spacing: -0.02em;
57
+ }
58
+
59
+ > span {
60
+ margin-top: 0.2rem;
61
+ color: var(--muted);
62
+ font-size: 0.67rem;
63
+ font-weight: 700;
64
+ letter-spacing: 0.08em;
65
+ text-transform: uppercase;
66
+ }
67
+ }
68
+ }
69
+
70
+ > document-title {
71
+ display: flex;
72
+ min-width: 0;
73
+ flex-flow: column;
74
+ align-items: center;
75
+
76
+ > strong {
77
+ max-width: 100%;
78
+ color: var(--ink);
79
+ font-family: "Newsreader", serif;
80
+ font-size: 1.2rem;
81
+ font-weight: 650;
82
+ text-align: center;
83
+ }
84
+
85
+ > span {
86
+ margin-top: 0.16rem;
87
+ color: var(--muted);
88
+ font-size: 0.69rem;
89
+ }
90
+ }
91
+
92
+ > toolbar-actions {
93
+ display: flex;
94
+ align-items: center;
95
+ justify-content: flex-end;
96
+ gap: 0.45rem;
97
+
98
+ > button {
99
+ display: inline-flex;
100
+ align-items: center;
101
+ gap: 0.35rem;
102
+ min-height: 2.25rem;
103
+ padding: 0.4rem 0.68rem;
104
+ border: 1px solid var(--border);
105
+ border-radius: 0.65rem;
106
+ color: #565363;
107
+ background: white;
108
+ font-size: 0.73rem;
109
+ font-weight: 700;
110
+
111
+ &:hover:not(:disabled) {
112
+ border-color: #bdb4df;
113
+ color: var(--accent);
114
+ background: #f8f6ff;
115
+ }
116
+
117
+ &:disabled {
118
+ opacity: 0.42;
119
+ }
120
+ }
121
+
122
+ > label {
123
+ display: flex;
124
+ align-items: center;
125
+ gap: 0.45rem;
126
+ min-height: 2.25rem;
127
+ padding: 0.27rem 0.35rem;
128
+ border: 1px solid var(--border);
129
+ border-radius: 99rem;
130
+ background: white;
131
+
132
+ > avatar-dot {
133
+ display: grid;
134
+ place-items: center;
135
+ width: 1.65rem;
136
+ aspect-ratio: 1;
137
+ border-radius: 50%;
138
+ color: white;
139
+ background: var(--person-color);
140
+ font-size: 0.7rem;
141
+ font-weight: 800;
142
+ }
143
+
144
+ > select {
145
+ max-width: 8rem;
146
+ border: 0;
147
+ outline: 0;
148
+ color: #4a4755;
149
+ background: transparent;
150
+ font-size: 0.72rem;
151
+ font-weight: 700;
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ > main {
158
+ display: grid;
159
+ grid-template-columns: minmax(21rem, 0.95fr) minmax(24rem, 1.05fr) 15rem;
160
+ min-height: 0;
161
+ padding: 1.15rem;
162
+ gap: 1rem;
163
+
164
+ > editor-pane,
165
+ > preview-pane,
166
+ > presence-rail {
167
+ min-width: 0;
168
+ min-height: 0;
169
+ border: 1px solid var(--border);
170
+ border-radius: 1.1rem;
171
+ background: var(--paper);
172
+ box-shadow: 0 0.9rem 2.4rem #2b21450c;
173
+ }
174
+
175
+ > editor-pane,
176
+ > preview-pane {
177
+ display: grid;
178
+ grid-template-rows: auto minmax(0, 1fr);
179
+ overflow: hidden;
180
+
181
+ > pane-heading {
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: space-between;
185
+ min-height: 3.15rem;
186
+ padding: 0.75rem 1rem;
187
+ border-bottom: 1px solid #ebe8ef;
188
+ background: #fcfbfd;
189
+
190
+ > span {
191
+ color: var(--muted);
192
+ font-size: 0.68rem;
193
+ }
194
+ }
195
+ }
196
+
197
+ > editor-pane {
198
+ > pane-heading {
199
+ > label {
200
+ font-size: 0.75rem;
201
+ font-weight: 800;
202
+ letter-spacing: 0.055em;
203
+ text-transform: uppercase;
204
+ }
205
+ }
206
+
207
+ > editor-surface {
208
+ position: relative;
209
+ min-height: 0;
210
+ background:
211
+ linear-gradient(90deg, #f8f6fb 2.75rem, transparent 2.75rem),
212
+ var(--panel);
213
+
214
+ > textarea {
215
+ position: absolute;
216
+ inset: 0;
217
+ z-index: 1;
218
+ width: 100%;
219
+ height: 100%;
220
+ resize: none;
221
+ padding: 1.45rem 1.45rem 8rem 3.7rem;
222
+ border: 0;
223
+ outline: 0;
224
+ color: #383542;
225
+ background: transparent;
226
+ caret-color: var(--accent);
227
+ font-family: "DM Mono", monospace;
228
+ font-size: 0.83rem;
229
+ line-height: 1.72rem;
230
+ tab-size: 2;
231
+
232
+ &:disabled {
233
+ opacity: 0.58;
234
+ }
235
+ }
236
+
237
+ > caret-layer {
238
+ position: absolute;
239
+ inset: 0;
240
+ z-index: 2;
241
+ overflow: hidden;
242
+ pointer-events: none;
243
+
244
+ > remote-caret {
245
+ position: absolute;
246
+ top: calc(1.45rem + var(--caret-line) * 1.72rem);
247
+ left: calc(3.7rem + var(--caret-column) * 0.5rem);
248
+ width: 2px;
249
+ height: 1.25rem;
250
+ background: var(--person-color);
251
+
252
+ > span {
253
+ position: absolute;
254
+ top: -1.05rem;
255
+ left: 0;
256
+ padding: 0.14rem 0.35rem;
257
+ border-radius: 0.3rem 0.3rem 0.3rem 0;
258
+ color: white;
259
+ background: var(--person-color);
260
+ font-size: 0.56rem;
261
+ font-weight: 800;
262
+ white-space: nowrap;
263
+ }
264
+ }
265
+ }
266
+ }
267
+ }
268
+
269
+ > preview-pane {
270
+ > pane-heading {
271
+ > strong {
272
+ font-size: 0.75rem;
273
+ font-weight: 800;
274
+ letter-spacing: 0.055em;
275
+ text-transform: uppercase;
276
+ }
277
+ }
278
+
279
+ > article {
280
+ overflow: auto;
281
+ padding: clamp(1.6rem, 4vw, 4rem);
282
+ color: #37333d;
283
+ font-family: "Newsreader", Georgia, serif;
284
+ font-size: 1.05rem;
285
+ line-height: 1.72;
286
+
287
+ > h1,
288
+ > h2,
289
+ > h3,
290
+ > h4,
291
+ > h5,
292
+ > h6 {
293
+ margin: 1.8em 0 0.55em;
294
+ color: #282430;
295
+ font-weight: 650;
296
+ letter-spacing: -0.025em;
297
+ line-height: 1.1;
298
+ }
299
+
300
+ > h1:first-child {
301
+ margin-top: 0;
302
+ font-size: clamp(2.15rem, 5vw, 3.5rem);
303
+ }
304
+
305
+ > h2 {
306
+ font-size: 1.55rem;
307
+ }
308
+
309
+ > p,
310
+ > ul,
311
+ > ol,
312
+ > blockquote,
313
+ > pre {
314
+ margin: 0 0 1.25rem;
315
+ }
316
+
317
+ > ul,
318
+ > ol {
319
+ padding-left: 1.35rem;
320
+ }
321
+
322
+ > blockquote {
323
+ padding: 0.75rem 1.1rem;
324
+ border-left: 3px solid #b5a5f6;
325
+ color: #5d566b;
326
+ background: #f7f4ff;
327
+ font-style: italic;
328
+ }
329
+
330
+ > pre {
331
+ overflow: auto;
332
+ padding: 1rem 1.15rem;
333
+ border: 1px solid #e2deea;
334
+ border-radius: 0.7rem;
335
+ color: #ede9ff;
336
+ background: #302c3a;
337
+ font-family: "DM Mono", monospace;
338
+ font-size: 0.76rem;
339
+ line-height: 1.65;
340
+ }
341
+
342
+ strong {
343
+ color: #332d42;
344
+ font-weight: 650;
345
+ }
346
+
347
+ code:not(pre code) {
348
+ padding: 0.15em 0.35em;
349
+ border-radius: 0.25rem;
350
+ color: #6547d6;
351
+ background: #f0ecff;
352
+ font-family: "DM Mono", monospace;
353
+ font-size: 0.8em;
354
+ }
355
+
356
+ a {
357
+ color: #6547d6;
358
+ text-decoration-color: #b9abf2;
359
+ text-underline-offset: 0.15em;
360
+ }
361
+ }
362
+ }
363
+
364
+ > presence-rail {
365
+ display: flex;
366
+ flex-flow: column;
367
+ overflow: auto;
368
+ padding: 1.15rem;
369
+
370
+ > strong {
371
+ font-size: 0.72rem;
372
+ font-weight: 800;
373
+ letter-spacing: 0.055em;
374
+ text-transform: uppercase;
375
+ }
376
+
377
+ > ul {
378
+ display: flex;
379
+ flex-flow: column;
380
+ gap: 0.85rem;
381
+ margin: 1.1rem 0 0;
382
+ padding: 0;
383
+ list-style: none;
384
+
385
+ > li {
386
+ display: grid;
387
+ grid-template-columns: auto minmax(0, 1fr);
388
+ align-items: center;
389
+ gap: 0.65rem;
390
+
391
+ > avatar-dot {
392
+ display: grid;
393
+ place-items: center;
394
+ width: 2rem;
395
+ aspect-ratio: 1;
396
+ border: 2px solid white;
397
+ border-radius: 50%;
398
+ color: white;
399
+ background: var(--person-color);
400
+ box-shadow: 0 0 0 1px var(--person-color);
401
+ font-size: 0.72rem;
402
+ font-weight: 800;
403
+ }
404
+
405
+ > person-label {
406
+ display: flex;
407
+ min-width: 0;
408
+ flex-flow: column;
409
+
410
+ > strong {
411
+ overflow: hidden;
412
+ font-size: 0.76rem;
413
+ text-overflow: ellipsis;
414
+ white-space: nowrap;
415
+ }
416
+
417
+ > span {
418
+ margin-top: 0.12rem;
419
+ color: var(--muted);
420
+ font-size: 0.62rem;
421
+ }
422
+ }
423
+ }
424
+ }
425
+
426
+ > aside {
427
+ margin-top: auto;
428
+ padding: 0.9rem;
429
+ border: 1px solid #e3dcff;
430
+ border-radius: 0.8rem;
431
+ background: linear-gradient(145deg, #f9f7ff, #f1edff);
432
+
433
+ > strong {
434
+ color: #5941b4;
435
+ font-size: 0.7rem;
436
+ }
437
+
438
+ > p {
439
+ margin: 0.4rem 0 0;
440
+ color: #6d6680;
441
+ font-size: 0.65rem;
442
+ line-height: 1.55;
443
+ }
444
+ }
445
+ }
446
+ }
447
+
448
+ > footer {
449
+ display: flex;
450
+ align-items: center;
451
+ gap: 0.45rem;
452
+ min-height: 2.6rem;
453
+ padding: 0.55rem 1.5rem;
454
+ border-top: 1px solid #e2dfe8;
455
+ color: var(--muted);
456
+ background: #faf9fc;
457
+ font-size: 0.66rem;
458
+
459
+ > span {
460
+ width: 0.48rem;
461
+ aspect-ratio: 1;
462
+ border-radius: 50%;
463
+ background: #aaa5b3;
464
+
465
+ &[data-status="live"] {
466
+ background: #21a879;
467
+ box-shadow: 0 0 0 0.22rem #21a8791c;
468
+ }
469
+
470
+ &[data-status="offline"] {
471
+ background: #df8c35;
472
+ }
473
+ }
474
+
475
+ > strong {
476
+ color: #5f5b69;
477
+ font-weight: 700;
478
+ }
479
+
480
+ > small {
481
+ margin-left: auto;
482
+ }
483
+
484
+ > output {
485
+ color: #a5435e;
486
+ }
487
+ }
488
+
489
+ @media (max-width: 1080px) {
490
+ > header {
491
+ grid-template-columns: 1fr 1fr;
492
+
493
+ > document-title {
494
+ display: none;
495
+ }
496
+ }
497
+
498
+ > main {
499
+ grid-template-columns: minmax(20rem, 1fr) minmax(22rem, 1fr);
500
+
501
+ > presence-rail {
502
+ display: none;
503
+ }
504
+ }
505
+ }
506
+
507
+ @media (max-width: 720px) {
508
+ > header {
509
+ grid-template-columns: 1fr auto;
510
+ padding-inline: 0.85rem;
511
+
512
+ > toolbar-actions {
513
+ > button {
514
+ > span {
515
+ display: none;
516
+ }
517
+ }
518
+
519
+ > label {
520
+ > select {
521
+ display: none;
522
+ }
523
+ }
524
+ }
525
+ }
526
+
527
+ > main {
528
+ display: flex;
529
+ min-height: auto;
530
+ flex-flow: column;
531
+ padding: 0.7rem;
532
+
533
+ > editor-pane,
534
+ > preview-pane {
535
+ min-height: 62svh;
536
+ }
537
+ }
538
+ }
539
+ }