|
2 | 2 |
|
3 | 3 | module ApiPublic |
4 | 4 | module V1 |
5 | | - # ThemeController provides theming configuration for headless frontends |
6 | | - # Returns CSS variables, colors, and fonts for dynamic theme injection |
| 5 | + # Public API endpoint for theme configuration |
| 6 | + # Returns complete theme data including colors, fonts, and CSS |
7 | 7 | class ThemeController < BaseController |
| 8 | + |
| 9 | + # GET /api_public/v1/theme |
| 10 | + # Returns theme configuration for the current website |
| 11 | + # |
| 12 | + # Query Parameters: |
| 13 | + # - locale: optional locale code (e.g., "en", "es") |
| 14 | + # |
| 15 | + # Response: |
| 16 | + # { |
| 17 | + # "theme": { |
| 18 | + # "name": "brisbane", |
| 19 | + # "palette_id": "ocean_blue", |
| 20 | + # "colors": { |
| 21 | + # "primary_color": "#3B82F6", |
| 22 | + # "secondary_color": "#10B981", |
| 23 | + # ... |
| 24 | + # }, |
| 25 | + # "fonts": { |
| 26 | + # "heading": "Playfair Display", |
| 27 | + # "body": "Inter" |
| 28 | + # }, |
| 29 | + # "dark_mode": { |
| 30 | + # "enabled": true, |
| 31 | + # "setting": "auto" |
| 32 | + # }, |
| 33 | + # "css_variables": ":root { --primary-color: #3B82F6; ... }" |
| 34 | + # } |
| 35 | + # } |
8 | 36 | def index |
9 | | - website = Pwb::Current.website |
| 37 | + locale = params[:locale] |
| 38 | + I18n.locale = locale if locale.present? |
10 | 39 |
|
| 40 | + website = Pwb::Current.website |
| 41 | + |
11 | 42 | render json: { |
12 | | - data: { |
13 | | - theme_name: website.theme_name, |
14 | | - dark_mode: website.dark_mode_setting, |
15 | | - colors: website.style_variables, |
16 | | - css_variables: website.css_variables, |
17 | | - css_with_dark_mode: website.css_variables_with_dark_mode, |
18 | | - fonts: extract_fonts(website), |
19 | | - palette: { |
20 | | - selected: website.selected_palette, |
21 | | - available: website.available_palettes.keys |
22 | | - } |
23 | | - } |
| 43 | + theme: build_theme_response(website) |
24 | 44 | } |
25 | 45 | end |
26 | 46 |
|
27 | 47 | private |
28 | 48 |
|
| 49 | + def build_theme_response(website) |
| 50 | + { |
| 51 | + name: website.theme_name || "default", |
| 52 | + palette_id: website.effective_palette_id, |
| 53 | + palette_mode: website.respond_to?(:palette_mode) ? (website.palette_mode || "dynamic") : "dynamic", |
| 54 | + colors: website.style_variables, |
| 55 | + fonts: extract_fonts(website), |
| 56 | + border_radius: extract_border_radius(website), |
| 57 | + dark_mode: build_dark_mode_config(website), |
| 58 | + css_variables: website.css_variables_with_dark_mode, |
| 59 | + custom_css: website.respond_to?(:raw_css) ? website.raw_css : nil |
| 60 | + } |
| 61 | + end |
| 62 | + |
29 | 63 | def extract_fonts(website) |
30 | | - vars = website.style_variables || {} |
| 64 | + vars = website.style_variables |
| 65 | + { |
| 66 | + heading: vars["font_primary"] || vars["font_secondary"] || "Inter", |
| 67 | + body: vars["font_primary"] || "Inter" |
| 68 | + } |
| 69 | + end |
| 70 | + |
| 71 | + def extract_border_radius(website) |
| 72 | + vars = website.style_variables |
| 73 | + base_radius = vars["border_radius"] || "0.5rem" |
| 74 | + |
| 75 | + { |
| 76 | + sm: "calc(#{base_radius} * 0.5)", |
| 77 | + md: base_radius, |
| 78 | + lg: "calc(#{base_radius} * 1.5)", |
| 79 | + xl: "calc(#{base_radius} * 2)" |
| 80 | + } |
| 81 | + end |
| 82 | + |
| 83 | + def build_dark_mode_config(website) |
31 | 84 | { |
32 | | - primary: vars["font_primary"] || "Open Sans", |
33 | | - secondary: vars["font_secondary"] || "Vollkorn" |
| 85 | + enabled: website.dark_mode_enabled?, |
| 86 | + setting: website.dark_mode_setting, |
| 87 | + force_dark: website.force_dark_mode?, |
| 88 | + auto: website.auto_dark_mode? |
34 | 89 | } |
35 | 90 | end |
36 | 91 | end |
|
0 commit comments