summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-09-18 10:04:43 +0700
committerpolwex <polwex@sortug.com>2025-09-18 10:04:43 +0700
commite69afcff1c1f42436998ca0b070162d556dd577c (patch)
treeceaf1e3c7f654902eb3029483a4a2af37591c320
parent7bac4927e8895719a91011da9a2b997579238145 (diff)
-rw-r--r--NOTES.md5
-rw-r--r--desk/app/nostrill.hoon101
-rw-r--r--desk/lib/mutations/nostr.hoon (renamed from desk/lib/nostrill/mutations.hoon)31
-rw-r--r--desk/lib/mutations/trill.hoon78
-rw-r--r--desk/lib/nostr/events.hoon49
-rw-r--r--desk/lib/nostr/keys.hoon (renamed from desk/lib/nostr.hoon)0
-rw-r--r--desk/lib/nostrill.hoon54
-rw-r--r--desk/lib/nostrill/comms.hoon4
-rw-r--r--desk/lib/nostrill/follows.hoon7
-rw-r--r--desk/lib/scri.hoon9
-rw-r--r--desk/lib/shim.hoon6
-rw-r--r--desk/sur/nostrill/comms.hoon21
-rw-r--r--front/src/styles/ThemeProvider.tsx144
-rw-r--r--front/src/styles/styles.css15
14 files changed, 381 insertions, 143 deletions
diff --git a/NOTES.md b/NOTES.md
index 79406c2..cfca357 100644
--- a/NOTES.md
+++ b/NOTES.md
@@ -45,3 +45,8 @@ lol forget the frontend make it work for Primal
- ~It appears relays ignore you if you pass more than 11 authors on a filter~
- Turns out the pubkeys were wrong because we were not padding the hex strings to 64 chars. fixed now
- Relay send a notice if too many concurrent REQs
+
+# Hard stuff
+
+It's hard to sync with the Nostr relays. We can fetch a bunch of posts and that's fine but then we want to fetch other data related to those posts, say the authors metadata or reactions or whatever. So we do it in bulk, but when? Nostr data keeps trickling in if we're subscribed through the shim.
+
diff --git a/desk/app/nostrill.hoon b/desk/app/nostrill.hoon
index 721a590..ddbcd61 100644
--- a/desk/app/nostrill.hoon
+++ b/desk/app/nostrill.hoon
@@ -1,7 +1,11 @@
-/- sur=nostrill, nsur=nostr, tf=trill-feed
-/+ lib=nostrill, nlib=nostr, sr=sortug, scri,
- shim, dbug, muta=nostrill-mutations, jsonlib=json-nostrill,
- trill=trill-post, comms=nostrill-comms, followlib=nostrill-follows
+/- sur=nostrill, nsur=nostr, tf=trill-feed, comms=nostrill-comms
+/+ lib=nostrill, nostr-keys, sr=sortug, scri,
+ shim, dbug,
+ evlib=nostr-events,
+ mutations-nostr,
+ mutations-trill,
+ jsonlib=json-nostrill,
+ trill=trill-post, commlib=nostrill-comms, followlib=nostrill-follows
/= web /web/router
|%
+$ versioned-state $%(state-0:sur)
@@ -14,10 +18,11 @@
+* this .
rout ~(. router:web [state bowl])
cards ~(. cards:lib bowl)
- mutat ~(. muta [state bowl])
+ mutan ~(. mutations-nostr [state bowl])
+ mutat ~(. mutations-trill [state bowl])
shimm ~(. shim [state bowl])
scry ~(. scri [state bowl])
- coms ~(. comms [state bowl])
+ coms ~(. commlib [state bowl])
fols ~(. followlib [state bowl])
++ on-init
^- (quip card:agent:gall agent:gall)
@@ -65,7 +70,7 @@
?~ msg `this
?> ?=(%ws -.u.msg)
:: =^ cards state (handle-shim-msg:mutat u.msg)
- =^ cards state (handle-ws:mutat +.u.msg)
+ =^ cards state (handle-ws:mutan +.u.msg)
[cards this]
::
@@ -82,63 +87,19 @@
%fols (handle-fols +.u.upoke)
%begs (handle-begs +.u.upoke)
%prof (handle-prof +.u.upoke)
- %post (handle-post +.u.upoke)
%rela (handle-rela +.u.upoke)
+ %post =^ cs state
+ (handle-post:mutat +.u.upoke)
+ [cs this]
==
++ handle-cycle-keys
- =/ ks (gen-keys:nlib eny.bowl)
+ =/ ks (gen-keys:nostr-keys eny.bowl)
=. keys [ks keys]
:: =/ nkeys keys(i ks, t `(list keys:nsur)`keys)
:: :: =. keys nkeys
~& new-keys=keys
`this
- ++ handle-post |= poke=post-poke:ui:sur
- ?- -.poke
- %add
- =/ sp (build-sp:trill our.bowl our.bowl content.poke ~ ~)
- =/ p (build-post:trill now.bowl pub.i.keys sp)
- =. state (add-to-feed:mutat p)
- =/ profile (~(get by profiles) [%urbit our.bowl])
- =/ pw [p (some pub.i.keys) ~ ~ profile]
- =/ =fact:ui:sur [%post %add pw]
- =/ card (update-ui:cards fact)
- :_ this :~(card)
- %quote
- =/ sp (build-sp:trill our.bowl our.bowl content.poke ~ ~)
- =/ quote [%ref %trill host.poke /(crip (scow:sr %ud id.poke))]
- =. contents.sp (snoc contents.sp quote)
- =/ p (build-post:trill now.bowl pub.i.keys sp)
- =. state (add-to-feed:mutat p)
- =/ profile (~(get by profiles) [%urbit our.bowl])
- =/ pw [p (some pub.i.keys) ~ ~ profile]
- =/ =fact:ui:sur [%post %add pw]
- =/ card (update-ui:cards fact)
- :_ this :~(card)
- %reply
- =/ sp (build-sp:trill host.poke our.bowl content.poke `id.poke `thread.poke)
- =/ p (build-post:trill now.bowl pub.i.keys sp)
- =. state (add-to-feed:mutat p)
- =/ profile (~(get by profiles) [%urbit our.bowl])
- =/ pw [p (some pub.i.keys) ~ ~ profile]
- =/ =fact:ui:sur [%post %add pw]
- =/ card (update-ui:cards fact)
- :_ this :~(card)
- %rp
- =/ quote [%ref %trill host.poke /(crip (scow:sr %ud id.poke))]
- =/ sp (build-sp:trill host.poke our.bowl '' ~ ~)
- =. contents.sp ~[quote]
- =/ p (build-post:trill now.bowl pub.i.keys sp)
- =. state (add-to-feed:mutat p)
- =/ profile (~(get by profiles) [%urbit our.bowl])
- =/ pw [p (some pub.i.keys) ~ ~ profile]
- =/ =fact:ui:sur [%post %add pw]
- =/ card (update-ui:cards fact)
- :_ this :~(card)
-
- :: %rt `this
- :: %del `this
- ==
++ handle-begs |= poke=begs-poke:ui:sur
?- -.poke
%feed
@@ -177,9 +138,9 @@
[cs this]
::
%send
- =/ upoast (get-poast:mutat host.poke id.poke)
+ =/ upoast (get-poast:scry host.poke id.poke)
?~ upoast `this
- =/ event (post-to-event:lib i.keys eny.bowl u.upoast)
+ =/ event (post-to-event:evlib i.keys eny.bowl u.upoast)
=/ req=bulk-req:shim:nsur [relays.poke %event event]
=/ cards :~((send:shimm req))
[cards this]
@@ -194,7 +155,7 @@
=/ l ~| "wtf" (need lol)
`this
%genkey
- =/ keys (gen-keys:nlib eny.bowl)
+ =/ keys (gen-keys:nostr-keys eny.bowl)
~& pub=(scow:sr %ux -.keys)
~& priv=(scow:sr %ux +.keys)
`this
@@ -229,7 +190,7 @@
- (~(put in -.acc) id.ev)
+ (~(put in +.acc) pubkey.ev)
==
- =^ cards state (populate-profiles:mutat -.ids)
+ =^ cards state (populate-profiles:mutan -.ids)
:: (get-profiles:shimm +.ids)
:: (get-engagement:shimm -.ids)
[cards this]
@@ -254,7 +215,7 @@
~& >>> invalid=invalid
`this
=/ p=event:nsur +.i.poasts
- =/ valid (validate-pubkey:nlib pubkey.p)
+ =/ valid (validate-pubkey:nostr-keys pubkey.p)
?. valid
=/ ids (crip (scow:sr %ux id.p))
~& ids
@@ -270,7 +231,7 @@
=/ npks (~(put in pubkeys) pubkey.p)
$(poasts t.poasts, pubkeys npks)
::
- =^ cards state (populate-profiles:mutat pks)
+ =^ cards state (populate-profiles:mutan pks)
[cards this]
%ui
=/ =fact:ui:sur [%post %add *post-wrapper:sur]
@@ -326,16 +287,22 @@
~& on-agent=[wire -.sign]
:: if p.sign is not ~ here that means it's intentional
?+ wire `this
- [%refollow ~]
- ?. ?=(%watch-ack -.sign) `this
- ?~ p.sign `this
- =^ cs state (handle-kick-nack:fols src.bowl) [cs this]
[%follow ~]
+ ?: ?=(%watch-ack -.sign)
+ ?~ p.sign `this
+ =^ cs state (handle-kick-nack:fols src.bowl) [cs this]
?: ?=(%kick -.sign)
=^ cs state (handle-refollow:fols src.bowl)
[cs this]
?. ?=(%fact -.sign) `this
- =^ cs state (handle-agent-res:fols q.q.cage.sign)
+
+ =/ =fact:comms ;; fact:comms q.q.cage.sign
+ =^ cs state
+ ?- -.fact
+ %init (handle-follow-res:fols +.fact)
+ %post (handle-post-fact:mutat +.fact)
+ %prof (handle-prof-fact:mutan +.fact)
+ ==
[cs this]
==
@@ -351,7 +318,7 @@
=/ msg (parse-body:shimm jstring)
?~ msg ~& `@t`jstring `this
?> ?=(%http -.u.msg)
- =^ cards state (handle-http:mutat sub-id.wire +.u.msg)
+ =^ cards state (handle-http:mutan sub-id.wire +.u.msg)
`this
==
::
diff --git a/desk/lib/nostrill/mutations.hoon b/desk/lib/mutations/nostr.hoon
index 8fca2b2..2c6acd5 100644
--- a/desk/lib/nostrill/mutations.hoon
+++ b/desk/lib/mutations/nostr.hoon
@@ -1,4 +1,4 @@
-/- sur=nostrill, nsur=nostr,
+/- sur=nostrill, nsur=nostr, comms=nostrill-comms,
post=trill-post, gate=trill-gate, feed=trill-feed
/+ appjs=json-nostrill,
@@ -10,24 +10,6 @@
|_ [=state:sur =bowl:gall]
+$ card card:agent:gall
-++ debug-own-feed
- =/ postlist (tap:orm:feed feed.state)
- =/ lol
- |- ?~ postlist ~
- ~& >> poast=+.i.postlist
- $(postlist t.postlist)
- ~
-:: TODO not a mutation but fuck it
-++ get-poast |= [host=@p id=@] ^- (unit post:post)
- =/ poast ?: .=(host our.bowl)
- (get:orm:feed feed.state id)
- ~
- poast
-
-:: state
-++ add-to-feed |= p=post:post
- =. feed.state (put:orm:feed feed.state id.p p)
- state
:: events
++ process-events ^- (quip card _state)
:: =/ l events.state
@@ -247,4 +229,15 @@
=. relays.state (~(put by relays.state) relay u.rs)
`state
--
+
+++ handle-prof-fact |= pf=prof-fact:comms
+ ^- (quip card _state)
+ =/ =user:sur [%urbit src.bowl]
+ ?- -.pf
+ %prof =. profiles.state (~(put by profiles.state) user +.pf)
+ :: TODO kinda wanna send it to the UI
+ `state
+ %keys `state
+ :: TODO really need a way to keep track of everyone's pubkeys
+ ==
--
diff --git a/desk/lib/mutations/trill.hoon b/desk/lib/mutations/trill.hoon
new file mode 100644
index 0000000..ea6dadf
--- /dev/null
+++ b/desk/lib/mutations/trill.hoon
@@ -0,0 +1,78 @@
+/- sur=nostrill, nsur=nostr, comms=nostrill-comms,
+ post=trill-post, gate=trill-gate, feed=trill-feed
+
+/+ appjs=json-nostrill,
+ lib=nostrill,
+ trill=trill-post,
+ njs=json-nostr,
+ postlib=trill-post,
+ shim,
+ sr=sortug
+
+|_ [=state:sur =bowl:gall]
++$ card card:agent:gall
+++ debug-own-feed
+ =/ postlist (tap:orm:feed feed.state)
+ =/ lol
+ |- ?~ postlist ~
+ ~& >> poast=+.i.postlist
+ $(postlist t.postlist)
+ ~
+
+:: state
+++ add-to-feed |= p=post:post
+ =. feed.state (put:orm:feed feed.state id.p p)
+ state
+
+++ handle-post |= poke=post-poke:ui:sur
+ ^- (quip card _state)
+ =/ profile (~(get by profiles.state) [%urbit our.bowl])
+ =/ pubkey pub.i.keys.state
+ =/ p=post:post
+ ?- -.poke
+ %add
+ =/ sp (build-sp:trill our.bowl our.bowl content.poke ~ ~)
+ (build-post:trill now.bowl pubkey sp)
+ %quote
+ =/ sp (build-sp:trill our.bowl our.bowl content.poke ~ ~)
+ =/ quote [%ref %trill host.poke /(crip (scow:sr %ud id.poke))]
+ =. contents.sp (snoc contents.sp quote)
+ (build-post:trill now.bowl pubkey sp)
+ %reply
+ =/ sp (build-sp:trill host.poke our.bowl content.poke `id.poke `thread.poke)
+ (build-post:trill now.bowl pubkey sp)
+ %rp
+ =/ quote [%ref %trill host.poke /(crip (scow:sr %ud id.poke))]
+ =/ sp (build-sp:trill host.poke our.bowl '' ~ ~)
+ =. contents.sp ~[quote]
+ (build-post:trill now.bowl pubkey sp)
+ ==
+ =/ pw [p (some pubkey) ~ ~ profile]
+ =/ jfact=fact:ui:sur [%post %add pw]
+ =/ ui-card (update-ui:cards:lib jfact)
+ :: only update followers when we are updating our own feed
+ ?. .=(our.bowl host.p) [~[ui-card] state]
+ =. state (add-to-feed p)
+ =/ =fact:comms [%post %add p]
+ =/ fact-card (update-followers:cards:lib fact)
+ :_ state
+ :~ ui-card
+ fact-card
+ ==
+
+
+++ handle-post-fact |= pf=post-fact:comms
+ ^- (quip card _state)
+ =/ =user:sur [%urbit src.bowl]
+ =/ fed (~(get by following.state) user)
+ ?~ fed ~& "emmm not following ya" `state
+ =/ nf=feed:feed
+ ?: ?=(%del -.pf)
+ =< + (del:orm:feed u.fed id.pf)
+ ::mmm people aren't supposed to update if its not their own feeds
+ :: =/ =user:nsur [%urbit host.p.pdf]
+ (put:orm:feed u.fed id.p.pf p.pf)
+ =. following.state (~(put by following.state) user nf)
+ :: TODO update the ui with the changes
+ :_ state ~
+--
diff --git a/desk/lib/nostr/events.hoon b/desk/lib/nostr/events.hoon
new file mode 100644
index 0000000..2a3e818
--- /dev/null
+++ b/desk/lib/nostr/events.hoon
@@ -0,0 +1,49 @@
+/- sur=nostrill, nsur=nostr, post=trill-post, gate=trill-gate
+/+ js=json-nostr, sr=sortug, trill=trill-post, nostr-keys
+|%
+++ post-to-event |= [=keys:nsur eny=@ p=post:post] ^- event:nsur
+ =/ cl (latest-post-content:trill contents.p)
+ =/ string (crip (content-list-to-md:trill cl))
+ =/ ts (to-unix-secs:jikan:sr id.p)
+ =/ raw=raw-event:nsur [pub.keys ts 1 ~ string]
+ =/ event-id (hash-event:nostr-keys raw)
+ =/ signature (sign-event:nostr-keys priv.keys event-id eny)
+ ~& hash-and-signed=[event-id signature]
+ =/ =event:nsur :*
+ event-id
+ pub.keys
+ created-at.raw
+ kind.raw
+ tags.raw
+ content.raw
+ signature
+ ==
+ event
+
+++ event-to-post
+ |= [=event:nsur profile=(unit user-meta:nsur) relay=(unit @t)]
+ ^- post-wrapper:sur
+
+ =/ cl (tokenize:trill content.event)
+ =/ ts (from-unix:jikan:sr created-at.event)
+ =/ cm=content-map:post (init-content-map:trill cl ts)
+
+ :: TODO more about @ps and stuff
+ =/ p=post:post :*
+ id=ts
+ host=`@p`pubkey.event
+ author=`@p`pubkey.event
+ thread=ts
+ parent=~
+ children=~
+ contents=cm
+ read=*lock:gate
+ write=*lock:gate
+ *engagement:post
+ 0v0
+ *signature:post
+ tags=~
+ ==
+ =/ meta [(some pubkey.event) (some id.event) relay profile]
+ [p meta]
+--
diff --git a/desk/lib/nostr.hoon b/desk/lib/nostr/keys.hoon
index 90eb563..90eb563 100644
--- a/desk/lib/nostr.hoon
+++ b/desk/lib/nostr/keys.hoon
diff --git a/desk/lib/nostrill.hoon b/desk/lib/nostrill.hoon
index 6d22adc..41caff2 100644
--- a/desk/lib/nostrill.hoon
+++ b/desk/lib/nostrill.hoon
@@ -1,5 +1,5 @@
-/- post=trill-post, nsur=nostr, sur=nostrill, gate=trill-gate
-/+ trill=trill-post, nostr, sr=sortug, jsonlib=json-nostrill
+/- post=trill-post, nsur=nostr, sur=nostrill, gate=trill-gate, comms=nostrill-comms
+/+ trill=trill-post, nostr-keys, sr=sortug, jsonlib=json-nostrill
|%
::
++ default-state |= =bowl:gall ^- state:sur
@@ -9,7 +9,7 @@
:: =/ l ~['wss://relay.damus.io' 'wss://nos.lol']
=/ rl %+ turn l |= t=@t [t *relay-stats:nsur]
:: =/ l ~[['wss://relay.damus.io' ~]]
- =/ key (gen-keys:nostr eny.bowl)
+ =/ key (gen-keys:nostr-keys eny.bowl)
=/ keyl [key ~]
s(relays (malt rl), keys keyl)
@@ -29,51 +29,6 @@
$(l t.l)
::
-++ post-to-event |= [=keys:nsur eny=@ p=post:post] ^- event:nsur
- =/ cl (latest-post-content:trill contents.p)
- =/ string (crip (content-list-to-md:trill cl))
- =/ ts (to-unix-secs:jikan:sr id.p)
- =/ raw=raw-event:nsur [pub.keys ts 1 ~ string]
- =/ event-id (hash-event:nostr raw)
- =/ signature (sign-event:nostr priv.keys event-id eny)
- ~& hash-and-signed=[event-id signature]
- =/ =event:nsur :*
- event-id
- pub.keys
- created-at.raw
- kind.raw
- tags.raw
- content.raw
- signature
- ==
- event
-
-++ event-to-post
- |= [=event:nsur profile=(unit user-meta:nsur) relay=(unit @t)]
- ^- post-wrapper:sur
-
- =/ cl (tokenize:trill content.event)
- =/ ts (from-unix:jikan:sr created-at.event)
- =/ cm=content-map:post (init-content-map:trill cl ts)
-
- :: TODO more about @ps and stuff
- =/ p=post:post :*
- id=ts
- host=`@p`pubkey.event
- author=`@p`pubkey.event
- thread=ts
- parent=~
- children=~
- contents=cm
- read=*lock:gate
- write=*lock:gate
- *engagement:post
- 0v0
- *signature:post
- tags=~
- ==
- =/ meta [(some pubkey.event) (some id.event) relay profile]
- [p meta]
++ cards
|_ =bowl:gall
@@ -82,5 +37,8 @@
++ update-ui |= =fact:ui:sur ^- card:agent:gall
=/ jon (fact:en:jsonlib fact)
[%give %fact ~[/ui] %json !>(jon)]
+ :: ++ update-followers |= =fact:comms ^- card:agent:gall
+ ++ update-followers |= =fact:comms ^- card:agent:gall
+ [%give %fact ~[/follow] %noun !>(fact)]
--
--
diff --git a/desk/lib/nostrill/comms.hoon b/desk/lib/nostrill/comms.hoon
index 23e442a..5ae07a0 100644
--- a/desk/lib/nostrill/comms.hoon
+++ b/desk/lib/nostrill/comms.hoon
@@ -83,8 +83,10 @@
=/ c2 [%give %kick paths ~]
:~(c1 c2)
:: for the follow flow
- =/ cage [%noun !>(res)]
+ =/ cage [%noun !>([%init res])]
=/ c1 [%give %fact paths cage]
:~(c1)
+
+
--
diff --git a/desk/lib/nostrill/follows.hoon b/desk/lib/nostrill/follows.hoon
index 1cf8a66..9cda041 100644
--- a/desk/lib/nostrill/follows.hoon
+++ b/desk/lib/nostrill/follows.hoon
@@ -31,10 +31,7 @@
=/ c2 (urbit-leave +.user)
:~(c1 c2)
-++ handle-agent-res |= raw=*
- ~& "handling-agent-res"
- =/ =res:comms ;; res:comms raw
- ~& res=-.res
+++ handle-follow-res |= =res:comms
?- -.res
%ng :: bruh
`state
@@ -47,7 +44,7 @@
++ handle-refollow |= sip=@p
:_ state :_ ~
:: (urbit-watch sip)
- [%pass /refollow %agent [sip dap.bowl] %watch /followre]
+ [%pass /follow %agent [sip dap.bowl] %watch /follow]
++ handle-follow-ok |= [=user:sur =fc:feed profile=(unit user-meta:nsur)]
^- (quip card:agent:gall _state)
diff --git a/desk/lib/scri.hoon b/desk/lib/scri.hoon
index b590624..e76d79a 100644
--- a/desk/lib/scri.hoon
+++ b/desk/lib/scri.hoon
@@ -12,6 +12,15 @@
|_ [=state:sur =bowl:gall]
+$ card card:agent:gall
+
+++ get-poast |= [host=@p id=@] ^- (unit post:post)
+ =/ poast ?: .=(host our.bowl)
+ (get:orm:feed feed.state id)
+ ~
+ poast
+
+
+
++ thread |= [hs=@t ids=@t]
^- (unit (unit cage)) :- ~ :- ~ :- %json !>
%- beg-res:en:appjs
diff --git a/desk/lib/shim.hoon b/desk/lib/shim.hoon
index d9a5e6e..af2d142 100644
--- a/desk/lib/shim.hoon
+++ b/desk/lib/shim.hoon
@@ -1,5 +1,5 @@
/- sur=nostrill, nsur=nostr
-/+ js=json-nostr, sr=sortug, nlib=nostr, constants
+/+ js=json-nostr, sr=sortug, nostr-keys, constants
/= web /web/router
|_ [=state:sur =bowl:gall]
@@ -21,7 +21,7 @@
^- [bulk-req:shim:nsur _state]
=/ rls ~(tap by relays.state)
=| urls=(list @t)
- =/ sub-id (gen-sub-id:nlib eny.bowl)
+ =/ sub-id (gen-sub-id:nostr-keys eny.bowl)
=/ =req:shim:nsur [%req sub-id fs]
|- ?~ rls [[urls req] state]
:: build http card
@@ -120,7 +120,7 @@
:: TODO make a function to use most reliable
=/ relay (head ~(tap in relays))
~& http=relay
- =/ sub-id (gen-sub-id:nlib eny.bowl)
+ =/ sub-id (gen-sub-id:nostr-keys eny.bowl)
=/ kinds (silt ~[0])
=/ total=filter:nsur [~ `pubkeys `kinds ~ ~ ~ ~]
=/ req=http-req:shim:nsur [relay http-delay:constants sub-id ~[total]]
diff --git a/desk/sur/nostrill/comms.hoon b/desk/sur/nostrill/comms.hoon
index 4930235..42ea1ba 100644
--- a/desk/sur/nostrill/comms.hoon
+++ b/desk/sur/nostrill/comms.hoon
@@ -5,6 +5,11 @@
[%res res]
[%dbug *]
==
++$ emgagement
+ $% [%reply host=@p id=@da]
+ [%del-reply host=@p id=@da]
+ [%reaction host=@p id=@da reaction=@t]
+ ==
+$ req
$% [%feed ~]
[%thread id=@da]
@@ -17,4 +22,20 @@
$% [%feed =fc:feed profile=(unit user-meta:nsur)]
[%thread p=full-node:post]
==
+:: TODO there's some overlap between what we send to the UI and we send to our followers
+:: but it's not exactly the same
++$ fact
+ $% [%post post-fact]
+ [%prof prof-fact]
+ [%init res]
+ ==
++$ post-fact
+ $% [%add p=post:post]
+ [%del id=@da]
+ [%changes p=post:post]
+ ==
++$ prof-fact
+ $% [%prof =user-meta:nsur]
+ [%keys pub=@ux]
+ ==
--
diff --git a/front/src/styles/ThemeProvider.tsx b/front/src/styles/ThemeProvider.tsx
index 2cc0ca6..08d2e64 100644
--- a/front/src/styles/ThemeProvider.tsx
+++ b/front/src/styles/ThemeProvider.tsx
@@ -19,6 +19,8 @@ export interface ThemeColors {
primary: string;
primaryHover: string;
secondary: string;
+ accent: string;
+ accentHover: string;
background: string;
surface: string;
surfaceHover: string;
@@ -37,11 +39,82 @@ export interface ThemeColors {
overlay: string;
}
+export interface ThemeTypography {
+ fontSizeXs: string;
+ fontSizeSm: string;
+ fontSizeMd: string;
+ fontSizeLg: string;
+ fontSizeXl: string;
+ fontWeightNormal: string;
+ fontWeightMedium: string;
+ fontWeightSemibold: string;
+ fontWeightBold: string;
+}
+
+export interface ThemeSpacing {
+ spacingXs: string;
+ spacingSm: string;
+ spacingMd: string;
+ spacingLg: string;
+ spacingXl: string;
+}
+
+export interface ThemeRadius {
+ radiusSm: string;
+ radiusMd: string;
+ radiusLg: string;
+ radiusFull: string;
+}
+
+export interface ThemeTransitions {
+ transitionFast: string;
+ transitionNormal: string;
+ transitionSlow: string;
+}
+
export interface Theme {
name: ThemeName;
colors: ThemeColors;
+ typography: ThemeTypography;
+ spacing: ThemeSpacing;
+ radius: ThemeRadius;
+ transitions: ThemeTransitions;
}
+// Common theme properties
+const commonTypography: ThemeTypography = {
+ fontSizeXs: "0.75rem",
+ fontSizeSm: "0.875rem",
+ fontSizeMd: "1rem",
+ fontSizeLg: "1.125rem",
+ fontSizeXl: "1.25rem",
+ fontWeightNormal: "400",
+ fontWeightMedium: "500",
+ fontWeightSemibold: "600",
+ fontWeightBold: "700",
+};
+
+const commonSpacing: ThemeSpacing = {
+ spacingXs: "0.25rem",
+ spacingSm: "0.5rem",
+ spacingMd: "1rem",
+ spacingLg: "1.5rem",
+ spacingXl: "2rem",
+};
+
+const commonRadius: ThemeRadius = {
+ radiusSm: "0.25rem",
+ radiusMd: "0.5rem",
+ radiusLg: "0.75rem",
+ radiusFull: "9999px",
+};
+
+const commonTransitions: ThemeTransitions = {
+ transitionFast: "150ms ease",
+ transitionNormal: "250ms ease",
+ transitionSlow: "350ms ease",
+};
+
const themes: Record<ThemeName, Theme> = {
light: {
name: "light",
@@ -49,6 +122,8 @@ const themes: Record<ThemeName, Theme> = {
primary: "#543fd7",
primaryHover: "#4532b8",
secondary: "#f39c12",
+ accent: "#2a9d8f",
+ accentHover: "#238b7f",
background: "#ffffff",
surface: "#f8f9fa",
surfaceHover: "#e9ecef",
@@ -66,6 +141,10 @@ const themes: Record<ThemeName, Theme> = {
shadow: "rgba(0, 0, 0, 0.1)",
overlay: "rgba(0, 0, 0, 0.5)",
},
+ typography: commonTypography,
+ spacing: commonSpacing,
+ radius: commonRadius,
+ transitions: commonTransitions,
},
dark: {
name: "dark",
@@ -73,6 +152,8 @@ const themes: Record<ThemeName, Theme> = {
primary: "#7c6ef7",
primaryHover: "#9085f9",
secondary: "#f39c12",
+ accent: "#2a9d8f",
+ accentHover: "#238b7f",
background: "#0d1117",
surface: "#161b22",
surfaceHover: "#21262d",
@@ -90,6 +171,10 @@ const themes: Record<ThemeName, Theme> = {
shadow: "rgba(0, 0, 0, 0.3)",
overlay: "rgba(0, 0, 0, 0.7)",
},
+ typography: commonTypography,
+ spacing: commonSpacing,
+ radius: commonRadius,
+ transitions: commonTransitions,
},
sepia: {
name: "sepia",
@@ -97,6 +182,8 @@ const themes: Record<ThemeName, Theme> = {
primary: "#8b4513",
primaryHover: "#6b3410",
secondary: "#d2691e",
+ accent: "#2a9d8f",
+ accentHover: "#238b7f",
background: "#f4e8d0",
surface: "#ede0c8",
surfaceHover: "#e6d9c0",
@@ -114,6 +201,10 @@ const themes: Record<ThemeName, Theme> = {
shadow: "rgba(62, 39, 35, 0.1)",
overlay: "rgba(62, 39, 35, 0.5)",
},
+ typography: commonTypography,
+ spacing: commonSpacing,
+ radius: commonRadius,
+ transitions: commonTransitions,
},
noir: {
name: "noir",
@@ -121,6 +212,8 @@ const themes: Record<ThemeName, Theme> = {
primary: "#ffffff",
primaryHover: "#e0e0e0",
secondary: "#808080",
+ accent: "#2a9d8f",
+ accentHover: "#238b7f",
background: "#000000",
surface: "#0a0a0a",
surfaceHover: "#1a1a1a",
@@ -138,6 +231,10 @@ const themes: Record<ThemeName, Theme> = {
shadow: "rgba(255, 255, 255, 0.1)",
overlay: "rgba(0, 0, 0, 0.9)",
},
+ typography: commonTypography,
+ spacing: commonSpacing,
+ radius: commonRadius,
+ transitions: commonTransitions,
},
ocean: {
name: "ocean",
@@ -145,6 +242,8 @@ const themes: Record<ThemeName, Theme> = {
primary: "#006994",
primaryHover: "#005577",
secondary: "#00acc1",
+ accent: "#2a9d8f",
+ accentHover: "#238b7f",
background: "#e1f5fe",
surface: "#b3e5fc",
surfaceHover: "#81d4fa",
@@ -162,6 +261,10 @@ const themes: Record<ThemeName, Theme> = {
shadow: "rgba(1, 87, 155, 0.1)",
overlay: "rgba(1, 87, 155, 0.5)",
},
+ typography: commonTypography,
+ spacing: commonSpacing,
+ radius: commonRadius,
+ transitions: commonTransitions,
},
forest: {
name: "forest",
@@ -169,6 +272,8 @@ const themes: Record<ThemeName, Theme> = {
primary: "#2e7d32",
primaryHover: "#1b5e20",
secondary: "#689f38",
+ accent: "#2a9d8f",
+ accentHover: "#238b7f",
background: "#f1f8e9",
surface: "#dcedc8",
surfaceHover: "#c5e1a5",
@@ -186,6 +291,10 @@ const themes: Record<ThemeName, Theme> = {
shadow: "rgba(27, 94, 32, 0.1)",
overlay: "rgba(27, 94, 32, 0.5)",
},
+ typography: commonTypography,
+ spacing: commonSpacing,
+ radius: commonRadius,
+ transitions: commonTransitions,
},
gruvbox: {
name: "gruvbox",
@@ -193,6 +302,8 @@ const themes: Record<ThemeName, Theme> = {
primary: "#fe8019",
primaryHover: "#d65d0e",
secondary: "#fabd2f",
+ accent: "#2a9d8f",
+ accentHover: "#238b7f",
background: "#282828",
surface: "#3c3836",
surfaceHover: "#504945",
@@ -210,6 +321,10 @@ const themes: Record<ThemeName, Theme> = {
shadow: "rgba(0, 0, 0, 0.3)",
overlay: "rgba(40, 40, 40, 0.8)",
},
+ typography: commonTypography,
+ spacing: commonSpacing,
+ radius: commonRadius,
+ transitions: commonTransitions,
},
};
@@ -254,11 +369,40 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
root.setAttribute("data-theme", themeName);
+ // Set color variables
Object.entries(theme.colors).forEach(([key, value]) => {
const cssVarName = `--color-${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
root.style.setProperty(cssVarName, value);
});
+ // Set typography variables
+ Object.entries(theme.typography).forEach(([key, value]) => {
+ const cssVarName = `--${key.replace(/([A-Z])/g, "-$1").toLowerCase().replace("font-", "font-").replace("size", "").replace("weight", "")}`;
+ root.style.setProperty(cssVarName, value);
+ });
+
+ // Set spacing variables
+ Object.entries(theme.spacing).forEach(([key, value]) => {
+ const cssVarName = `--${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
+ root.style.setProperty(cssVarName, value);
+ });
+
+ // Set radius variables
+ Object.entries(theme.radius).forEach(([key, value]) => {
+ const cssVarName = `--${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
+ root.style.setProperty(cssVarName, value);
+ });
+
+ // Set transition variables
+ Object.entries(theme.transitions).forEach(([key, value]) => {
+ const cssVarName = `--${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`;
+ root.style.setProperty(cssVarName, value);
+ });
+
+ // Legacy variables for backward compatibility
+ root.style.setProperty('--text-color', theme.colors.text);
+ root.style.setProperty('--background-color', theme.colors.background);
+
localStorage.setItem("theme", themeName);
}, [themeName, theme]);
diff --git a/front/src/styles/styles.css b/front/src/styles/styles.css
index 42a2e3c..5affd4f 100644
--- a/front/src/styles/styles.css
+++ b/front/src/styles/styles.css
@@ -34,6 +34,21 @@
/* tailwindy */
+.global-center {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+.centered {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+
.grow {
flex-grow: 1;
}