Deployment and lifecycle management for Nix
0
fork

Configure Feed

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

web: standardize buttons with variant system

Add variant attr (:primary, :secondary, :danger, :icon) to the button
component and convert all raw <button> tags to use <.button>. All action
buttons now share consistent sizing (rounded-md, px-3 py-1.5) and the
bordered outline style. Deploy, Retry, and View log all use :secondary.

+71 -40
+31 -6
apps/sower/lib/sower_web/components/core_components.ex
··· 73 73 class="shadow-zinc-700/10 ring-zinc-700/10 relative hidden rounded-2xl bg-zinc-200 dark:bg-zinc-300 p-14 shadow-lg ring-1 transition" 74 74 > 75 75 <div class="absolute top-6 right-5"> 76 - <button 76 + <.button 77 + variant={:icon} 77 78 phx-click={JS.exec("data-cancel", to: "##{@id}")} 78 79 type="button" 79 80 class="-m-3 flex-none p-3 opacity-20 hover:opacity-40" 80 81 aria-label={gettext("close")} 81 82 > 82 83 <.icon name="hero-x-mark-solid" class="h-5 w-5" /> 83 - </button> 84 + </.button> 84 85 </div> 85 86 <div id={"#{@id}-content"}> 86 87 {render_slot(@inner_block)} ··· 129 130 {@title} 130 131 </p> 131 132 <p class="mt-2 text-sm leading-5">{msg}</p> 132 - <button type="button" class="group absolute top-1 right-1 p-2" aria-label={gettext("close")}> 133 + <.button variant={:icon} type="button" class="group absolute top-1 right-1 p-2" aria-label={gettext("close")}> 133 134 <.icon name="hero-x-mark-solid" class="h-5 w-5 opacity-40 group-hover:opacity-70" /> 134 - </button> 135 + </.button> 135 136 </div> 136 137 """ 137 138 end ··· 179 180 180 181 <.button>Send!</.button> 181 182 <.button phx-click="go" class="ml-2">Send!</.button> 183 + <.button variant={:secondary}>Toggle</.button> 184 + <.button variant={:danger}>Delete</.button> 185 + <.button variant={:icon}><.icon name="hero-x-mark" /></.button> 182 186 """ 183 187 attr :type, :string, default: nil 188 + attr :variant, :atom, default: :primary, values: [:primary, :secondary, :danger, :icon] 184 189 attr :class, :string, default: nil 185 190 attr :rest, :global, include: ~w(disabled form name value) 186 191 ··· 191 196 <button 192 197 type={@type} 193 198 class={[ 194 - "phx-submit-loading:opacity-75 text-zinc-100 bg-zinc-500 dark:text-zinc-200 dark:bg-zinc-600 hover:text-zinc-800 hover:bg-orange-500 dark:hover:text-zinc-800 dark:hover:bg-orange-500 py-2 px-3 rounded", 195 - "text-sm font-semibold leading-6 text-white active:text-white/80", 199 + button_base_class(@variant), 200 + button_variant_class(@variant), 196 201 @class 197 202 ]} 198 203 {@rest} ··· 201 206 </button> 202 207 """ 203 208 end 209 + 210 + defp button_base_class(:icon), do: "cursor-pointer disabled:opacity-50" 211 + 212 + defp button_base_class(_variant) do 213 + "phx-submit-loading:opacity-75 rounded-md px-3 py-1.5 text-sm font-semibold leading-6 disabled:opacity-50" 214 + end 215 + 216 + defp button_variant_class(:primary) do 217 + "border border-zinc-600 dark:border-zinc-500 text-zinc-100 bg-zinc-500 dark:text-zinc-200 dark:bg-zinc-600 hover:text-zinc-800 hover:bg-orange-500 dark:hover:text-zinc-800 dark:hover:bg-orange-500 active:text-white/80" 218 + end 219 + 220 + defp button_variant_class(:secondary) do 221 + "border border-zinc-300 dark:border-zinc-600 text-zinc-700 dark:text-zinc-200 hover:bg-zinc-50 dark:hover:bg-zinc-800" 222 + end 223 + 224 + defp button_variant_class(:danger) do 225 + "border border-red-600 dark:border-red-500 text-white bg-red-500 dark:bg-red-500 hover:bg-red-600 dark:hover:bg-red-600 active:text-white/80" 226 + end 227 + 228 + defp button_variant_class(:icon), do: "" 204 229 205 230 @doc """ 206 231 Renders an input with label and error messages.
+17 -16
apps/sower/lib/sower_web/components/layouts.ex
··· 113 113 114 114 <div class="relative flex shrink-0 items-center md:order-2 md:space-x-0 rtl:space-x-reverse"> 115 115 <%= if @current_user || nil do %> 116 - <button 116 + <.button 117 + variant={:icon} 117 118 type="button" 118 119 class="flex text-sm bg-zinc-800 rounded-full md:me-0 focus:ring-4 focus:ring-zinc-300 dark:focus:ring-zinc-600" 119 120 id="user-menu-button" ··· 168 169 > 169 170 </path> 170 171 </svg> 171 - </button> 172 + </.button> 172 173 <div 173 174 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" 174 175 id="user-dropdown" ··· 206 207 </ul> 207 208 </div> 208 209 <% else %> 209 - <.link 210 - navigate={~p"/auth/oidcc"} 211 - class="inline-flex shrink-0 whitespace-nowrap 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" 212 - > 213 - Sign In 210 + <.link navigate={~p"/auth/oidcc"}> 211 + <.button variant={:secondary}>Sign In</.button> 214 212 </.link> 215 213 <% end %> 216 214 </div> ··· 300 298 <div class="card relative flex flex-row items-center border-2 border-base-300 bg-base-300 rounded-full"> 301 299 <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]" /> 302 300 303 - <button 304 - class="flex p-2 cursor-pointer w-1/3" 301 + <.button 302 + variant={:icon} 303 + class="flex p-2 w-1/3" 305 304 phx-click={JS.dispatch("phx:set-theme")} 306 305 data-phx-theme="system" 307 306 > 308 307 <.icon name="hero-computer-desktop-micro" class="size-4 opacity-75 hover:opacity-100" /> 309 - </button> 308 + </.button> 310 309 311 - <button 312 - class="flex p-2 cursor-pointer w-1/3" 310 + <.button 311 + variant={:icon} 312 + class="flex p-2 w-1/3" 313 313 phx-click={JS.dispatch("phx:set-theme")} 314 314 data-phx-theme="light" 315 315 > 316 316 <.icon name="hero-sun-micro" class="size-4 opacity-75 hover:opacity-100" /> 317 - </button> 317 + </.button> 318 318 319 - <button 320 - class="flex p-2 cursor-pointer w-1/3" 319 + <.button 320 + variant={:icon} 321 + class="flex p-2 w-1/3" 321 322 phx-click={JS.dispatch("phx:set-theme")} 322 323 data-phx-theme="dark" 323 324 > 324 325 <.icon name="hero-moon-micro" class="size-4 opacity-75 hover:opacity-100" /> 325 - </button> 326 + </.button> 326 327 </div> 327 328 """ 328 329 end
+1
apps/sower/lib/sower_web/components/sower_components.ex
··· 294 294 <div class="inline-flex items-center gap-2"> 295 295 <.button 296 296 :if={@deployable} 297 + variant={:secondary} 297 298 type="button" 298 299 phx-click="deploy_subscription" 299 300 phx-value-subscription_sid={@subscription_sid}
+3 -3
apps/sower/lib/sower_web/live/agent_live/show.html.heex
··· 124 124 <.local_datetime datetime={deployment.inserted_at} user_timezone={@user_timezone} /> 125 125 </:col> 126 126 <:action :let={deployment}> 127 - <button 127 + <.button 128 128 :if={deployment.state in [:completed, :stale]} 129 + variant={:secondary} 129 130 type="button" 130 131 phx-click="retry_deployment" 131 132 phx-value-deployment_sid={deployment.sid} 132 133 phx-stop-propagation 133 134 phx-disable-with="Retrying..." 134 - class="text-sm text-zinc-700 dark:text-zinc-200 hover:text-orange-500 dark:hover:text-orange-400 disabled:opacity-50" 135 135 disabled={@retrying_deployment == deployment.sid} 136 136 > 137 137 Retry 138 - </button> 138 + </.button> 139 139 </:action> 140 140 </.table> 141 141 <p
+4 -3
apps/sower/lib/sower_web/live/deployment_live/index.ex
··· 36 36 <.local_datetime datetime={deployment.deployed_at} user_timezone={@user_timezone} /> 37 37 </:col> 38 38 <:action :let={{_id, deployment}}> 39 - <button 39 + <.button 40 40 :if={retryable?(deployment)} 41 + variant={:secondary} 41 42 type="button" 42 43 phx-click="retry" 43 44 phx-value-sid={deployment.sid} 44 45 phx-stop-propagation 45 46 phx-disable-with="Retrying..." 46 - class="hidden sm:inline text-sm text-zinc-700 dark:text-zinc-200 hover:text-orange-500 dark:hover:text-orange-400 disabled:opacity-50" 47 + class="hidden sm:inline" 47 48 disabled={@retrying_deployment_sid == deployment.sid} 48 49 > 49 50 Retry 50 - </button> 51 + </.button> 51 52 </:action> 52 53 </.table> 53 54 </Layouts.app>
+4 -3
apps/sower/lib/sower_web/live/deployment_live/show.ex
··· 15 15 <:actions> 16 16 <.button 17 17 :if={retryable?(@deployment)} 18 + variant={:secondary} 18 19 type="button" 19 20 phx-click="retry" 20 21 phx-disable-with="Retrying..." ··· 89 90 state={:completed} 90 91 result={sd.result} 91 92 /> 92 - <button 93 + <.button 93 94 :if={sd.log} 95 + variant={:secondary} 94 96 type="button" 95 97 phx-click="toggle_seed_log" 96 98 phx-value-seed_sid={sd.seed.sid} 97 - class="rounded-md border border-zinc-300 dark:border-zinc-600 px-3 py-1.5 text-sm text-zinc-700 dark:text-zinc-200 hover:bg-zinc-50 dark:hover:bg-zinc-800" 98 99 > 99 100 {if expanded_seed_log?(@expanded_seed_logs, sd.seed.sid), 100 101 do: "Hide log", 101 102 else: "View log"} 102 - </button> 103 + </.button> 103 104 </div> 104 105 </div> 105 106 <pre
+4 -4
apps/sower/lib/sower_web/live/forge/connection_live/show.html.heex
··· 25 25 <.table id="repositories" rows={@connection.repositories}> 26 26 <:col :let={repository}>{repository.owner}/{repository.repo}</:col> 27 27 <:action :let={repository}> 28 - <button phx-click={JS.push("remove_repo", value: %{repo_id: repository.id})}> 28 + <.button variant={:secondary} phx-click={JS.push("remove_repo", value: %{repo_id: repository.id})}> 29 29 Remove Repository 30 - </button> 30 + </.button> 31 31 </:action> 32 32 </.table> 33 33 </:item> ··· 36 36 <.table :if={@logged_in} id="repositories" rows={@repositories} row_click={false}> 37 37 <:col :let={repository}>{repository["full_name"]}</:col> 38 38 <:action :let={repository}> 39 - <button phx-click={JS.push("add_repo", value: repository)}> 39 + <.button variant={:secondary} phx-click={JS.push("add_repo", value: repository)}> 40 40 Add Repository 41 - </button> 41 + </.button> 42 42 </:action> 43 43 </.table> 44 44
+6 -4
apps/sower/lib/sower_web/live/settings/access_token_live/form_component.ex
··· 40 40 type="select" 41 41 options={Sower.Accounts.AccessToken.permission_roles()} 42 42 /> 43 - <button 43 + <.button 44 + variant={:icon} 44 45 type="button" 45 46 name="access_token[permissions_drop][]" 46 47 value={perm.index} 47 48 phx-click={JS.dispatch("change")} 48 49 > 49 50 <.icon name="hero-x-mark" class="w-6 h-6 relative top-2" /> 50 - </button> 51 + </.button> 51 52 </.inputs_for> 52 53 53 54 <input type="hidden" name="access_token[permissions_drop][]" /> 54 55 55 56 <:actions> 56 - <button 57 + <.button 58 + variant={:secondary} 57 59 type="button" 58 60 name="access_token[permissions_sort][]" 59 61 value="new" 60 62 phx-click={JS.dispatch("change")} 61 63 > 62 64 add permission 63 - </button> 65 + </.button> 64 66 <.button phx-disable-with="Saving...">Save</.button> 65 67 </:actions> 66 68 </.simple_form>
+1 -1
apps/sower/lib/sower_web/live/settings/access_token_live/show.html.heex
··· 12 12 phx-click={JS.push("delete", value: %{id: @access_token.id})} 13 13 data-confirm="Are you sure?" 14 14 > 15 - <.button class="bg-red-500 dark:bg-red-500">Delete</.button> 15 + <.button variant={:danger}>Delete</.button> 16 16 </.link> 17 17 </:actions> 18 18 </.header>