Auto-indexing service and GraphQL API for AT Protocol Records
quickslice.slices.network/
atproto
gleam
graphql
1/// Onboarding Page Component
2///
3/// Displays the initial admin setup page for first-time configuration.
4/// This page is shown when there are no admins configured in the system.
5/// The user enters their handle and is redirected to the OAuth flow.
6import components/actor_autocomplete
7import components/button
8import components/logo
9import lustre/attribute
10import lustre/element.{type Element}
11import lustre/element/html
12
13pub type Msg {
14 AutocompleteInput(String)
15 AutocompleteSelect(String)
16 AutocompleteKeydown(String)
17 AutocompleteBlur
18 AutocompleteFocus
19}
20
21pub type Model {
22 Model
23}
24
25pub fn init() -> Model {
26 Model
27}
28
29pub fn view(
30 autocomplete_model: actor_autocomplete.Model,
31 on_input: fn(String) -> msg,
32 on_select: fn(String) -> msg,
33 on_keydown: fn(String) -> msg,
34 on_blur: fn() -> msg,
35 on_focus: fn() -> msg,
36) -> Element(msg) {
37 html.div([attribute.class("max-w-md mx-auto mt-12")], [
38 html.div(
39 [attribute.class("bg-zinc-800/50 rounded p-8 border border-zinc-700")],
40 [
41 // Logo centered at top
42 html.div([attribute.class("flex justify-center mb-6")], [
43 logo.view("w-16 h-16"),
44 ]),
45 html.h1(
46 [
47 attribute.class(
48 "text-2xl font-semibold text-zinc-300 mb-2 text-center",
49 ),
50 ],
51 [
52 element.text("Welcome to Quickslice"),
53 ],
54 ),
55 html.p([attribute.class("text-zinc-400 mb-6 text-center")], [
56 element.text("Set up an administrator account to get started."),
57 ]),
58 html.form(
59 [
60 attribute.action("/admin/oauth/authorize"),
61 attribute.method("POST"),
62 attribute.class("space-y-4"),
63 ],
64 [
65 html.div([], [
66 html.label([attribute.class("block text-sm text-zinc-400 mb-2")], [
67 element.text("AT Protocol Handle"),
68 ]),
69 actor_autocomplete.view(
70 autocomplete_model,
71 "onboarding-handle",
72 "login_hint",
73 "user.bsky.social",
74 "font-mono px-4 py-2 text-sm text-zinc-300 bg-zinc-900 border border-zinc-800 rounded focus:outline-none focus:border-zinc-700 w-full",
75 on_input,
76 on_select,
77 on_keydown,
78 on_blur,
79 on_focus,
80 ),
81 ]),
82
83 html.div([attribute.class("pt-2")], [
84 button.submit(
85 disabled: autocomplete_model.query == "",
86 text: "Continue",
87 ),
88 ]),
89 ],
90 ),
91 ],
92 ),
93 ])
94}