Deployment and lifecycle management for Nix
0
fork

Configure Feed

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

sower: update to latest phoenix/liveview layout structure

+280 -201
+5 -7
apps/sower/lib/sower_web.ex
··· 21 21 22 22 def router do 23 23 quote do 24 + # explicit path management 24 25 use Phoenix.Router, helpers: true 25 26 26 27 # Import common connection and controller functions to use in pipelines ··· 38 39 39 40 def controller do 40 41 quote do 41 - use Phoenix.Controller, 42 - formats: [:html, :json], 43 - layouts: [html: SowerWeb.Layouts] 42 + use Phoenix.Controller, formats: [:html, :json] 44 43 45 44 import Plug.Conn 46 45 import SowerWeb.Gettext ··· 51 50 52 51 def live_view do 53 52 quote do 54 - use Phoenix.LiveView, 55 - layout: {SowerWeb.Layouts, :app} 53 + use Phoenix.LiveView 56 54 57 55 unquote(html_helpers()) 58 56 end ··· 87 85 import SowerWeb.CoreComponents 88 86 import SowerWeb.Gettext 89 87 90 - # Shortcut for generating JS commands 91 88 alias Phoenix.LiveView.JS 89 + alias SowerWeb.Layouts 92 90 93 91 # Routes generation with the ~p sigil 94 92 unquote(verified_routes()) ··· 105 103 end 106 104 107 105 @doc """ 108 - When used, dispatch to the appropriate controller/view/etc. 106 + When used, dispatch to the appropriate controller/live_view/etc. 109 107 """ 110 108 defmacro __using__(which) when is_atom(which) do 111 109 apply(__MODULE__, which, [])
-38
apps/sower/lib/sower_web/components/core_components.ex
··· 137 137 end 138 138 139 139 @doc """ 140 - Shows the flash group with standard titles and content. 141 - 142 - ## Examples 143 - 144 - <.flash_group flash={@flash} /> 145 - """ 146 - attr :flash, :map, required: true, doc: "the map of flash messages" 147 - 148 - def flash_group(assigns) do 149 - ~H""" 150 - <.flash kind={:info} title="Success!" flash={@flash} /> 151 - <.flash kind={:error} title="Error!" flash={@flash} /> 152 - <.flash 153 - id="client-error" 154 - kind={:error} 155 - title="We can't find the internet" 156 - phx-disconnected={show(".phx-client-error #client-error")} 157 - phx-connected={hide("#client-error")} 158 - hidden 159 - > 160 - Attempting to reconnect <.icon name="hero-arrow-path" class="ml-1 h-3 w-3 animate-spin" /> 161 - </.flash> 162 - 163 - <.flash 164 - id="server-error" 165 - kind={:error} 166 - title="Something went wrong!" 167 - phx-disconnected={show(".phx-server-error #server-error")} 168 - phx-connected={hide("#server-error")} 169 - hidden 170 - > 171 - Hang in there while we get back on track 172 - <.icon name="hero-arrow-path" class="ml-1 h-3 w-3 animate-spin" /> 173 - </.flash> 174 - """ 175 - end 176 - 177 - @doc """ 178 140 Renders a simple form. 179 141 180 142 ## Examples
+265
apps/sower/lib/sower_web/components/layouts.ex
··· 1 1 defmodule SowerWeb.Layouts do 2 + @moduledoc """ 3 + This module holds layouts and related functionality 4 + used by your application. 5 + """ 2 6 use SowerWeb, :html 3 7 8 + @doc """ 9 + Renders your app layout. 10 + 11 + This function is typically invoked from every template, 12 + and it often contains your application menu, sidebar, 13 + or similar. 14 + 15 + ## Examples 16 + 17 + <Layouts.app flash={@flash}> 18 + <h1>Content</h1> 19 + </Layouts.app> 20 + 21 + """ 22 + attr :flash, :map, required: true, doc: "the map of flash messages" 23 + 24 + attr :current_scope, :map, 25 + default: nil, 26 + doc: "the current [scope](https://hexdocs.pm/phoenix/scopes.html)" 27 + 28 + attr :current_user, :map, default: nil 29 + 30 + slot :inner_block, required: true 31 + 32 + def app(assigns) do 33 + ~H""" 34 + <header> 35 + <nav class="bg-zinc-200 dark:bg-zinc-800 w-full"> 36 + <div class="max-w-screen-xl flex flex-no-wrap items-center justify-between mx-auto p-4"> 37 + <div class="items-center justify-between w-full md:flex md:w-auto md:order-1"> 38 + <ul class="flex flex-col font-medium mt-4 md:space-x-8 rtl:space-x-reverse md:flex-row md:mt-0 md:border-0 "> 39 + <li> 40 + <.link navigate={~p"/"} class="hover:text-orange-700 dark:hover:text-orange-300"> 41 + Home 42 + </.link> 43 + </li> 44 + <li> 45 + <.link navigate={~p"/seeds"} class="hover:text-orange-700 dark:hover:text-orange-300"> 46 + Seeds 47 + </.link> 48 + </li> 49 + <li> 50 + <.link navigate={~p"/agents"} class="hover:text-orange-700 dark:hover:text-orange-300"> 51 + Agents 52 + </.link> 53 + </li> 54 + <li> 55 + <.link 56 + navigate={~p"/nix/caches"} 57 + class="hover:text-orange-700 dark:hover:text-orange-300" 58 + > 59 + Caches 60 + </.link> 61 + </li> 62 + <li> 63 + <.link navigate={~p"/forges"} class="hover:text-orange-700 dark:hover:text-orange-300"> 64 + Forges 65 + </.link> 66 + </li> 67 + </ul> 68 + </div> 69 + 70 + <div class="relative md:order-2 space-x-3 md:space-x-0 rtl:space-x-reverse"> 71 + <%= if @current_user || nil do %> 72 + <button 73 + type="button" 74 + class="flex text-sm bg-zinc-800 rounded-full md:me-0 focus:ring-4 focus:ring-zinc-300 dark:focus:ring-zinc-600" 75 + id="user-menu-button" 76 + aria-expanded="false" 77 + data-dropdown-toggle="user-dropdown" 78 + data-dropdown-placement="bottom" 79 + phx-click={JS.toggle(to: "#user-dropdown")} 80 + phx-click-away={ 81 + JS.hide( 82 + to: "#user-dropdown", 83 + transition: 84 + {"ease-out duration-75", "opacity-100 scale-100", "opacity-0 scale-95"} 85 + ) 86 + } 87 + phx-key="escape" 88 + phx-window-key={ 89 + JS.hide( 90 + to: "#user-dropdown", 91 + transition: 92 + {"ease-out duration-75", "opacity-100 scale-100", "opacity-0 scale-95"} 93 + ) 94 + } 95 + > 96 + <span class="sr-only">Open user menu</span> 97 + <svg 98 + width="24px" 99 + height="24px" 100 + stroke-width="0.5" 101 + viewBox="0 0 24 24" 102 + xmlns="http://www.w3.org/2000/svg" 103 + class="stroke-zinc-900 dark:stroke-zinc-200 fill-zinc-200 dark:fill-zinc-800 hover:fill-orange-300 dark:hover:fill-orange-700" 104 + > 105 + <path 106 + d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2Z" 107 + stroke-width="1.5" 108 + stroke-linecap="round" 109 + stroke-linejoin="round" 110 + > 111 + </path> 112 + <path 113 + d="M4.271 18.3457C4.271 18.3457 6.50002 15.5 12 15.5C17.5 15.5 19.7291 18.3457 19.7291 18.3457" 114 + stroke-width="1.5" 115 + stroke-linecap="round" 116 + stroke-linejoin="round" 117 + > 118 + </path> 119 + <path 120 + d="M12 12C13.6569 12 15 10.6569 15 9C15 7.34315 13.6569 6 12 6C10.3431 6 9 7.34315 9 9C9 10.6569 10.3431 12 12 12Z" 121 + stroke-width="1.5" 122 + stroke-linecap="round" 123 + stroke-linejoin="round" 124 + > 125 + </path> 126 + </svg> 127 + </button> 128 + <div 129 + class="absolute z-[1000] m-0 hidden top-8 right-8 whitespace-nowrap text-base list-none bg-white divide-y divide-zinc-100 rounded-lg shadow dark:bg-zinc-700 dark:divide-zinc-600" 130 + id="user-dropdown" 131 + > 132 + <div class="px-4 py-3"> 133 + <span class="px-3 py-2 text-sm font-medium text-zinc-700 dark:text-zinc-200 rounded-md"> 134 + Hello, {@current_user.name}! 135 + </span> 136 + </div> 137 + <ul class="py-2" aria-labelledby="user-menu-button"> 138 + <li> 139 + <.link 140 + navigate={~p"/settings/access-tokens"} 141 + class="block px-4 py-2 text-sm text-zinc-700 hover:bg-zinc-100 dark:hover:bg-zinc-600 dark:text-zinc-200 dark:hover:text-white" 142 + > 143 + Access Tokens 144 + </.link> 145 + </li> 146 + <li> 147 + <.link 148 + navigate={~p"/settings"} 149 + class="block px-4 py-2 text-sm text-zinc-700 hover:bg-zinc-100 dark:hover:bg-zinc-600 dark:text-zinc-200 dark:hover:text-white" 150 + > 151 + Settings 152 + </.link> 153 + </li> 154 + <li> 155 + <a 156 + href="#" 157 + class="block px-4 py-2 text-sm text-zinc-700 hover:bg-zinc-100 dark:hover:bg-zinc-600 dark:text-zinc-200 dark:hover:text-white" 158 + > 159 + Sign out 160 + </a> 161 + </li> 162 + </ul> 163 + </div> 164 + <% else %> 165 + <.link 166 + navigate={~p"/auth/oidcc"} 167 + class="rounded-lg bg-zinc-100 px-2 py-1 text-[0.8125rem] font-semibold leading-6 text-zinc-900 hover:bg-zinc-200/80 active:text-zinc-900/70" 168 + > 169 + Sign In 170 + </.link> 171 + <% end %> 172 + </div> 173 + </div> 174 + </nav> 175 + </header> 176 + <main class="px-4 py-8 sm:px-6 lg:px-8 relative"> 177 + <div class="mx-auto max-w-6xl"> 178 + <.flash_group flash={@flash} /> 179 + {render_slot(@inner_block)} 180 + </div> 181 + </main> 182 + """ 183 + end 184 + 185 + @doc """ 186 + Shows the flash group with standard titles and content. 187 + 188 + ## Examples 189 + 190 + <.flash_group flash={@flash} /> 191 + """ 192 + attr :flash, :map, required: true, doc: "the map of flash messages" 193 + attr :id, :string, default: "flash-group", doc: "the optional id of flash container" 194 + 195 + def flash_group(assigns) do 196 + ~H""" 197 + <div id={@id} aria-live="polite"> 198 + <.flash kind={:info} flash={@flash} /> 199 + <.flash kind={:error} flash={@flash} /> 200 + 201 + <.flash 202 + id="client-error" 203 + kind={:error} 204 + title="We can't find the internet" 205 + phx-disconnected={show(".phx-client-error #client-error") |> JS.remove_attribute("hidden")} 206 + phx-connected={hide("#client-error") |> JS.set_attribute({"hidden", ""})} 207 + hidden 208 + > 209 + Attempting to reconnect 210 + <.icon name="hero-arrow-path" class="ml-1 size-3 motion-safe:animate-spin" /> 211 + </.flash> 212 + 213 + <.flash 214 + id="server-error" 215 + kind={:error} 216 + title="Something went wrong!" 217 + phx-disconnected={show(".phx-server-error #server-error") |> JS.remove_attribute("hidden")} 218 + phx-connected={hide("#server-error") |> JS.set_attribute({"hidden", ""})} 219 + hidden 220 + > 221 + Attempting to reconnect 222 + <.icon name="hero-arrow-path" class="ml-1 size-3 motion-safe:animate-spin" /> 223 + </.flash> 224 + </div> 225 + """ 226 + end 227 + 228 + @doc """ 229 + Provides dark vs light theme toggle based on themes defined in app.css. 230 + 231 + See <head> in root.html.heex which applies the theme before page load. 232 + """ 233 + def theme_toggle(assigns) do 234 + ~H""" 235 + <div class="card relative flex flex-row items-center border-2 border-base-300 bg-base-300 rounded-full"> 236 + <div class="absolute w-1/3 h-full rounded-full border-1 border-base-200 bg-base-100 brightness-200 left-0 [[data-theme=light]_&]:left-1/3 [[data-theme=dark]_&]:left-2/3 transition-[left]" /> 237 + 238 + <button 239 + class="flex p-2 cursor-pointer w-1/3" 240 + phx-click={JS.dispatch("phx:set-theme")} 241 + data-phx-theme="system" 242 + > 243 + <.icon name="hero-computer-desktop-micro" class="size-4 opacity-75 hover:opacity-100" /> 244 + </button> 245 + 246 + <button 247 + class="flex p-2 cursor-pointer w-1/3" 248 + phx-click={JS.dispatch("phx:set-theme")} 249 + data-phx-theme="light" 250 + > 251 + <.icon name="hero-sun-micro" class="size-4 opacity-75 hover:opacity-100" /> 252 + </button> 253 + 254 + <button 255 + class="flex p-2 cursor-pointer w-1/3" 256 + phx-click={JS.dispatch("phx:set-theme")} 257 + data-phx-theme="dark" 258 + > 259 + <.icon name="hero-moon-micro" class="size-4 opacity-75 hover:opacity-100" /> 260 + </button> 261 + </div> 262 + """ 263 + end 264 + 265 + # Embed all files in layouts/* within this module. 266 + # The default root.html.heex file contains the HTML 267 + # skeleton of your application, namely HTML headers 268 + # and other static content. 4 269 embed_templates "layouts/*" 5 270 end
-148
apps/sower/lib/sower_web/components/layouts/app.html.heex
··· 1 - <header> 2 - <nav class="bg-zinc-200 dark:bg-zinc-800 w-full"> 3 - <div class="max-w-screen-xl flex flex-no-wrap items-center justify-between mx-auto p-4"> 4 - <div class="items-center justify-between w-full md:flex md:w-auto md:order-1"> 5 - <ul class="flex flex-col font-medium mt-4 md:space-x-8 rtl:space-x-reverse md:flex-row md:mt-0 md:border-0 "> 6 - <li> 7 - <.link navigate={~p"/"} class="hover:text-orange-700 dark:hover:text-orange-300"> 8 - Home 9 - </.link> 10 - </li> 11 - <li> 12 - <.link navigate={~p"/seeds"} class="hover:text-orange-700 dark:hover:text-orange-300"> 13 - Seeds 14 - </.link> 15 - </li> 16 - <li> 17 - <.link navigate={~p"/agents"} class="hover:text-orange-700 dark:hover:text-orange-300"> 18 - Agents 19 - </.link> 20 - </li> 21 - <li> 22 - <.link 23 - navigate={~p"/nix/caches"} 24 - class="hover:text-orange-700 dark:hover:text-orange-300" 25 - > 26 - Caches 27 - </.link> 28 - </li> 29 - <li> 30 - <.link navigate={~p"/forges"} class="hover:text-orange-700 dark:hover:text-orange-300"> 31 - Forges 32 - </.link> 33 - </li> 34 - </ul> 35 - </div> 36 - 37 - <div class="relative md:order-2 space-x-3 md:space-x-0 rtl:space-x-reverse"> 38 - <%= if @current_user do %> 39 - <button 40 - type="button" 41 - class="flex text-sm bg-zinc-800 rounded-full md:me-0 focus:ring-4 focus:ring-zinc-300 dark:focus:ring-zinc-600" 42 - id="user-menu-button" 43 - aria-expanded="false" 44 - data-dropdown-toggle="user-dropdown" 45 - data-dropdown-placement="bottom" 46 - phx-click={JS.toggle(to: "#user-dropdown")} 47 - phx-click-away={ 48 - JS.hide( 49 - to: "#user-dropdown", 50 - transition: 51 - {"ease-out duration-75", "opacity-100 scale-100", "opacity-0 scale-95"} 52 - ) 53 - } 54 - phx-key="escape" 55 - phx-window-key={ 56 - JS.hide( 57 - to: "#user-dropdown", 58 - transition: 59 - {"ease-out duration-75", "opacity-100 scale-100", "opacity-0 scale-95"} 60 - ) 61 - } 62 - > 63 - <span class="sr-only">Open user menu</span> 64 - <svg 65 - width="24px" 66 - height="24px" 67 - stroke-width="0.5" 68 - viewBox="0 0 24 24" 69 - xmlns="http://www.w3.org/2000/svg" 70 - class="stroke-zinc-900 dark:stroke-zinc-200 fill-zinc-200 dark:fill-zinc-800 hover:fill-orange-300 dark:hover:fill-orange-700" 71 - > 72 - <path 73 - d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2Z" 74 - stroke-width="1.5" 75 - stroke-linecap="round" 76 - stroke-linejoin="round" 77 - > 78 - </path> 79 - <path 80 - d="M4.271 18.3457C4.271 18.3457 6.50002 15.5 12 15.5C17.5 15.5 19.7291 18.3457 19.7291 18.3457" 81 - stroke-width="1.5" 82 - stroke-linecap="round" 83 - stroke-linejoin="round" 84 - > 85 - </path> 86 - <path 87 - d="M12 12C13.6569 12 15 10.6569 15 9C15 7.34315 13.6569 6 12 6C10.3431 6 9 7.34315 9 9C9 10.6569 10.3431 12 12 12Z" 88 - stroke-width="1.5" 89 - stroke-linecap="round" 90 - stroke-linejoin="round" 91 - > 92 - </path> 93 - </svg> 94 - </button> 95 - <div 96 - class="absolute z-[1000] m-0 hidden top-8 right-8 whitespace-nowrap text-base list-none bg-white divide-y divide-zinc-100 rounded-lg shadow dark:bg-zinc-700 dark:divide-zinc-600" 97 - id="user-dropdown" 98 - > 99 - <div class="px-4 py-3"> 100 - <span class="px-3 py-2 text-sm font-medium text-zinc-700 dark:text-zinc-200 rounded-md"> 101 - Hello, {@current_user.name}! 102 - </span> 103 - </div> 104 - <ul class="py-2" aria-labelledby="user-menu-button"> 105 - <li> 106 - <.link 107 - navigate={~p"/settings/access-tokens"} 108 - class="block px-4 py-2 text-sm text-zinc-700 hover:bg-zinc-100 dark:hover:bg-zinc-600 dark:text-zinc-200 dark:hover:text-white" 109 - > 110 - Access Tokens 111 - </.link> 112 - </li> 113 - <li> 114 - <.link 115 - navigate={~p"/settings"} 116 - class="block px-4 py-2 text-sm text-zinc-700 hover:bg-zinc-100 dark:hover:bg-zinc-600 dark:text-zinc-200 dark:hover:text-white" 117 - > 118 - Settings 119 - </.link> 120 - </li> 121 - <li> 122 - <a 123 - href="#" 124 - class="block px-4 py-2 text-sm text-zinc-700 hover:bg-zinc-100 dark:hover:bg-zinc-600 dark:text-zinc-200 dark:hover:text-white" 125 - > 126 - Sign out 127 - </a> 128 - </li> 129 - </ul> 130 - </div> 131 - <% else %> 132 - <.link 133 - navigate={~p"/auth/oidcc"} 134 - class="rounded-lg bg-zinc-100 px-2 py-1 text-[0.8125rem] font-semibold leading-6 text-zinc-900 hover:bg-zinc-200/80 active:text-zinc-900/70" 135 - > 136 - Sign In 137 - </.link> 138 - <% end %> 139 - </div> 140 - </div> 141 - </nav> 142 - </header> 143 - <main class="px-4 py-8 sm:px-6 lg:px-8 relative"> 144 - <div class="mx-auto max-w-6xl"> 145 - <.flash_group flash={@flash} /> 146 - {@inner_content} 147 - </div> 148 - </main>
+3 -3
apps/sower/lib/sower_web/components/layouts/root.html.heex
··· 1 1 <!DOCTYPE html> 2 - <html lang="en" class="[scrollbar-gutter:stable]"> 2 + <html lang="en"> 3 3 <head> 4 4 <meta charset="utf-8" /> 5 - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 5 + <meta name="viewport" content="width=device-width, initial-scale=1" /> 6 6 <meta name="csrf-token" content={get_csrf_token()} /> 7 - <.live_title suffix=" · Phoenix Framework"> 7 + <.live_title default="Sower" suffix=""> 8 8 {assigns[:page_title] || "Sower"} 9 9 </.live_title> 10 10 <link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
+7 -5
apps/sower/lib/sower_web/controllers/page_html/home.html.heex
··· 1 - <div> 2 - <p> 3 - Then he told them many things in parables, saying: “A farmer went out to sow his seed. As he was scattering the seed, some fell along the path, and the birds came and ate it up. Some fell on rocky places, where it did not have much soil. It sprang up quickly, because the soil was shallow. But when the sun came up, the plants were scorched, and they withered because they had no root. Other seed fell among thorns, which grew up and choked the plants. Still other seed fell on good soil, where it produced a crop—a hundred, sixty or thirty times what was sown. Whoever has ears, let them hear.” 4 - </p> 5 - </div> 1 + <Layouts.app flash={@flash}> 2 + <div> 3 + <p> 4 + Then he told them many things in parables, saying: “A farmer went out to sow his seed. As he was scattering the seed, some fell along the path, and the birds came and ate it up. Some fell on rocky places, where it did not have much soil. It sprang up quickly, because the soil was shallow. But when the sun came up, the plants were scorched, and they withered because they had no root. Other seed fell among thorns, which grew up and choked the plants. Still other seed fell on good soil, where it produced a crop—a hundred, sixty or thirty times what was sown. Whoever has ears, let them hear.” 5 + </p> 6 + </div> 7 + </Layouts.app>