Packages
phoenix_kit
1.7.173
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
221 Versions
Jump to
Current section
221 Versions
Compare versions
18
files changed
+166
additions
-69
deletions
unknownCHANGELOG.md
File is too large to be displayed (100 KB limit).
| @@ -1,6 +1,6 @@ | |
| 1 1 | {<<"links">>,[{<<"GitHub">>,<<"https://github.com/BeamLabEU/phoenix_kit">>}]}. |
| 2 2 | {<<"name">>,<<"phoenix_kit">>}. |
| 3 | - {<<"version">>,<<"1.7.172">>}. |
| 3 | + {<<"version">>,<<"1.7.173">>}. |
| 4 4 | {<<"description">>, |
| 5 5 | <<65,32,102,111,117,110,100,97,116,105,111,110,32,102,111,114,32,98,117,105, |
| 6 6 | 108,100,105,110,103,32,69,108,105,120,105,114,32,80,104,111,101,110,105, |
| @@ -13,24 +13,35 @@ defmodule PhoenixKit.Migrations.Postgres.V80 do | |
| 13 13 | def up(%{prefix: prefix} = _opts) do |
| 14 14 | p = prefix_str(prefix) |
| 15 15 | |
| 16 | - # Convert template content fields to JSONB |
| 17 | - # Existing string values are preserved as {"en": "original_value"} |
| 18 | - execute(""" |
| 19 | - ALTER TABLE #{p}phoenix_kit_email_templates |
| 20 | - ALTER COLUMN subject TYPE jsonb |
| 21 | - USING jsonb_build_object('en', subject), |
| 22 | - ALTER COLUMN html_body TYPE jsonb |
| 23 | - USING jsonb_build_object('en', html_body), |
| 24 | - ALTER COLUMN text_body TYPE jsonb |
| 25 | - USING jsonb_build_object('en', text_body), |
| 26 | - ALTER COLUMN display_name TYPE jsonb |
| 27 | - USING jsonb_build_object('en', display_name), |
| 28 | - ALTER COLUMN description TYPE jsonb |
| 29 | - USING CASE |
| 30 | - WHEN description IS NULL THEN NULL |
| 31 | - ELSE jsonb_build_object('en', description) |
| 32 | - END |
| 33 | - """) |
| 16 | + # Convert template content fields to JSONB. Guarded on the current type of |
| 17 | + # `subject` (all 5 columns are converted together, so one check covers the |
| 18 | + # group) — without it, re-running this migration against an |
| 19 | + # already-converted database double-wraps the JSONB values |
| 20 | + # (`jsonb_build_object('en', subject)` where `subject` is itself already |
| 21 | + # `{"en": "..."}`). A retry can happen because this version previously |
| 22 | + # didn't record its own "COMMENT ON TABLE ... IS '80'" marker like every |
| 23 | + # other version module does, so a failure later in the same multi-version |
| 24 | + # migration run (disable_ddl_transaction; each step auto-commits) would |
| 25 | + # cause a subsequent `mix ecto.migrate` to resume from V80 again. |
| 26 | + if column_type(prefix, "phoenix_kit_email_templates", "subject") != "jsonb" do |
| 27 | + # Existing string values are preserved as {"en": "original_value"} |
| 28 | + execute(""" |
| 29 | + ALTER TABLE #{p}phoenix_kit_email_templates |
| 30 | + ALTER COLUMN subject TYPE jsonb |
| 31 | + USING jsonb_build_object('en', subject), |
| 32 | + ALTER COLUMN html_body TYPE jsonb |
| 33 | + USING jsonb_build_object('en', html_body), |
| 34 | + ALTER COLUMN text_body TYPE jsonb |
| 35 | + USING jsonb_build_object('en', text_body), |
| 36 | + ALTER COLUMN display_name TYPE jsonb |
| 37 | + USING jsonb_build_object('en', display_name), |
| 38 | + ALTER COLUMN description TYPE jsonb |
| 39 | + USING CASE |
| 40 | + WHEN description IS NULL THEN NULL |
| 41 | + ELSE jsonb_build_object('en', description) |
| 42 | + END |
| 43 | + """) |
| 44 | + end |
| 34 45 | |
| 35 46 | # Add locale tracking to email logs |
| 36 47 | execute(""" |
| @@ -42,6 +53,8 @@ defmodule PhoenixKit.Migrations.Postgres.V80 do | |
| 42 53 | CREATE INDEX IF NOT EXISTS idx_email_logs_locale |
| 43 54 | ON #{p}phoenix_kit_email_logs (locale) |
| 44 55 | """) |
| 56 | + |
| 57 | + execute("COMMENT ON TABLE #{p}phoenix_kit IS '80'") |
| 45 58 | end |
| 46 59 | |
| 47 60 | def down(%{prefix: prefix} = _opts) do |
| @@ -68,6 +81,22 @@ defmodule PhoenixKit.Migrations.Postgres.V80 do | |
| 68 81 | ALTER TABLE #{p}phoenix_kit_email_logs |
| 69 82 | DROP COLUMN IF EXISTS locale |
| 70 83 | """) |
| 84 | + |
| 85 | + execute("COMMENT ON TABLE #{p}phoenix_kit IS '79'") |
| 86 | + end |
| 87 | + |
| 88 | + defp column_type(prefix, table, column) do |
| 89 | + schema = prefix || "public" |
| 90 | + |
| 91 | + query = """ |
| 92 | + SELECT data_type FROM information_schema.columns |
| 93 | + WHERE table_schema = '#{schema}' AND table_name = '#{table}' AND column_name = '#{column}' |
| 94 | + """ |
| 95 | + |
| 96 | + case repo().query(query, [], log: false) do |
| 97 | + {:ok, %{rows: [[data_type]]}} -> data_type |
| 98 | + _ -> nil |
| 99 | + end |
| 71 100 | end |
| 72 101 | |
| 73 102 | defp prefix_str(nil), do: "" |
| @@ -7,6 +7,8 @@ defmodule PhoenixKit.ThemeConfig do | |
| 7 7 | theme requires changing this module and the shared CSS asset only. |
| 8 8 | """ |
| 9 9 | |
| 10 | + use Gettext, backend: PhoenixKitWeb.Gettext |
| 11 | + |
| 10 12 | @default_html_theme "phoenix-light" |
| 11 13 | |
| 12 14 | @custom_theme_variables %{ |
| @@ -99,6 +101,65 @@ defmodule PhoenixKit.ThemeConfig do | |
| 99 101 | "silk" => "Silk" |
| 100 102 | } |
| 101 103 | |
| 104 | + @doc """ |
| 105 | + Returns the translated, user-facing label for a theme key. |
| 106 | + |
| 107 | + `@labels` is a compile-time module attribute, so it can't hold macro-expanded |
| 108 | + `gettext/1` calls directly — this function is the translated counterpart, |
| 109 | + with one literal `gettext/1` call per theme so `mix gettext.extract` can |
| 110 | + find them. |
| 111 | + """ |
| 112 | + def translated_label("system"), do: gettext("System") |
| 113 | + def translated_label("phoenix-light"), do: gettext("Phoenix Light") |
| 114 | + def translated_label("phoenix-dark"), do: gettext("Phoenix Dark") |
| 115 | + def translated_label("light"), do: gettext("Light") |
| 116 | + def translated_label("dark"), do: gettext("Dark") |
| 117 | + def translated_label("cupcake"), do: gettext("Cupcake") |
| 118 | + def translated_label("bumblebee"), do: gettext("Bumblebee") |
| 119 | + def translated_label("emerald"), do: gettext("Emerald") |
| 120 | + def translated_label("corporate"), do: gettext("Corporate") |
| 121 | + def translated_label("synthwave"), do: gettext("Synthwave") |
| 122 | + def translated_label("retro"), do: gettext("Retro") |
| 123 | + def translated_label("cyberpunk"), do: gettext("Cyberpunk") |
| 124 | + def translated_label("valentine"), do: gettext("Valentine") |
| 125 | + def translated_label("halloween"), do: gettext("Halloween") |
| 126 | + def translated_label("garden"), do: gettext("Garden") |
| 127 | + def translated_label("forest"), do: gettext("Forest") |
| 128 | + def translated_label("aqua"), do: gettext("Aqua") |
| 129 | + def translated_label("lofi"), do: gettext("Lo-Fi") |
| 130 | + def translated_label("pastel"), do: gettext("Pastel") |
| 131 | + def translated_label("fantasy"), do: gettext("Fantasy") |
| 132 | + def translated_label("wireframe"), do: gettext("Wireframe") |
| 133 | + def translated_label("black"), do: gettext("Black") |
| 134 | + def translated_label("luxury"), do: gettext("Luxury") |
| 135 | + def translated_label("dracula"), do: gettext("Dracula") |
| 136 | + def translated_label("cmyk"), do: gettext("CMYK") |
| 137 | + def translated_label("autumn"), do: gettext("Autumn") |
| 138 | + def translated_label("business"), do: gettext("Business") |
| 139 | + def translated_label("acid"), do: gettext("Acid") |
| 140 | + def translated_label("lemonade"), do: gettext("Lemonade") |
| 141 | + def translated_label("night"), do: gettext("Night") |
| 142 | + def translated_label("coffee"), do: gettext("Coffee") |
| 143 | + def translated_label("winter"), do: gettext("Winter") |
| 144 | + def translated_label("dim"), do: gettext("Dim") |
| 145 | + def translated_label("nord"), do: gettext("Nord") |
| 146 | + def translated_label("sunset"), do: gettext("Sunset") |
| 147 | + def translated_label("caramellatte"), do: gettext("Caramel Latte") |
| 148 | + def translated_label("abyss"), do: gettext("Abyss") |
| 149 | + def translated_label("silk"), do: gettext("Silk") |
| 150 | + def translated_label(theme), do: Map.get(@labels, theme, theme) |
| 151 | + |
| 152 | + @doc """ |
| 153 | + Returns a map of theme names to translated, user-facing labels. |
| 154 | + |
| 155 | + Same shape as `label_map/0` but locale-aware — use this (not |
| 156 | + `label_map/0`) for anything rendered to a user, including client-side JS |
| 157 | + embeds built from a JSON-encoded map. |
| 158 | + """ |
| 159 | + def translated_label_map do |
| 160 | + Map.new(@labels, fn {key, _label} -> {key, translated_label(key)} end) |
| 161 | + end |
| 162 | + |
| 102 163 | @dropdown_order [ |
| 103 164 | "system", |
| 104 165 | "phoenix-light", |
| @@ -299,7 +360,7 @@ defmodule PhoenixKit.ThemeConfig do | |
| 299 360 | defp theme_to_map(theme) do |
| 300 361 | %{ |
| 301 362 | value: theme, |
| 302 | - label: Map.fetch!(@labels, theme), |
| 363 | + label: translated_label(theme), |
| 303 364 | preview_theme: Map.get(@preview_themes, theme), |
| 304 365 | type: if(theme == "system", do: :system, else: :theme) |
| 305 366 | } |
| @@ -449,7 +449,7 @@ defmodule PhoenixKitWeb.Components.LayoutWrapper do | |
| 449 449 | |
| 450 450 | // Theme configuration and controller |
| 451 451 | const themeBaseMap = <%= ThemeConfig.base_map() |> Phoenix.json_library().encode!() |> Phoenix.HTML.raw() %>; |
| 452 | - const themeLabels = <%= ThemeConfig.label_map() |> Phoenix.json_library().encode!() |> Phoenix.HTML.raw() %>; |
| 452 | + const themeLabels = <%= ThemeConfig.translated_label_map() |> Phoenix.json_library().encode!() |> Phoenix.HTML.raw() %>; |
| 453 453 | |
| 454 454 | // Admin theme controller for PhoenixKit with animated slider |
| 455 455 | const adminThemeController = { |
Loading more files…