-module(glaze@basecoat@theme). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/glaze/basecoat/theme.gleam"). -export([from_list/1, default_theme/0, dark_theme/0, to_list/1, get/2, set/3, set_many/2, tailwind_v4_bridge_css/0, tailwind_v4_bridge_style_tag/0, style_tag/1, style_tag_light_dark/2]). -export_type([token/0, theme/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Theme tokens and \\ generation for Basecoat UI.\n" "\n" " Basecoat uses shadcn/ui compatible CSS variables for theming.\n" " This module provides typed tokens and helpers to generate theme styles.\n" "\n" " ### Example\n" "\n" " ```gleam\n" " import glaze/basecoat\n" " import glaze/basecoat/theme\n" "\n" " let my_theme =\n" " theme.default_theme()\n" " |> theme.set(theme.Primary, \"oklch(0.205 0 0)\")\n" " |> theme.set(theme.Radius, \"0.5rem\")\n" "\n" " html.head([], [\n" " glaze_basecoat.register(glaze_basecoat.version),\n" " theme.style_tag(my_theme),\n" " ])\n" " ```\n" "\n" " ## Theming\n" "\n" " You can use any shadcn/ui theme. Visit [ui.shadcn.com/themes](https://ui.shadcn.com/themes)\n" " to browse available themes and copy their CSS variables.\n" "\n" ). -type token() :: background | foreground | card | card_foreground | popover | popover_foreground | primary | primary_foreground | secondary | secondary_foreground | muted | muted_foreground | accent | accent_foreground | destructive | destructive_foreground | border | input | ring | radius | chart1 | chart2 | chart3 | chart4 | chart5 | sidebar | sidebar_foreground | sidebar_primary | sidebar_primary_foreground | sidebar_accent | sidebar_accent_foreground | sidebar_border | sidebar_ring. -opaque theme() :: {theme, gleam@dict:dict(token(), binary())}. -file("src/glaze/basecoat/theme.gleam", 183). ?DOC( " Construct a `Theme` from a list of token-value pairs.\n" "\n" " If the same token appears multiple times, the last value overrides previous ones.\n" "\n" " ### Example\n" "\n" " ```gleam\n" " let t = theme.from_list([\n" " #(theme.Primary, \"oklch(0.205 0 0)\"),\n" " #(theme.PrimaryForeground, \"oklch(0.985 0 0)\"),\n" " ])\n" " ```\n" ). -spec from_list(list({token(), binary()})) -> theme(). from_list(Tokens) -> Values = gleam@list:fold( Tokens, maps:new(), fun(Acc, Cur) -> {Token, Value} = Cur, gleam@dict:insert(Acc, Token, Value) end ), {theme, Values}. -file("src/glaze/basecoat/theme.gleam", 88). ?DOC( " Returns Basecoat's default theme (shadcn/ui default theme).\n" "\n" " This includes the default color palette and border radius.\n" " Start with this and customize as needed.\n" ). -spec default_theme() -> theme(). default_theme() -> _pipe = [{background, <<"oklch(1 0 0)"/utf8>>}, {foreground, <<"oklch(0.145 0 0)"/utf8>>}, {card, <<"oklch(1 0 0)"/utf8>>}, {card_foreground, <<"oklch(0.145 0 0)"/utf8>>}, {popover, <<"oklch(1 0 0)"/utf8>>}, {popover_foreground, <<"oklch(0.145 0 0)"/utf8>>}, {primary, <<"oklch(0.205 0 0)"/utf8>>}, {primary_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {secondary, <<"oklch(0.97 0 0)"/utf8>>}, {secondary_foreground, <<"oklch(0.205 0 0)"/utf8>>}, {muted, <<"oklch(0.97 0 0)"/utf8>>}, {muted_foreground, <<"oklch(0.556 0 0)"/utf8>>}, {accent, <<"oklch(0.97 0 0)"/utf8>>}, {accent_foreground, <<"oklch(0.205 0 0)"/utf8>>}, {destructive, <<"oklch(0.577 0.245 27.325)"/utf8>>}, {destructive_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {border, <<"oklch(0.922 0 0)"/utf8>>}, {input, <<"oklch(0.922 0 0)"/utf8>>}, {ring, <<"oklch(0.708 0 0)"/utf8>>}, {radius, <<"0.5rem"/utf8>>}, {chart1, <<"oklch(0.646 0.222 41.116)"/utf8>>}, {chart2, <<"oklch(0.6 0.118 184.704)"/utf8>>}, {chart3, <<"oklch(0.398 0.07 227.392)"/utf8>>}, {chart4, <<"oklch(0.828 0.189 84.429)"/utf8>>}, {chart5, <<"oklch(0.769 0.188 70.08)"/utf8>>}, {sidebar, <<"oklch(0.985 0 0)"/utf8>>}, {sidebar_foreground, <<"oklch(0.145 0 0)"/utf8>>}, {sidebar_primary, <<"oklch(0.205 0 0)"/utf8>>}, {sidebar_primary_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {sidebar_accent, <<"oklch(0.97 0 0)"/utf8>>}, {sidebar_accent_foreground, <<"oklch(0.205 0 0)"/utf8>>}, {sidebar_border, <<"oklch(0.922 0 0)"/utf8>>}, {sidebar_ring, <<"oklch(0.708 0 0)"/utf8>>}], from_list(_pipe). -file("src/glaze/basecoat/theme.gleam", 131). ?DOC( " Returns the dark theme variant.\n" "\n" " Use this for dark mode or combine with `default_theme()` using `light-dark()`.\n" ). -spec dark_theme() -> theme(). dark_theme() -> _pipe = [{background, <<"oklch(0.145 0 0)"/utf8>>}, {foreground, <<"oklch(0.985 0 0)"/utf8>>}, {card, <<"oklch(0.205 0 0)"/utf8>>}, {card_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {popover, <<"oklch(0.269 0 0)"/utf8>>}, {popover_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {primary, <<"oklch(0.922 0 0)"/utf8>>}, {primary_foreground, <<"oklch(0.205 0 0)"/utf8>>}, {secondary, <<"oklch(0.269 0 0)"/utf8>>}, {secondary_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {muted, <<"oklch(0.269 0 0)"/utf8>>}, {muted_foreground, <<"oklch(0.708 0 0)"/utf8>>}, {accent, <<"oklch(0.371 0 0)"/utf8>>}, {accent_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {destructive, <<"oklch(0.704 0.191 22.216)"/utf8>>}, {destructive_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {border, <<"oklch(1 0 0 / 10%)"/utf8>>}, {input, <<"oklch(1 0 0 / 15%)"/utf8>>}, {ring, <<"oklch(0.556 0 0)"/utf8>>}, {radius, <<"0.5rem"/utf8>>}, {chart1, <<"oklch(0.488 0.243 264.376)"/utf8>>}, {chart2, <<"oklch(0.696 0.17 162.48)"/utf8>>}, {chart3, <<"oklch(0.769 0.188 70.08)"/utf8>>}, {chart4, <<"oklch(0.627 0.265 303.9)"/utf8>>}, {chart5, <<"oklch(0.645 0.246 16.439)"/utf8>>}, {sidebar, <<"oklch(0.205 0 0)"/utf8>>}, {sidebar_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {sidebar_primary, <<"oklch(0.488 0.243 264.376)"/utf8>>}, {sidebar_primary_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {sidebar_accent, <<"oklch(0.269 0 0)"/utf8>>}, {sidebar_accent_foreground, <<"oklch(0.985 0 0)"/utf8>>}, {sidebar_border, <<"oklch(1 0 0 / 10%)"/utf8>>}, {sidebar_ring, <<"oklch(0.439 0 0)"/utf8>>}], from_list(_pipe). -file("src/glaze/basecoat/theme.gleam", 194). ?DOC(" Convert a `Theme` into token-value pairs.\n"). -spec to_list(theme()) -> list({token(), binary()}). to_list(Theme) -> {theme, Values} = Theme, maps:to_list(Values). -file("src/glaze/basecoat/theme.gleam", 201). ?DOC(" Get a token value from a theme.\n"). -spec get(theme(), token()) -> binary(). get(Theme, Token) -> {theme, Values} = Theme, case gleam_stdlib:map_get(Values, Token) of {ok, Value} -> Value; {error, _} -> <<""/utf8>> end. -file("src/glaze/basecoat/theme.gleam", 211). ?DOC(" Set a token value in a theme.\n"). -spec set(theme(), token(), binary()) -> theme(). set(Theme, Token, Value) -> {theme, Values} = Theme, {theme, gleam@dict:insert(Values, Token, Value)}. -file("src/glaze/basecoat/theme.gleam", 218). ?DOC(" Set multiple token values in a theme.\n"). -spec set_many(theme(), list({token(), binary()})) -> theme(). set_many(Theme, Updates) -> gleam@list:fold( Updates, Theme, fun(Acc, Cur) -> {Token, Value} = Cur, set(Acc, Token, Value) end ). -file("src/glaze/basecoat/theme.gleam", 267). ?DOC( " The Tailwind v4 `@theme` mapping used by Basecoat.\n" "\n" " This matches the `@theme` block in Basecoat's `src/css/basecoat.css`.\n" ). -spec tailwind_v4_bridge_css() -> binary(). tailwind_v4_bridge_css() -> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"@theme {\n"/utf8, " --color-background: var(--background);\n"/utf8>>/binary, " --color-foreground: var(--foreground);\n"/utf8>>/binary, " --color-card: var(--card);\n"/utf8>>/binary, " --color-card-foreground: var(--card-foreground);\n"/utf8>>/binary, " --color-popover: var(--popover);\n"/utf8>>/binary, " --color-popover-foreground: var(--popover-foreground);\n"/utf8>>/binary, " --color-primary: var(--primary);\n"/utf8>>/binary, " --color-primary-foreground: var(--primary-foreground);\n"/utf8>>/binary, " --color-secondary: var(--secondary);\n"/utf8>>/binary, " --color-secondary-foreground: var(--secondary-foreground);\n"/utf8>>/binary, " --color-muted: var(--muted);\n"/utf8>>/binary, " --color-muted-foreground: var(--muted-foreground);\n"/utf8>>/binary, " --color-accent: var(--accent);\n"/utf8>>/binary, " --color-accent-foreground: var(--accent-foreground);\n"/utf8>>/binary, " --color-destructive: var(--destructive);\n"/utf8>>/binary, " --color-border: var(--border);\n"/utf8>>/binary, " --color-input: var(--input);\n"/utf8>>/binary, " --color-ring: var(--ring);\n"/utf8>>/binary, " --color-chart-1: var(--chart-1);\n"/utf8>>/binary, " --color-chart-2: var(--chart-2);\n"/utf8>>/binary, " --color-chart-3: var(--chart-3);\n"/utf8>>/binary, " --color-chart-4: var(--chart-4);\n"/utf8>>/binary, " --color-chart-5: var(--chart-5);\n"/utf8>>/binary, " --color-sidebar: var(--sidebar);\n"/utf8>>/binary, " --color-sidebar-foreground: var(--sidebar-foreground);\n"/utf8>>/binary, " --color-sidebar-primary: var(--sidebar-primary);\n"/utf8>>/binary, " --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);\n"/utf8>>/binary, " --color-sidebar-accent: var(--sidebar-accent);\n"/utf8>>/binary, " --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);\n"/utf8>>/binary, " --color-sidebar-border: var(--sidebar-border);\n"/utf8>>/binary, " --color-sidebar-ring: var(--sidebar-ring);\n"/utf8>>/binary, "}\n"/utf8>>. -file("src/glaze/basecoat/theme.gleam", 259). ?DOC( " Render a `