this repo has no description
lustre frontent oat-ui gleam
0
fork

Configure Feed

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

๐Ÿ’„ Add basic navbar items

+176 -10
+15 -6
src/client.gleam
··· 1 + import client/language 1 2 import client/page 2 3 import client/page/home 3 4 import client/page/login ··· 25 26 route: route.Route, 26 27 /// Current Page model 27 28 page: page.Page, 29 + /// Selected language 30 + lang: language.Language, 28 31 ) 29 32 } 30 33 ··· 87 90 88 91 // Batch all scheduled effects and build the initial application `Model` 89 92 let effect = effect.batch([restore_session, init_modem]) 90 - #(Model(session:, route:, page:), effect) 93 + #(Model(session:, route:, page:, lang: language.BrazillianPortuguese), effect) 91 94 } 92 95 93 96 fn init_session( ··· 113 116 f: fn(a) -> Msg, 114 117 ) -> element.Element(Msg) { 115 118 html.section([attr.data("sidebar-layout", "")], [ 116 - navbar.view(model.session) |> element.map(NavbarMsg), 119 + navbar.view(model.session, model.lang) |> element.map(NavbarMsg), 117 120 sidebar.view(model.session) |> element.map(SidebarMsg), 118 121 html.main([attr.class("p-4")], [element_view |> element.map(f)]), 119 122 ]) ··· 123 126 pub fn view(model: Model) -> element.Element(Msg) { 124 127 case model { 125 128 // HOME PAGE --------------------------------------------------------------- 126 - Model(session:, route: route.Home, page: page.Home) -> 129 + Model(session:, route: route.Home, page: page.Home, ..) -> 127 130 layout(model, home.view(session), HomeMsg) 128 131 129 132 // LOGIN PAGE -------------------------------------------------------------- 130 - Model(session:, route: route.Login, page: page.Login(page)) -> 133 + Model(session:, route: route.Login, page: page.Login(page), ..) -> 131 134 layout(model, login.view(session, page), LoginMsg) 132 135 133 136 _ -> not_found.view() ··· 139 142 /// Update current application `Model` 140 143 pub fn update(model: Model, msg: Msg) -> #(Model, Effect(Msg)) { 141 144 case model, msg { 142 - // NAVIGATION 145 + // ๏‰ธ NAVIGATION 143 146 model, UserNavigatedTo(route) -> handle_navigation(model, route) 144 147 148 + // ๏’„ LANGUAGE SELECTION 149 + model, NavbarMsg(navbar.UserSelectedLanguage(lang)) -> #( 150 + Model(..model, lang:), 151 + effect.none(), 152 + ) 153 + 145 154 // SESSION MANAGEMENT ----------------------------------------------------- 146 155 // 147 156 // Success 148 157 Model(session: session.Pending(on_success:, on_error: _), ..), 149 158 UserRestoredSession(Ok(session)) 150 159 -> #( 151 - Model(session:, route: on_success, page: page.init(on_success)), 160 + Model(..model, session:, route: on_success, page: page.init(on_success)), 152 161 modem.push(route.to_path(on_success), option.None, option.None), 153 162 ) 154 163
+24
src/client/language.gleam
··· 1 + pub type Language { 2 + BrazillianPortuguese 3 + English 4 + German 5 + Spanish 6 + } 7 + 8 + pub fn to_flag(lang: Language) { 9 + case lang { 10 + BrazillianPortuguese -> "๐Ÿ‡ง๐Ÿ‡ท" 11 + English -> "๐Ÿ‡บ๐Ÿ‡ธ" 12 + German -> "๐Ÿ‡ฉ๐Ÿ‡ช" 13 + Spanish -> "๐Ÿ‡ช๐Ÿ‡ธ" 14 + } 15 + } 16 + 17 + pub fn to_string(lang: Language) { 18 + case lang { 19 + BrazillianPortuguese -> "Brazillian Portuguese" 20 + English -> "English" 21 + German -> "German" 22 + Spanish -> "Spanish" 23 + } 24 + }
+83 -4
src/client/page/navbar.gleam
··· 1 + import client/language 1 2 import client/session 3 + import gleam/list 2 4 import icon 3 5 import lustre/attribute.{class} as attr 4 6 import lustre/element 5 7 import lustre/element/html 8 + import lustre/event 6 9 7 - pub type Msg 10 + pub type Msg { 11 + UserSelectedLanguage(lang: language.Language) 12 + } 8 13 9 - pub fn view(_session: session.Session) -> element.Element(Msg) { 10 - html.nav([attr.data("topnav", ""), class("p-4 h-full border-b")], [ 14 + pub fn view( 15 + _session: session.Session, 16 + lang: language.Language, 17 + ) -> element.Element(Msg) { 18 + html.nav( 19 + [attr.data("topnav", ""), class("flex justify-between h-full border-b")], 20 + [ 21 + view_left_section(), 22 + view_middle_section(), 23 + view_right_section(lang), 24 + ], 25 + ) 26 + } 27 + 28 + fn view_left_section() -> element.Element(Msg) { 29 + html.section([class("flex gap-2 items-center")], [ 11 30 // Toggle button 12 31 icon.menu([ 13 32 class("p-1 rounded-sm border size-8"), 14 33 attr.data("sidebar-toggle", ""), 15 34 ]), 16 35 17 - html.p([], [html.text("navbar")]), 36 + // ๏ฌ Logo 37 + icon.leaf([ 38 + class("p-2 text-white size-10"), 39 + class("from-green-500 via-emerald-500 to-teal-600 bg-linear-to-r"), 40 + class("rounded-md drop-shadow-md"), 41 + ]), 42 + 43 + // ๎™Ž Title 44 + html.h2( 45 + [ 46 + class("inline my-0 text-2xl font-bold"), 47 + // Gradient 48 + class("text-transparent bg-clip-text"), 49 + class("from-green-600 to-teal-600 bg-linear-to-r"), 50 + ], 51 + [html.text("Vรฉrtis Climate")], 52 + ), 53 + ]) 54 + } 55 + 56 + fn view_middle_section() -> element.Element(Msg) { 57 + html.section([class("hidden space-x-4 text-sm text-gray-500 md:inline")], [ 58 + html.a([], [html.text("Soluรงรตes")]), 59 + html.a([], [html.text("Como Funciona")]), 60 + html.a([], [html.text("Benefรญcios")]), 61 + html.a([], [html.text("Contato")]), 62 + ]) 63 + } 64 + 65 + const languages = [ 66 + language.BrazillianPortuguese, 67 + language.English, 68 + language.German, 69 + language.Spanish, 70 + ] 71 + 72 + fn view_right_section(lang: language.Language) -> element.Element(Msg) { 73 + let id = "lang-selection" 74 + 75 + html.section([], [ 76 + // Language Selection 77 + element.element("ot-dropdown", [], [ 78 + // Button 79 + html.button([class("text-lg ghost"), attr.popovertarget(id)], [ 80 + icon.globe([]), 81 + html.text(language.to_flag(lang)), 82 + ]), 83 + 84 + // Dropdown 85 + html.menu( 86 + [attr.popover(""), attr.id(id)], 87 + // Show all available languages 88 + list.map(languages, fn(lang) { 89 + let on_click = event.on_click(UserSelectedLanguage(lang)) 90 + html.button([attr.role("menuitem"), on_click], [ 91 + // Join flag and string value 92 + html.text(language.to_flag(lang) <> " " <> language.to_string(lang)), 93 + ]) 94 + }), 95 + ), 96 + ]), 18 97 ]) 19 98 }
+54
src/icon.gleam
··· 65 65 ], 66 66 ) 67 67 } 68 + 69 + pub fn globe(attributes: List(Attribute(a))) { 70 + svg.svg( 71 + [ 72 + attribute("stroke-linejoin", "round"), 73 + attribute("stroke-linecap", "round"), 74 + attribute("stroke-width", "2"), 75 + attribute("stroke", "currentColor"), 76 + attribute("fill", "none"), 77 + attribute("viewBox", "0 0 24 24"), 78 + attribute("height", "24"), 79 + attribute("width", "24"), 80 + ..attributes 81 + ], 82 + [ 83 + svg.circle([ 84 + attribute("r", "10"), 85 + attribute("cy", "12"), 86 + attribute("cx", "12"), 87 + ]), 88 + svg.path([ 89 + attribute("d", "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"), 90 + ]), 91 + svg.path([attribute("d", "M2 12h20")]), 92 + ], 93 + ) 94 + } 95 + 96 + pub fn leaf(attributes: List(Attribute(a))) { 97 + svg.svg( 98 + [ 99 + attribute("stroke-linejoin", "round"), 100 + attribute("stroke-linecap", "round"), 101 + attribute("stroke-width", "2"), 102 + attribute("stroke", "currentColor"), 103 + attribute("fill", "none"), 104 + attribute("viewBox", "0 0 24 24"), 105 + attribute("height", "24"), 106 + attribute("width", "24"), 107 + ..attributes 108 + ], 109 + [ 110 + svg.path([ 111 + attribute( 112 + "d", 113 + "M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z", 114 + ), 115 + ]), 116 + svg.path([ 117 + attribute("d", "M2 21c0-3 1.85-5.36 5.08-6C9.5 14.52 12 13 13 12"), 118 + ]), 119 + ], 120 + ) 121 + }