(NOT CRYPTO RELATED)
web4ᵗʰ or "temporal web" is a paradigm where time is added as a new dimension for user interactions on the web: the fourth dimension 🔮
the rationale can be found here and a 5-minute screencast below:
this repository is meant to be used as a starter kit for those willing to try web4ᵗʰ at their next company hackathon or from the comfort of their homes
-
click the button "Use this template" above, or
git clone [email protected]:teawaterwire/web4th.git && cd web4th
-
npm install
-
npm run dev
(any Java SDK > 8 is needed) -
wait for the build to complete and open http://localhost:8280/
-
create new session
-
profit (you should see something like this 👇)
it's all about adding actions and mapping them to components
- create a file under
src/app/actions
and add it to the existingsrc/app/actions/registry.cljs
;; src/app/actions/new_action.cljs
(ns app.actions.new-action
(:require
[app.actions.entrypoint :as actions]))
;; src/app/actions/registry.cljs
(ns app.actions.registry
(:require [app.actions.new-action]]))
- create a component that will be displayed when the action is triggered
the component is passed an initial state
(defn component [state]
[:div "something: " (:something state)])
an action can be triggered from a component by calling actions/send-action
[:button {:on-click #(actions/send-action :new-action)}]
optional arguments can be passed to the action
[:button {:on-click #(actions/send-action :new-action arguments)}]
- register the action by implementing the multimethod
actions/get-action
the method is passed three values: the action, the global db and the arguments
(defmethod actions/get-action :new-action
[action db args]
{:component component
:state {:something "something"
;; :and (from-global db)
;; :more (from-local args)
}})
the global db
contains value like the username, the messages in the timeline or anything that can be added with re-frame
- optionally use
actions/add-primary-action
to make it a primary action
an action marked as primary can be triggered directly in the command bar, with the option to make it appear by default as well
(actions/add-primary-action :new-action "Label" {:default? true})
you can find examples (hello, pingpong, todolist) under the actions/examples folder
just comment the line in src/app/actions/registry.cljs
if you want to deactivate them without deleting the code
(a real-world example can be found here: https://github.com/teawaterwire/art)
there's a special action called :app.actions.onboarding/onboarding
that is triggered automatically when the user logs in the first time
the matching component should be an introductory message for the user telling them what they can do with your app — don't waste the opportunity 😉
what is state?
- state is "data over time"
but what is the purpose of data?
- to be used by components
for what?
- to create new data upon the triggering of "actions"
does it mean that in web4ᵗʰ state is spread over all components?
- yes, each component represents a sliced snapshot of state
isn't that inefficient?
- components can have local state and it's up to developers to decide when snapshots should be taken (and trigger an action that will render another component)
what's the point of this?
- being able to keep and navigate to all previous important states of the application unlocks new capabilities
- for example, users can go back in time to components and trigger different actions that will "branch off" to a different present 🤯
let's talk about the section at the bottom of the screen: the command bar
it's grouping three features:
-
start/stop chat with support as first-class citizen
-
trigger primary actions
-
input freeform text to either:
- chat with support
- filter through primary and non-default actions
- just write anything like on a notebook
to understand what is support as first-class citizen:
-
change "matrix.org" to "https://matrix.teawaterwire.dev"
-
choose a username/password and click "register"
-
replace "support" with your username in
src/app/config.cljs
then back from the application click "Start chat with support"
this will invite the support account you created in the "conversation" between the app and the end-user
on the support side you can now send messages to the user, but more importantly also actions that will be displayed as components!
you might wonder what is this app-id
in the config file... glad you asked!
the history of interactions between the user and the app is stored as messages in a chat room
when the user signs up this "room" is created and the account app-id
immediately invited
later on the support-id
will be invited and kicked again from the room depending on what the end user wants
but the app-id
will always stay in the room, as if it was an admin account with access to the entire history of the user's interactions
(you can register your own app account the same way you registered the support account)
this repository comes with a GitHub workflow that builds and deploys to Github Pages
this can be triggered manually or on every push to the master
branch
enable "GitHub Actions" under Settings > Pages > Build and deployment
(you either need your repository to be public or have a paid account)
need help plz 🎨 (using Tailwind btw - it's great)
choices were made
authentication is inevitable but has to be as frictionless as possible
a private key / public key provided by crypto wallet was the first guess, but friction was still there
using biometrics to authenticate is frictionless, but support was limited (only on desktop with magic.link)
it was finally decided to identify a user by a session id
that is randomly generated upon creation
a user can save that id
to "load" the session on another browser if needed
it is up to the app developer to add other auth systems within a session (allowing for instance different crypto wallets to be connected under the same session)
a decentralized conversation store was the key missing ingredient for a true web4ᵗʰ app
leveraging their work at the protocol level but also at the application level: existing cross platform clients can be used to interact with users (support account)
for convenience a Matrix homeserver is deployed at matrix.teawaterwire.dev but you can deploy your own relatively easily following this helpful tutorial (and passing the --really-enable-open-registration
flag)
it feels right to use immutable data for immutable conversations
but ClojureScript has other advantages:
- true interactive programming with a REPL (Calva recommended)
- re-frame to get smooth global state management
- reagent for the most elegant way to write React component
people not willing to write a single lispy parenthesis can just write JavaScript (and React components) — the amazing tool which is shadow-cljs will deal with it 😌
<3 open to contributions <3
Webo Webini Lupus 🐺