objective categorical abstract machine language personal data server
65
fork

Configure Feed

Select the types of activity you want to include in your feed.

login page

futurGH 03494acb ad54c15e

+163 -16
+3
dune
··· 5 5 (deps 6 6 %{workspace_root}/tools/tailwindcss/tailwindcss 7 7 (:input %{workspace_root}/public/main.css) 8 + (source_tree %{workspace_root}/public) 8 9 (source_tree %{workspace_root}/pegasus/lib/templates)) 9 10 (action 10 11 (chdir ··· 16 17 %{input} 17 18 -o 18 19 %{target}))))) 20 + 21 + (copy_files public/*)
+16 -14
pegasus/lib/api/account_/login.ml
··· 1 1 let get_handler = 2 2 Xrpc.handler (fun ctx -> 3 - let _redirect_url = 3 + let redirect_url = 4 4 Dream.query ctx.req "redirect_url" |> Option.value ~default:"/" 5 5 in 6 - (* render login page with 7 - [ ("redirect_url", `String redirect_url) 8 - ; ("error", `Null) ] 9 - *) 10 - Dream.html "" ) 6 + let html = JSX.render (Templates.Login.make ~redirect_url ()) in 7 + Dream.html html ) 11 8 12 9 let post_handler = 13 10 Xrpc.handler (fun ctx -> 14 - let%lwt form = Dream.form ctx.req in 15 - match form with 11 + match%lwt Dream.form ctx.req with 16 12 | `Ok fields -> ( 17 13 let identifier = List.assoc "identifier" fields in 18 14 let password = List.assoc "password" fields in ··· 24 20 in 25 21 match actor with 26 22 | None -> 27 - (* render login page with 28 - [ ("error", `String "Invalid credentials") 29 - ; ("redirect_url", `String redirect_url) ] 30 - *) 31 - Dream.html ~status:`Unauthorized "" 23 + let html = 24 + JSX.render 25 + (Templates.Login.make ~redirect_url 26 + ~error:"Invalid username or password. Please try again." () ) 27 + in 28 + Dream.html ~status:`Unauthorized html 32 29 | Some {did; _} -> 33 30 let%lwt () = Dream.invalidate_session ctx.req in 34 31 let%lwt () = Dream.set_session_field ctx.req "did" did in 35 32 Dream.redirect ctx.req redirect_url ) 36 33 | _ -> 37 - Errors.invalid_request "invalid request body" ) 34 + let html = 35 + JSX.render 36 + (Templates.Login.make ~redirect_url:"/" 37 + ~error:"Invalid credentials provided. Please try again." () ) 38 + in 39 + Dream.html ~status:`Unauthorized html )
+12
pegasus/lib/templates/components/button.mlx
··· 1 + let make ?id ?(type_ = "button") ?(class_ = "") ~children () = 2 + <button 3 + ?id 4 + type_ 5 + class_=( "bg-white font-serif text-mana-200 text-lg py-1 px-4 rounded-lg \ 6 + w-full flex items-center justify-center transition delay-50 \ 7 + duration-300 shadow-whisper hover:shadow-shimmer \ 8 + hover:bg-mist-20 focus:shadow-shimmer focus:bg-mist-20 \ 9 + focus:outline-none active:shadow-glow disabled:bg-mana-40 \ 10 + disabled:text-mist-100 " ^ class_ )> 11 + children 12 + </button>
+49
pegasus/lib/templates/components/input.mlx
··· 1 + open JSX 2 + 3 + (* putting this inline messes with ocamlformat-mlx *) 4 + let req_marker = " *" 5 + 6 + let make ~id ?(class_ = "") ?(type_ = "text") ?label ?(sr_only = false) ?value 7 + ?placeholder ?(required = false) ?(disabled = false) ?trailing () = 8 + let placeholder = if label <> None && sr_only then label else placeholder in 9 + <div> 10 + ( match label with 11 + | Some label -> 12 + <div 13 + class_=( "flex justify-between text-sm" 14 + ^ if sr_only then " sr-only" else "" )> 15 + <label for_=id class_="text-mist-100"> 16 + ( if required then 17 + list 18 + [ string label 19 + ; <span class_="text-phoenix-100">(string req_marker)</span> 20 + ] 21 + else string label ) 22 + </label> 23 + ( if required then null 24 + else <span class_="text-mist-80">"optional"</span> ) 25 + </div> 26 + | None -> 27 + null ) 28 + <div 29 + class_=( "flex items-center rounded-lg py-1.5 px-3 outline-1 \ 30 + outline-mana-40 disabled:outline-mana-40/20 \ 31 + disabled:bg-mana-40/20 focus-within:outline-2 \ 32 + focus-within:outline-mana-100" ^ class_ )> 33 + <input 34 + id 35 + type_ 36 + ?placeholder 37 + required 38 + disabled 39 + ?value 40 + class_="block min-w-0 grow text-mist-100 placeholder:text-mist-80 \ 41 + placeholder:font-medium focus:outline-none" 42 + /> 43 + ( match trailing with 44 + | Some trailing -> 45 + <div class_="shrink-0 text-mist-100 select-none">trailing</div> 46 + | None -> 47 + null ) 48 + </div> 49 + </div>
+11
pegasus/lib/templates/icons/circle_alert.mlx
··· 1 + let make ?class_ () = 2 + <svg 3 + ?class_ 4 + viewBox="0 0 24 24" 5 + fill="none" 6 + stroke="currentColor" 7 + strokeLinecap="round" 8 + strokeLinejoin="round" 9 + strokeWidth="2"> 10 + <circle cx="12" cy="12" r="10" /> <path d="M12 8v4M12 16h.01" /> 11 + </svg>
+6 -2
pegasus/lib/templates/layout.mlx
··· 1 1 open JSX 2 2 3 - let make ?(title = "Pegasus") children = 3 + let make ?(title = "Pegasus") ~children () = 4 4 <html lang="en"> 5 5 <head> 6 6 <meta charset="utf-8" /> ··· 8 8 <link rel="stylesheet" href="/public/index.css" /> 9 9 <title>(string title)</title> 10 10 </head> 11 - <body>(list children)</body> 11 + <body 12 + class_="bg-feather-100 font-sans font-normal text-base tracking-normal \ 13 + flex items-center justify-center min-h-screen"> 14 + children 15 + </body> 12 16 </html>
+21
pegasus/lib/templates/login.mlx
··· 1 + open JSX 2 + open Components 3 + 4 + let make ~redirect_url ?error () = 5 + let _r = redirect_url in 6 + let _e = error in 7 + <Layout title="Login"> 8 + <main class_="w-full h-auto max-w-xs px-4 sm:px-0"> 9 + <h1 class_="text-2xl font-serif text-mana-200 mb-2">"sign in"</h1> 10 + <span class_="w-full text-balance text-mist-100"> 11 + "Enter your handle, email address, or DID, and your password." 12 + </span> 13 + <form method_="post" class_="w-full flex flex-col mt-4 mb-2 gap-y-2"> 14 + <Input sr_only=true id="identifier" type_="text" label="identifier" /> 15 + <Input sr_only=true id="password" type_="password" label="password" /> 16 + (match error with | Some error -> <span class_="inline-flex items-center text-phoenix-100 text-sm">(list [ <Icons.Circle_alert class_="w-4 h-4 mr-2" />; (string error)]) </span> | None -> null) 17 + <Button type_="submit" class_="mt-2">"sign in"</Button> 18 + </form> 19 + <span class_="text-sm text-mist-100">"Or "<a href="/account/signup" class_="text-mana-100 underline decoration-mana-100 hover:text-mana-200">"create an account"</a>"."</span> 20 + </main> 21 + </Layout>
public/fonts/Fragment.woff

This is a binary file and will not be displayed.

public/fonts/Fragment.woff2

This is a binary file and will not be displayed.

+45
public/main.css
··· 1 1 @import "tailwindcss" source("../pegasus/lib/templates"); 2 + 3 + @font-face { 4 + font-family: "Fragment"; 5 + src: 6 + url("fonts/Fragment.woff2") format("woff2"), 7 + url("fonts/Fragment.woff") format("woff"); 8 + font-weight: normal; 9 + font-style: normal; 10 + font-display: swap; 11 + } 12 + 13 + @font-face { 14 + font-family: "Geist"; 15 + src: url("https://fonts.gstatic.com/s/geist/v4/gyByhwUxId8gMEwcGFWNOITd.woff2") 16 + format("woff2"); 17 + font-weight: 300 400; 18 + font-style: normal; 19 + font-display: swap; 20 + } 21 + 22 + @theme { 23 + --font-serif: Fragment, Georgia, "Times New Roman", Times, serif; 24 + --font-sans: Geist, Helvetica, -apple-system, system-ui, sans-serif; 25 + --font-weight-normal: 300; 26 + --font-weight-medium: 400; 27 + 28 + --tracking-normal: 0.01em; 29 + 30 + --color-*: initial; 31 + --color-white: #fff; 32 + --color-feather-100: #c8cfd2; 33 + --color-phoenix-100: #db4c64; 34 + --color-mana-40: #9b9eaa; 35 + --color-mana-100: #6558a1; 36 + --color-mana-200: #312b4d; 37 + --color-mist-20: #ecedf8; 38 + --color-mist-40: #dee1e3; 39 + --color-mist-60: #a4a9ac; 40 + --color-mist-80: #737579; 41 + --color-mist-100: #4f4f53; 42 + 43 + --shadow-whisper: inset 0 0 1em #97baff8c; 44 + --shadow-shimmer: inset 0 0 1em #79a7ed99; 45 + --shadow-glow: inset 0 0 2em #2d37ba73; 46 + }