a demonstration replicated social networking web app built with anproto
wiredove.net/
social
ed25519
protocols
1body {
2 background-color: #f2f2f2;
3 color: #444;
4 font-family: "Source Sans 3", sans-serif;
5 max-width: 100%;
6 margin-top: 45px;
7 margin-bottom: 10em;
8}
9
10.profile-header {
11 background-position: center;
12 background-size: cover;
13 background-repeat: no-repeat;
14}
15
16.profile-header-layout {
17 display: grid;
18 grid-template-columns: 150px 1fr;
19 gap: 16px;
20 align-items: start;
21}
22
23.profile-header-layout h2 {
24 margin-top: 0;
25}
26
27.profile-avatar {
28 margin: 0;
29 border-radius: 50%;
30}
31
32.profile-bio p {
33 margin-bottom: 0;
34}
35
36.profile-bio-status {
37 color: #777;
38 font-size: 0.9em;
39 margin-top: 6px;
40}
41
42.profile-view-only {
43 display: block;
44}
45
46.profile-edit-only {
47 display: none;
48}
49
50.profile-editing .profile-view-only {
51 display: none;
52}
53
54.profile-editing .profile-edit-only {
55 display: block;
56}
57
58@media (max-width: 640px) {
59 .profile-header-layout {
60 grid-template-columns: 1fr;
61 text-align: center;
62 }
63
64 .profile-avatar {
65 margin: 0 auto;
66 }
67}
68
69#scroller {max-width: 680px; margin-left: auto; margin-right: auto;}
70
71blockquote { border-left: 5px solid #f5f5f5; margin-left: none; padding-left: 10px; color: #777; }
72
73p, h1, h2, h3, h4, h5, h6 { margin-top: 0; margin-bottom: 5px;}
74
75pre {
76 //color: #dd1144;
77 background: #f5f5f5;
78 width: 100%;
79 display: block;
80}
81
82code {
83 background: #f5f5f5;
84 padding: 5px;
85 border-radius: 5px;
86 display: inline-block;
87 vertical-align: bottom;
88}
89
90code, pre {
91 font-family: "Roboto Mono", monospace;
92 font-size: .9em;
93 overflow: auto;
94 word-break: break-all;
95 word-wrap: break-word;
96 white-space: pre;
97 white-space: -moz-pre-wrap;
98 white-space: pre-wrap;
99 white-space: pre\9;
100}
101
102button {
103 margin-left: 5px;
104 font-size: .85em;
105 background: #fff;
106 background-image: linear-gradient(to bottom, #ffffff, #f2f2f2);
107 border: 1px solid #e4e4e4;
108 padding: 5px 10px 5px 10px;
109 border-radius: 5px;
110}
111
112hr { border: 1px solid #e4e4e4;}
113
114button:hover {
115 background: #f2f2f2;
116 cursor: pointer;
117}
118
119.composer-toggle {
120 display: inline-flex;
121 gap: 2px;
122 margin-bottom: 6px;
123 background: #f0f0f0;
124 border: 1px solid #e4e4e4;
125 border-radius: 999px;
126 padding: 2px;
127 position: relative;
128 overflow: hidden;
129}
130
131.composer-toggle button {
132 border-radius: 999px;
133 padding: 4px 10px;
134 border: none;
135 background: transparent;
136 position: relative;
137 z-index: 1;
138}
139
140.composer-toggle button.active {
141 font-weight: 600;
142}
143
144.composer-toggle-indicator {
145 position: absolute;
146 top: 2px;
147 bottom: 2px;
148 left: 2px;
149 width: calc(50% - 2px);
150 border-radius: 999px;
151 background: #fff;
152 border: 1px solid #e4e4e4;
153 transition: transform 180ms ease;
154 pointer-events: none;
155}
156
157.composer-toggle.event-active .composer-toggle-indicator {
158 transform: translateX(100%);
159}
160
161textarea, input, select {
162 font-size: 1em;
163 font-family: "Source Sans 3", sans-serif;
164 border: 1px solid #f8f8f8;
165 border-radius: 5px;
166 background: #f8f8f8;
167 color: #555;
168 padding: 5px;
169 //box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
170}
171
172.composer { margin-left: 0; margin-top: 0;}
173
174textarea:hover, textarea:focus, input:hover, input:focus, select:hover, select:focus, {
175 background: transparent;
176}
177
178textarea:focus, input:focus, select:focus {
179 outline: none !important;
180}
181
182textarea {
183 margin-top: 5px;
184 margin-bottom: 5px;
185 width: 99%;
186 height: 150px;
187}
188
189.composer-header {
190 display: flex;
191 align-items: center;
192 gap: 8px;
193 flex-wrap: wrap;
194}
195
196.event-preview {
197 border: 1px solid #e4e4e4;
198 border-radius: 6px;
199 padding: 8px 10px;
200 margin-bottom: 8px;
201 background: #fafafa;
202}
203
204.event-preview-title {
205 font-weight: 600;
206 margin-bottom: 2px;
207}
208
209.event-preview-meta {
210 color: #777;
211 font-size: 0.95em;
212}
213
214.event-location-wrapper {
215 position: relative;
216}
217
218.event-location-wrapper input {
219 width: 100%;
220}
221
222.event-time-row {
223 display: flex;
224 gap: 6px;
225 flex-wrap: wrap;
226}
227
228.event-time-row select {
229 min-width: 120px;
230}
231
232.event-location-results {
233 position: absolute;
234 z-index: 5;
235 top: calc(100% + 4px);
236 left: 0;
237 right: 0;
238 display: none;
239 flex-direction: column;
240 gap: 2px;
241 padding: 4px;
242 border: 1px solid #e4e4e4;
243 background: #fff;
244 border-radius: 6px;
245 box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
246}
247
248.event-location-option {
249 text-align: left;
250 padding: 6px 8px;
251 border-radius: 4px;
252 cursor: pointer;
253}
254
255.event-location-option:hover,
256.event-location-option.active {
257 background: #f2f2f2;
258}
259
260.event-location-status {
261 font-size: 0.9em;
262 color: #2a6a2a;
263}
264
265.event-location-status.error {
266 color: #b00020;
267}
268
269.preview-controls {
270 display: flex;
271 align-items: center;
272 gap: 8px;
273 margin-top: 8px;
274}
275
276a {
277 color: #045fd0;
278 text-decoration: none;
279}
280
281a:hover {
282 color: #8d82fe;
283}
284
285img {width: 95%;}
286
287img.post-image {
288 width: 150px;
289 height: 150px;
290 object-fit: cover;
291 border-radius: 6px;
292 cursor: zoom-in;
293 display: block;
294 margin: 0;
295}
296
297.post-image-row {
298 display: flex;
299 flex-wrap: wrap;
300 gap: 8px;
301 margin: 6px 0 8px 0;
302}
303
304img.post-image.profile-avatar {
305 border-radius: 50%;
306}
307
308
309img.post-image:focus {
310 outline: 2px solid #045fd0;
311 outline-offset: 2px;
312}
313
314.material-symbols-outlined { color: #666; vertical-align: middle; font-size: 18px; cursor: pointer;}
315
316iframe {
317 width: 100%;
318 border: 1px solid #e4e4e4;
319 border-radius: 5px;
320 margin-top: 5px;
321 height: 275px;
322}
323
324#navbar {
325 padding-top: .5em;
326 padding-left: 1em;
327 padding-bottom: .5em;
328 padding-right: 1em;
329 position: fixed;
330 width: 100%;
331 box-sizing: border-box;
332 z-index: 1;
333 top: 0;
334 left: 0;
335 background-color: rgba(248,248,248,0.5);
336 border-bottom: 1px solid #eee;
337 backdrop-filter: blur(10px);
338 display: flex;
339 align-items: center;
340 gap: 6px;
341 flex-wrap: nowrap;
342}
343
344.navbar-left,
345.navbar-right {
346 display: inline-flex;
347 align-items: center;
348 gap: 6px;
349}
350
351.navbar-right {
352 margin-left: auto;
353}
354
355.publish-wrap {
356 position: relative;
357 display: inline-flex;
358 align-items: center;
359 width: 10px;
360 flex: 0 0 auto;
361}
362
363.publish-state {
364 width: 10px;
365 height: 10px;
366 border-radius: 999px;
367 border: 1px solid #c7c7c7;
368 background: #d8d8d8;
369 display: inline-block;
370 white-space: nowrap;
371 padding: 0;
372 flex: 0 0 auto;
373}
374
375.publish-desc {
376 position: absolute;
377 right: 16px;
378 top: 50%;
379 transform: translateY(-50%);
380 font-size: 12px;
381 color: #666;
382 min-width: 0;
383 max-width: min(380px, 55vw);
384 white-space: nowrap;
385 overflow: hidden;
386 text-overflow: ellipsis;
387 pointer-events: none;
388 text-align: right;
389}
390
391.publish-state.is-pending {
392 border-color: #c4a353;
393 background: #f2c94c;
394}
395
396.publish-state.is-ok {
397 border-color: #6bb77d;
398 background: #3cb371;
399}
400
401.publish-state.is-fail {
402 border-color: #d98b8b;
403 background: #d9534f;
404}
405
406.message {
407 padding: .75em;
408 background: #f8f8f8;
409 border: 1px solid #f5f5f5;
410 margin-top: 5px;
411 min-height: 35px;
412 border-radius: 5px;
413 overflow: hidden;
414 position: relative;
415}
416
417.message.edit-message {
418 padding: .75em .75em 0 .75em;
419}
420
421.message-main {
422 display: flex;
423 align-items: flex-start;
424 gap: 10px;
425}
426
427.message-main > a {
428 display: inline-flex;
429 align-items: center;
430}
431
432.message-main .avatar {
433 float: none;
434}
435
436.message-stack {
437 display: flex;
438 flex-direction: column;
439 gap: 2px;
440 min-width: 0;
441 flex: 1;
442}
443
444.message-stack .avatarlink {
445 line-height: 33px;
446 display: inline-block;
447}
448
449.message-body {
450 flex: 1;
451 min-width: 0;
452}
453
454.message-meta {
455 position: absolute;
456 top: .75em;
457 right: .75em;
458 display: inline-flex;
459 align-items: center;
460 gap: .35em;
461}
462
463.premessage {
464 min-height: 35px;
465}
466
467.message:hover {
468 border: 1px solid #eee;
469}
470
471.new-posts-banner {
472 position: sticky;
473 top: 52px;
474 z-index: 2;
475 display: flex;
476 justify-content: center;
477 padding: 6px 0;
478}
479
480.new-posts-button {
481 background: #fff5cc;
482 border: 1px solid #f2d675;
483 color: #6a4c00;
484}
485
486@media (prefers-color-scheme: dark) {
487 body {
488 background-color: #181818;
489 color: #ccc;
490 }
491 #navbar { background-color: rgba(34,34,34,0.5); border-bottom: 1px solid #333; }
492 .publish-state { border-color: #4a4a4a; background: #5a5a5a; }
493 .publish-state.is-pending { border-color: #8a7337; background: #f2c94c; }
494 .publish-state.is-ok { border-color: #3f8050; background: #3cb371; }
495 .publish-state.is-fail { border-color: #8c4a4a; background: #d9534f; }
496 .publish-desc { color: #bcbcbc; }
497 .message { background-color: #222; border: 1px solid #1e1e1e;}
498 .message:hover { border: 1px solid #333;}
499 .new-posts-button { background: #3a2f12; border: 1px solid #6b5320; color: #f5d27a; }
500
501 textarea, input, select, iframe { background: #222; color: #f5f5f5; border: 1px solid #222;}
502
503 button { color: #ccc; background: #333; border: 1px solid #444;}
504 button:hover { background: #222;}
505 hr { border: 1px solid #333;}
506 pre, code { background: #333; color: #f5f5f5;}
507 a {color: #50afe4;}
508
509 .composer-toggle {
510 background: #2a2a2a;
511 border-color: #333;
512 }
513
514 .composer-toggle-indicator {
515 background: #3a3a3a;
516 border-color: #4a4a4a;
517 }
518
519 .event-preview {
520 background: #1f1f1f;
521 border-color: #2a2a2a;
522 }
523
524 .event-preview-meta {
525 color: #a5a5a5;
526 }
527
528 .event-location-status {
529 color: #7bc27b;
530 }
531
532 .event-location-status.error {
533 color: #f28b82;
534 }
535
536 .event-location-results {
537 background: #1f1f1f;
538 border-color: #333;
539 box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);
540 }
541
542 .event-location-option {
543 color: #f5f5f5;
544 }
545
546 .event-location-option:hover,
547 .event-location-option.active {
548 background: #2b2b2b;
549 }
550
551}
552
553@media (max-width: 640px) {
554 #navbar {
555 padding-right: 1em;
556 gap: 4px;
557 flex-wrap: wrap;
558 }
559 .navbar-left,
560 .navbar-right {
561 gap: 4px;
562 }
563}
564
565
566.content {margin-top: 5px;}
567
568.message, .message > * {
569 animation: fadein .5s;
570}
571
572@keyframes fadein {
573 from { opacity: 0; }
574 to { opacity: 1; }
575}
576
577.reply { margin-left: 1em; }
578
579.reply-preview {
580 display: inline-flex;
581 align-items: center;
582 gap: 6px;
583 margin-right: 6px;
584}
585
586.reply-preview-icon {
587 font-size: 1em;
588}
589
590.reply-preview-author {
591 font-weight: 600;
592}
593
594.reply-preview-link {
595 font-weight: 500;
596}
597
598.pubkey {
599 color: #9da0a4;
600 font-family: monospace;
601}
602
603.edit-nav {
604 font-family: monospace;
605 font-size: 1em;
606}
607
608.edit-nav-btn {
609 color: #777;
610 margin: 0 2px;
611 cursor: pointer;
612}
613
614.edit-nav-btn.disabled {
615 color: #bbb;
616 cursor: default;
617 pointer-events: none;
618}
619
620.edit-nav-index {
621 color: #888;
622 margin: 0 2px;
623}
624
625.message-actions {
626 margin-top: 6px;
627 display: flex;
628 align-items: center;
629 gap: 6px;
630 width: 100%;
631}
632
633.message-actions-reply {
634}
635
636.message-actions-edit {
637 margin-left: auto;
638 display: inline-flex;
639 align-items: center;
640 gap: 4px;
641 justify-content: flex-end;
642}
643
644.message-actions-mod {
645 display: inline-flex;
646 align-items: center;
647 gap: 4px;
648}
649
650.edit-hint {
651 font-family: monospace;
652}
653
654.keypair-notice {
655 position: fixed;
656 top: 64px;
657 left: 50%;
658 transform: translateX(-50%);
659 z-index: 2000;
660 margin: 0;
661 padding: 8px 12px;
662 max-width: min(520px, 90vw);
663 background: #f8f8f8;
664 border: 1px solid #f5f5f5;
665 border-left: 4px solid #ff8c00;
666 border-radius: 6px;
667 color: inherit;
668 font-weight: 600;
669 display: none;
670 box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
671}
672
673.keypair-notice.show {
674 display: block;
675}
676
677.keypair-highlight {
678 box-shadow: 0 0 0 3px rgba(255, 140, 0, 0.6);
679 border-color: #ff8c00;
680}
681
682.disabled {
683 opacity: 0.5;
684 pointer-events: auto;
685}
686
687.moderation-panel {
688 margin-top: 6px;
689}
690
691.moderation-note {
692 color: #777;
693 font-size: 0.9em;
694}
695
696.moderation-section {
697 margin-top: 10px;
698}
699
700.moderation-section-title {
701 font-weight: 600;
702 margin-bottom: 6px;
703}
704
705.moderation-row {
706 display: flex;
707 align-items: center;
708 gap: 6px;
709 flex-wrap: wrap;
710}
711
712.moderation-row .moderation-input {
713 flex: 1 1 220px;
714 min-width: 160px;
715}
716
717.moderation-tags {
718 margin-top: 6px;
719 display: flex;
720 align-items: center;
721 gap: 6px;
722 flex-wrap: wrap;
723}
724
725.moderation-tag {
726 display: inline-flex;
727 align-items: center;
728 gap: 6px;
729 padding: 2px 6px;
730 border-radius: 12px;
731 background: #f0f0f0;
732 border: 1px solid #e4e4e4;
733 font-size: 0.9em;
734}
735
736.moderation-tag-remove {
737 padding: 0 6px;
738 line-height: 1.2;
739}
740
741.moderation-actions {
742 margin-top: 6px;
743 display: flex;
744 align-items: center;
745 gap: 6px;
746 flex-wrap: wrap;
747}
748
749.message.moderation-hidden {
750 background: #f7f5f5;
751 border: 1px dashed #e4e4e4;
752 color: #666;
753}
754
755.moderation-hidden-title {
756 font-weight: 600;
757}
758
759.moderation-hidden-actions {
760 display: inline-flex;
761 align-items: center;
762 gap: 6px;
763 margin-left: 8px;
764}
765
766@media (prefers-color-scheme: dark) {
767 .message.moderation-hidden {
768 background: #1d1f21;
769 border-color: #2b2d30;
770 color: #c8c9cc;
771 }
772
773 .moderation-note {
774 color: #a5a7ab;
775 }
776
777 .moderation-tag {
778 background: #242629;
779 border-color: #2f3236;
780 color: #c8c9cc;
781 }
782}
783
784@media (prefers-color-scheme: dark) {
785 .keypair-notice {
786 background: #222;
787 border: 1px solid #1e1e1e;
788 border-left: 4px solid #ff8c00;
789 color: #ccc;
790 }
791}
792
793.edit-summary {
794 display: inline-flex;
795 align-items: center;
796 line-height: 33px;
797 min-height: 33px;
798 gap: 4px;
799}
800
801.edit-summary-verb {
802 font-weight: 400;
803}
804
805
806.avatar, .avatar_small {
807 border-radius: 100%;
808 margin: 0px;
809 margin-right: 0px;
810 object-fit: cover;
811 vertical-align: top;
812 display: block;
813}
814
815.avatar {
816 height: 35px;
817 width: 35px;
818}
819
820.avatar_small { height: 25px; width: 25px;}
821
822.breadcrumbs { font-size: 1em; }
823
824.avatarlink { font-weight: 600;}
825.unstyled { color: #ccc;}
826.hljs { padding: 10px; border-radius: 5px; background: #555; color: #f2f2f2;}
827
828.modal-overlay {
829 position: fixed;
830 top: 0;
831 left: 0;
832 width: 100%;
833 height: 100%;
834 background: rgba(0, 0, 0, 0.5);
835 backdrop-filter: blur(5px);
836 z-index: 1000;
837 display: flex;
838 justify-content: center;
839 align-items: center;
840}
841
842.modal-content {
843 width: 90%;
844 max-width: 600px;
845 z-index: 1001;
846}
847
848.image-popover {
849 position: fixed;
850 inset: 0;
851 display: none;
852 align-items: center;
853 justify-content: center;
854 background: rgba(0, 0, 0, 0.6);
855 backdrop-filter: blur(4px);
856 z-index: 1100;
857 padding: 20px;
858 box-sizing: border-box;
859}
860
861.image-popover.open {
862 display: flex;
863}
864
865.image-popover-frame {
866 position: relative;
867 display: inline-flex;
868 align-items: center;
869 justify-content: center;
870 max-width: 90vw;
871 max-height: 90vh;
872}
873
874.image-popover-close {
875 position: absolute;
876 top: 8px;
877 right: 8px;
878 border: 0;
879 background: transparent;
880 border-radius: 999px;
881 width: 36px;
882 height: 36px;
883 display: inline-flex;
884 align-items: center;
885 justify-content: center;
886}
887
888.image-popover-close:hover {
889 background: rgba(255, 255, 255, 0.25);
890}
891
892.image-popover-image {
893 width: auto;
894 height: auto;
895 max-width: 90vw;
896 max-height: 90vh;
897 object-fit: contain;
898 border-radius: 6px;
899 box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
900 background: #fff;
901}
902
903@media (prefers-color-scheme: dark) {
904 .image-popover-close {
905 background: transparent;
906 color: #ddd;
907 }
908
909 .image-popover-close:hover {
910 background: rgba(0, 0, 0, 0.35);
911 }
912
913 .image-popover-image {
914 background: #222;
915 }
916}