From beeb4eccafd5b847ec16fab0f26753b8ad98a89b Mon Sep 17 00:00:00 2001 From: APB9785 <74077809+APB9785@users.noreply.github.com> Date: Fri, 13 Dec 2024 18:25:19 -0600 Subject: [PATCH 1/2] Add StationUI --- assets/css/beacon_live_admin.css | 2 + assets/css/station-ui-fonts.css | 153 +++ assets/css/station-ui.css | 111 ++ assets/js/station-ui.js | 45 + assets/tailwind.config.js | 3 + .../live_admin/components/admin_components.ex | 244 +--- .../live_admin/components/station_ui/html.ex | 30 + .../components/station_ui/html/accordion.ex | 142 +++ .../components/station_ui/html/avatar.ex | 239 ++++ .../components/station_ui/html/banner.ex | 72 ++ .../components/station_ui/html/button.ex | 84 ++ .../components/station_ui/html/card.ex | 180 +++ .../components/station_ui/html/footer.ex | 224 ++++ .../components/station_ui/html/form.ex | 100 ++ .../components/station_ui/html/icon.ex | 28 + .../components/station_ui/html/input.ex | 1026 +++++++++++++++++ .../components/station_ui/html/modal.ex | 162 +++ .../components/station_ui/html/navbar.ex | 102 ++ .../station_ui/html/notification_badge.ex | 35 + .../components/station_ui/html/pagination.ex | 224 ++++ .../components/station_ui/html/spinner.ex | 96 ++ .../station_ui/html/status_badge.ex | 38 + .../components/station_ui/html/tab_group.ex | 150 +++ .../components/station_ui/html/table_cell.ex | 44 + .../station_ui/html/table_header.ex | 44 + .../components/station_ui/html/tag.ex | 74 ++ .../components/station_ui/html/toast.ex | 68 ++ .../components/station_ui/html/toolbar.ex | 128 ++ .../components/station_ui/html/tooltip.ex | 34 + lib/beacon/live_admin/page_builder.ex | 1 + lib/beacon/live_admin/web.ex | 1 + 31 files changed, 3643 insertions(+), 241 deletions(-) create mode 100644 assets/css/station-ui-fonts.css create mode 100644 assets/css/station-ui.css create mode 100644 assets/js/station-ui.js create mode 100644 lib/beacon/live_admin/components/station_ui/html.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/accordion.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/avatar.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/banner.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/button.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/card.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/footer.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/form.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/icon.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/input.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/modal.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/navbar.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/notification_badge.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/pagination.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/spinner.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/status_badge.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/tab_group.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/table_cell.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/table_header.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/tag.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/toast.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/toolbar.ex create mode 100644 lib/beacon/live_admin/components/station_ui/html/tooltip.ex diff --git a/assets/css/beacon_live_admin.css b/assets/css/beacon_live_admin.css index 11232c7a..20d37c1a 100644 --- a/assets/css/beacon_live_admin.css +++ b/assets/css/beacon_live_admin.css @@ -1,3 +1,5 @@ +@import "./station-ui.css"; +@import "./station-ui-fonts.css"; @import "tailwindcss/base"; @import "tailwindcss/components"; @import "tailwindcss/utilities"; diff --git a/assets/css/station-ui-fonts.css b/assets/css/station-ui-fonts.css new file mode 100644 index 00000000..9c99519e --- /dev/null +++ b/assets/css/station-ui-fonts.css @@ -0,0 +1,153 @@ +/* Inter-100 */ +@font-face { + font-family: "Inter"; + font-weight: 100; + font-style: normal; + font-display: swap; + src: url("/fonts/inter/Inter-Thin.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/inter/Inter-Thin.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/inter/Inter-Thin.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} + +/* Inter-200 */ +@font-face { + font-family: "Inter"; + font-weight: 200; + font-style: normal; + font-display: swap; + src: url("/fonts/inter/Inter-ExtraLight.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/inter/Inter-ExtraLight.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/inter/Inter-ExtraLight.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} + +/* Inter-300 */ +@font-face { + font-family: "Inter"; + font-weight: 300; + font-style: normal; + font-display: swap; + src: url("/fonts/inter/Inter-Light.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/inter/Inter-Light.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/inter/Inter-Light.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} + +/* Inter-400 */ +@font-face { + font-family: "Inter"; + font-weight: 400; + font-style: normal; + font-display: swap; + src: url("/fonts/inter/Inter-Regular.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/inter/Inter-Regular.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/inter/Inter-Regular.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} + +/* Inter-500 */ +@font-face { + font-family: "Inter"; + font-weight: 500; + font-style: normal; + font-display: swap; + src: url("/fonts/inter/Inter-Medium.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/inter/Inter-Medium.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/inter/Inter-Medium.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} + +/* Inter-600 */ +@font-face { + font-family: "Inter"; + font-weight: 600; + font-style: normal; + font-display: swap; + src: url("/fonts/inter/Inter-SemiBold.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/inter/Inter-SemiBold.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/inter/Inter-SemiBold.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} + +/* Inter-700 */ +@font-face { + font-family: "Inter"; + font-weight: 700; + font-style: normal; + font-display: swap; + src: url("/fonts/inter/Inter-Bold.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/inter/Inter-Bold.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/inter/Inter-Bold.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} + +/* Inter-800 */ +@font-face { + font-family: "Inter"; + font-weight: 800; + font-style: normal; + font-display: swap; + src: url("/fonts/inter/Inter-ExtraBold.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/inter/Inter-ExtraBold.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/inter/Inter-ExtraBold.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} + +/* Inter-900 */ +@font-face { + font-family: "Inter"; + font-weight: 900; + font-style: normal; + font-display: swap; + src: url("/fonts/inter/Inter-Black.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/inter/Inter-Black.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/inter/Inter-Black.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} + +/* roboto-mono-300 - latin_latin-ext */ +@font-face { + font-family: "Roboto Mono"; + font-weight: 300; + font-style: normal; + font-display: swap; + src: url("/fonts/roboto-mono/roboto-mono-v23-latin_latin-ext-300.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/roboto-mono/roboto-mono-v23-latin_latin-ext-300.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/roboto-mono/roboto-mono-v23-latin_latin-ext-300.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} + +/* roboto-mono-500 - latin_latin-ext */ +@font-face { + font-family: "Roboto Mono"; + font-weight: 500; + font-style: normal; + font-display: swap; + src: url("/fonts/roboto-mono/roboto-mono-v23-latin_latin-ext-500.woff2"), + /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */ + url("/fonts/roboto-mono/roboto-mono-v23-latin_latin-ext-500.woff"), + /* Chrome 5+, Firefox 3.6+, IE 9+, Safari 5.1+, iOS 5+ */ + url("/fonts/roboto-mono/roboto-mono-v23-latin_latin-ext-500.ttf"); + /* Chrome 4+, Firefox 3.5+, IE 9+, Safari 3.1+, iOS 4.2+, Android Browser 2.2+ */ +} diff --git a/assets/css/station-ui.css b/assets/css/station-ui.css new file mode 100644 index 00000000..5182614c --- /dev/null +++ b/assets/css/station-ui.css @@ -0,0 +1,111 @@ +@layer base { + :root { + /* primary */ + --sui-brand-primary: theme("colors.indigo.700"); + --sui-brand-primary-bg: theme("colors.indigo.600"); + --sui-brand-primary-bg-disabled: theme("colors.slate.50"); + --sui-brand-primary-muted: theme("colors.indigo.500"); + --sui-brand-primary-shadow: theme("colors.slate.100"); + --sui-brand-primary-text: theme("colors.slate.800"); + --sui-brand-primary-text-inverted: theme("colors.white"); + --sui-brand-primary-text-disabled: theme("colors.slate.300"); + --sui-brand-primary-border: theme("colors.slate.300"); + --sui-brand-primary-border-inverted: theme("colors.slate.600"); + --sui-brand-primary-focus: theme("colors.purple.500"); + --sui-brand-primary-error: theme("colors.rose.500"); + --sui-brand-primary-success: theme("colors.emerald.500"); + --sui-brand-primary-icon: theme("colors.slate.500"); + --sui-brand-primary-icon-inverted: theme("colors.slate.400"); + + /* secondary */ + --sui-brand-secondary-bg: theme("colors.white"); + --sui-brand-secondary-bg-inverted: theme("colors.black"); + --sui-brand-secondary-text: theme("colors.slate.600"); + --sui-brand-secondary-text-muted: theme("colors.gray.500"); + --sui-brand-secondary-text-inverted: theme("colors.slate.400"); + + /* buttons */ + --sui-text-btn-disabled: theme("colors.slate.300"); + --sui-bg-btn-disabled: theme("colors.slate.50"); + --sui-border-btn-disabled: theme("colors.slate.50"); + + /* forms */ + --sui-form-bg-slider-progress: theme("colors.indigo.600"); + --sui-form-bg-slider-progress-disabled: theme("colors.zinc.300"); + --sui-form-bg-slider-thumb: theme("colors.indigo.600"); + --sui-form-bg-slider-thumb-active: theme("colors.indigo.800"); + --sui-form-bg-slider-thumb-disabled: theme("colors.slate.100"); + --sui-form-bg-slider-thumb-hover: theme("colors.indigo.500"); + --sui-form-bg-slider-track: theme("colors.white"); + --sui-form-bg-slider-track-disabled: theme("colors.slate.50"); + --sui-form-border-slider-thumb: theme("colors.indigo.500"); + --sui-form-border-slider-thumb-active: theme("colors.indigo.700"); + --sui-form-border-slider-thumb-disabled: theme("colors.zinc.300"); + --sui-form-border-slider-thumb-hover: theme("colors.indigo.400"); + --sui-form-border-slider-track: theme("colors.gray.400"); + --sui-form-border-slider-track-disabled: theme("colors.zinc.300"); + --sui-form-text: var(--sui-brand-primary-text); + --sui-form-text-disabled: theme("colors.gray.500"); + --sui-form-text-error: theme("colors.rose.700"); + } + + .sui-primary { + --sui-text-btn: theme("colors.white"); + --sui-text-btn-hover: theme("colors.white"); + --sui-text-btn-active: theme("colors.white"); + --sui-bg-btn: theme("colors.indigo.700"); + --sui-bg-btn-hover: theme("colors.indigo.600"); + --sui-bg-btn-active: theme("colors.indigo.800"); + --sui-border-btn: theme("colors.indigo.700"); + --sui-border-btn-hover: theme("colors.indigo.600"); + --sui-border-btn-active: theme("colors.indigo.800"); + } + + .sui-secondary { + --sui-text-btn: theme("colors.slate.800"); + --sui-text-btn-hover: theme("colors.slate.800"); + --sui-text-btn-active: theme("colors.slate.800"); + --sui-bg-btn: theme("colors.white"); + --sui-bg-btn-hover: theme("colors.slate.50"); + --sui-bg-btn-active: theme("colors.slate.200"); + --sui-border-btn: theme("colors.slate.800"); + --sui-border-btn-hover: theme("colors.slate.800"); + --sui-border-btn-active: theme("colors.slate.800"); + } + + .sui-tertiary { + --sui-text-btn: theme("colors.white"); + --sui-text-btn-hover: theme("colors.white"); + --sui-text-btn-active: theme("colors.white"); + --sui-bg-btn: theme("colors.slate.800"); + --sui-bg-btn-hover: theme("colors.slate.700"); + --sui-bg-btn-active: theme("colors.slate.900"); + --sui-border-btn: theme("colors.slate.800"); + --sui-border-btn-hover: theme("colors.slate.700"); + --sui-border-btn-active: theme("colors.slate.900"); + } + + .sui-primary-destructive { + --sui-text-btn: theme("colors.white"); + --sui-text-btn-hover: theme("colors.white"); + --sui-text-btn-active: theme("colors.white"); + --sui-bg-btn: theme("colors.rose.700"); + --sui-bg-btn-hover: theme("colors.rose.600"); + --sui-bg-btn-active: theme("colors.rose.800"); + --sui-border-btn: theme("colors.rose.700"); + --sui-border-btn-hover: theme("colors.rose.600"); + --sui-border-btn-active: theme("colors.rose.800"); + } + + .sui-secondary-destructive { + --sui-text-btn: theme("colors.rose.700"); + --sui-text-btn-hover: theme("colors.rose.600"); + --sui-text-btn-active: theme("colors.rose.800"); + --sui-bg-btn: theme("colors.white"); + --sui-bg-btn-hover: theme("colors.white"); + --sui-bg-btn-active: theme("colors.white"); + --sui-border-btn: theme("colors.rose.700"); + --sui-border-btn-hover: theme("colors.rose.600"); + --sui-border-btn-active: theme("colors.rose.800"); + } +} diff --git a/assets/js/station-ui.js b/assets/js/station-ui.js new file mode 100644 index 00000000..1b6a7954 --- /dev/null +++ b/assets/js/station-ui.js @@ -0,0 +1,45 @@ +// Tailwind CSS presets for Station UI +const defaultTheme = require("tailwindcss/defaultTheme"); + +module.exports = { + theme: { + container: { + center: true, + }, + extend: { + animation: { + "spin-reverse": "spin-reverse 1s linear infinite", + }, + fontFamily: { + sans: ["Inter", ...defaultTheme.fontFamily.sans], + mono: ["Roboto Mono", ...defaultTheme.fontFamily.mono], + }, + boxShadow: { + "inner-sm": "inset 0 1px 2px 0 rgb(0 0 0 / 0.05)", // shadow-sm + "inner-md": + "inset 0 4px 6px -1px rgb(0 0 0 / 0.1), inset 0 2px 4px -2px rgb(0 0 0 / 0.1)", // shadow-md + "inner-lg": + "inset 0 10px 15px -3px rgb(0 0 0 / 0.1), inset 0 4px 6px -4px rgb(0 0 0 / 0.1)", // shadow-lg + "inner-xl": + "inset 0 20px 25px -5px rgb(0 0 0 / 0.1), inset 0 8px 10px -6px rgb(0 0 0 / 0.1)", // shadow-xl + "inner-2xl": "inset 0 25px 50px -12px rgb(0 0 0 / 0.25)", // shadow-2xl + }, + keyframes: { + "spin-reverse": { + from: { + transform: "rotate(360deg)", + }, + }, + }, + spacing: { + 4.5: "1.125rem", //18px + }, + transitionProperty: { + "grid-rows": "grid-template-rows", + }, + } + }, + plugins: [ + require("@tailwindcss/container-queries"), + ] +} diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js index 31e97108..7dcece6e 100644 --- a/assets/tailwind.config.js +++ b/assets/tailwind.config.js @@ -12,6 +12,9 @@ const fs = require("fs") const path = require("path") module.exports = { + presets: [ + require('./js/station-ui.js'), + ], content: ["./js/**/*.js", "../lib/beacon/live_admin/**/*.*ex", "./svelte/**/*.svelte"], theme: { extend: { diff --git a/lib/beacon/live_admin/components/admin_components.ex b/lib/beacon/live_admin/components/admin_components.ex index ecdd2983..ea59b7f6 100644 --- a/lib/beacon/live_admin/components/admin_components.ex +++ b/lib/beacon/live_admin/components/admin_components.ex @@ -14,16 +14,16 @@ defmodule Beacon.LiveAdmin.AdminComponents do import Beacon.LiveAdmin.Router, only: [beacon_live_admin_path: 3] defdelegate header(assigns), to: CoreComponents - defdelegate icon(assigns), to: CoreComponents - defdelegate show_modal(assigns), to: CoreComponents defdelegate hide_modal(assigns), to: CoreComponents defdelegate show(selector), to: CoreComponents defdelegate show(js, selector), to: CoreComponents defdelegate hide(selector), to: CoreComponents defdelegate hide(js, selector), to: CoreComponents - defdelegate translate_error(error), to: CoreComponents defdelegate translate_errors(errors, field), to: CoreComponents + defp icon(assigns), do: Beacon.LiveAdmin.StationUI.HTML.Icon.icon(assigns) + defp input(assigns), do: Beacon.LiveAdmin.CoreComponents.input(assigns) + @menu_link_active_class "inline-block p-4 text-blue-600 border-b-2 border-blue-600 rounded-t-lg active" @menu_link_regular_class "inline-block p-4 border-b-2 border-transparent rounded-t-lg hover:text-gray-600 hover:border-gray-300" @@ -211,58 +211,6 @@ defmodule Beacon.LiveAdmin.AdminComponents do """ end - @doc """ - Renders a modal. - - ## Examples - - <.modal id="confirm-modal"> - This is a modal. - - - JS commands may be passed to the `:on_cancel` to configure - the closing/cancel event, for example: - - <.modal id="confirm" on_cancel={JS.navigate(~p"/posts")}> - This is another modal. - - - """ - attr :id, :string, required: true - attr :show, :boolean, default: false - attr :on_cancel, JS, default: %JS{} - slot :inner_block, required: true - - def modal(assigns) do - ~H""" - - <.focus_wrap - class="relative z-10 pt-0.5" - id={"#{@option_list_id}-wrapper"} - phx-key="escape" - phx-window-keydown={JS.exec("data-close-select", to: "##{@wrapper_id}")} - > + <.focus_wrap class="relative z-10 pt-0.5" id={"#{@option_list_id}-wrapper"} phx-key="escape" phx-window-keydown={JS.exec("data-close-select", to: "##{@wrapper_id}")}>