kiso 0.3.0.pre → 0.4.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -1
  3. data/README.md +16 -3
  4. data/app/assets/tailwind/kiso/engine.css +4 -3
  5. data/app/assets/tailwind/kiso/palettes/blue.css +65 -0
  6. data/app/assets/tailwind/kiso/palettes/green.css +65 -0
  7. data/app/assets/tailwind/kiso/palettes/orange.css +65 -0
  8. data/app/assets/tailwind/kiso/palettes/violet.css +65 -0
  9. data/app/assets/tailwind/kiso/palettes/zinc.css +65 -0
  10. data/app/helpers/kiso/app_component_helper.rb +53 -0
  11. data/app/helpers/kiso/component_helper.rb +110 -24
  12. data/app/helpers/kiso/ui_context_helper.rb +59 -0
  13. data/app/javascript/controllers/kiso/alert_controller.js +33 -0
  14. data/app/javascript/controllers/kiso/index.js +3 -0
  15. data/app/views/kiso/components/_alert.html.erb +19 -3
  16. data/app/views/kiso/components/_alert_dialog.html.erb +2 -2
  17. data/app/views/kiso/components/_app.html.erb +7 -0
  18. data/app/views/kiso/components/_avatar.html.erb +3 -3
  19. data/app/views/kiso/components/_breadcrumb.html.erb +1 -1
  20. data/app/views/kiso/components/_color_mode_button.html.erb +1 -1
  21. data/app/views/kiso/components/_color_mode_select.html.erb +4 -4
  22. data/app/views/kiso/components/_container.html.erb +7 -0
  23. data/app/views/kiso/components/_dashboard_sidebar.html.erb +1 -1
  24. data/app/views/kiso/components/_dialog.html.erb +2 -2
  25. data/app/views/kiso/components/_footer.html.erb +7 -0
  26. data/app/views/kiso/components/_header.html.erb +7 -0
  27. data/app/views/kiso/components/_main.html.erb +7 -0
  28. data/app/views/kiso/components/_page.html.erb +7 -0
  29. data/app/views/kiso/components/_page_body.html.erb +7 -0
  30. data/app/views/kiso/components/_page_card.html.erb +40 -0
  31. data/app/views/kiso/components/_page_grid.html.erb +7 -0
  32. data/app/views/kiso/components/_page_header.html.erb +38 -0
  33. data/app/views/kiso/components/_page_section.html.erb +11 -0
  34. data/app/views/kiso/components/_pagination.html.erb +1 -1
  35. data/app/views/kiso/components/_select_native.html.erb +3 -3
  36. data/app/views/kiso/components/_skeleton.html.erb +5 -0
  37. data/app/views/kiso/components/_slider.html.erb +4 -4
  38. data/app/views/kiso/components/_switch.html.erb +2 -2
  39. data/app/views/kiso/components/alert/_actions.html.erb +7 -0
  40. data/app/views/kiso/components/breadcrumb/_ellipsis.html.erb +1 -1
  41. data/app/views/kiso/components/combobox/_input.html.erb +1 -1
  42. data/app/views/kiso/components/combobox/_item.html.erb +2 -2
  43. data/app/views/kiso/components/combobox/_list.html.erb +2 -1
  44. data/app/views/kiso/components/command/_group.html.erb +2 -2
  45. data/app/views/kiso/components/command/_input.html.erb +3 -2
  46. data/app/views/kiso/components/command/_list.html.erb +2 -1
  47. data/app/views/kiso/components/dashboard_navbar/_toggle.html.erb +1 -1
  48. data/app/views/kiso/components/dashboard_sidebar/_collapse.html.erb +1 -1
  49. data/app/views/kiso/components/dashboard_sidebar/_toggle.html.erb +1 -1
  50. data/app/views/kiso/components/dialog/_close.html.erb +1 -1
  51. data/app/views/kiso/components/nav/_item.html.erb +2 -2
  52. data/app/views/kiso/components/nav/_section.html.erb +5 -5
  53. data/app/views/kiso/components/page/_center.html.erb +7 -0
  54. data/app/views/kiso/components/page/_left.html.erb +7 -0
  55. data/app/views/kiso/components/page/_right.html.erb +7 -0
  56. data/app/views/kiso/components/page_card/_body.html.erb +7 -0
  57. data/app/views/kiso/components/page_card/_description.html.erb +7 -0
  58. data/app/views/kiso/components/page_card/_footer.html.erb +7 -0
  59. data/app/views/kiso/components/page_card/_header.html.erb +7 -0
  60. data/app/views/kiso/components/page_card/_icon.html.erb +7 -0
  61. data/app/views/kiso/components/page_card/_title.html.erb +7 -0
  62. data/app/views/kiso/components/page_header/_description.html.erb +7 -0
  63. data/app/views/kiso/components/page_header/_headline.html.erb +7 -0
  64. data/app/views/kiso/components/page_header/_links.html.erb +7 -0
  65. data/app/views/kiso/components/page_header/_title.html.erb +7 -0
  66. data/app/views/kiso/components/page_section/_body.html.erb +7 -0
  67. data/app/views/kiso/components/page_section/_description.html.erb +7 -0
  68. data/app/views/kiso/components/page_section/_header.html.erb +7 -0
  69. data/app/views/kiso/components/page_section/_headline.html.erb +7 -0
  70. data/app/views/kiso/components/page_section/_links.html.erb +7 -0
  71. data/app/views/kiso/components/page_section/_title.html.erb +7 -0
  72. data/app/views/kiso/components/page_section/_wrapper.html.erb +7 -0
  73. data/app/views/kiso/components/pagination/_ellipsis.html.erb +1 -1
  74. data/app/views/kiso/components/pagination/_next.html.erb +2 -2
  75. data/app/views/kiso/components/pagination/_previous.html.erb +2 -2
  76. data/app/views/kiso/components/select/_item.html.erb +2 -2
  77. data/config/locales/en.yml +33 -0
  78. data/lib/generators/kiso/component/USAGE +35 -0
  79. data/lib/generators/kiso/component/component_generator.rb +104 -0
  80. data/lib/generators/kiso/component/templates/partial.html.erb.tt +7 -0
  81. data/lib/generators/kiso/component/templates/sub_part_partial.html.erb.tt +7 -0
  82. data/lib/generators/kiso/component/templates/sub_part_theme.rb.tt +21 -0
  83. data/lib/generators/kiso/component/templates/theme.rb.tt +21 -0
  84. data/lib/kiso/configuration.rb +40 -0
  85. data/lib/kiso/engine.rb +105 -1
  86. data/lib/kiso/presets/rounded.rb +136 -0
  87. data/lib/kiso/presets/sharp.rb +178 -0
  88. data/lib/kiso/presets.rb +49 -0
  89. data/lib/kiso/theme_overrides.rb +5 -1
  90. data/lib/kiso/themes/alert.rb +24 -11
  91. data/lib/kiso/themes/dashboard.rb +1 -1
  92. data/lib/kiso/themes/layout.rb +69 -0
  93. data/lib/kiso/themes/page.rb +295 -0
  94. data/lib/kiso/themes/skeleton.rb +16 -0
  95. data/lib/kiso/version.rb +1 -1
  96. data/lib/kiso.rb +7 -0
  97. metadata +63 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17ae0456b44e65c4a1f0c0fc7a0fb854daca4af8bf933d13d0fa2a3e78dc0b5d
4
- data.tar.gz: 5dad006edca36a6d23822274557de73667eb8bd8aa69aa575037859ed1983742
3
+ metadata.gz: ce3df9a9c977207d60d0253493414495486682817829e7afb9c3ea4f856756b2
4
+ data.tar.gz: ea280bd1479c2bfe90a8fdd3fe597efe1a88c427031f096b24536a02c3558899
5
5
  SHA512:
6
- metadata.gz: 490e5777fbc1fd030736c6c7866b3e39855699d7f71be28af41c9fc6bb2cbd7fd6b793d9d302e35886908ce663ddcc98e171ffd1c3419eebf8c6577073276c12
7
- data.tar.gz: caa47f1734d26450d7163108cefa70438d75e8ef1201ffc1b4123eb4e5bb5e22aa5f7b545fddad657235d79d18e62aacb05818b6f0aa87922baa20c2d3d66bbb
6
+ metadata.gz: 34279aa5743e7baf516464c98ab5984de8edace8789646cb2277270ba5320f8b5763849141a4c2ddeee85f42d23c21638bcc4d11dcb0dd0f34792b09c8efa217
7
+ data.tar.gz: 8da0d3477b660de7fc174da7a7a1608e39783bd763b428f570beaf4385b301fa5eb9105384a87ff61791d09bab655ad3882c148f39d93f6c8402149c0fbfbac8
data/CHANGELOG.md CHANGED
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.0.pre] - 2026-03-08
11
+
12
+ ### Added
13
+
14
+ - Layout component family: App, Container (4 size variants), Header, Footer, Main
15
+ - Page component family: Page (grid with sidebars), PageHeader, PageBody, PageSection, PageGrid, PageCard (4 variants)
16
+ - `appui()` helper for host app components with `app/themes/` and `app/views/components/`
17
+ - `kiso:framework_component` generator for scaffolding engine components
18
+ - `kiso:component` generator for scaffolding host app components
19
+ - Theme presets: `apply_preset(:rounded)` and `apply_preset(:sharp)`
20
+ - 5 OKLCH color palettes (zinc, blue, green, orange, violet)
21
+ - i18n support: all component strings use `t()` with `config/locales/en.yml`
22
+ - [Building Your Own Components](/guide/building-components) guide — how to wrap Kiso components with domain logic and build standalone components with `appui()`, themes, and sub-parts
23
+ - [Detailed release notes](/releases/batch-merge) with upgrade guide and examples for all new features
24
+
10
25
  ## [0.3.0.pre] - 2026-03-03
11
26
 
12
27
  ### Added
@@ -85,7 +100,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
85
100
  - Lookbook component previews
86
101
  - Bridgetown documentation site
87
102
 
88
- [Unreleased]: https://github.com/steveclarke/kiso/compare/v0.3.0.pre...HEAD
103
+ [Unreleased]: https://github.com/steveclarke/kiso/compare/v0.4.0.pre...HEAD
104
+ [0.4.0.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.4.0.pre
89
105
  [0.3.0.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.3.0.pre
90
106
  [0.2.2.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.2.2.pre
91
107
  [0.2.1.pre]: https://github.com/steveclarke/kiso/releases/tag/v0.2.1.pre
data/README.md CHANGED
@@ -1,6 +1,19 @@
1
- # Kiso 基礎
2
-
3
- UI components for Rails. Built on ERB, Tailwind CSS, and Hotwire.
1
+ <p align="center">
2
+ <a href="https://kisoui.com">
3
+ <img src="brand/svg/logo-horizontal-color.svg" width="280" alt="Kiso">
4
+ </a>
5
+ </p>
6
+
7
+ <p align="center">
8
+ UI components for Rails. Built on ERB, Tailwind CSS, and Hotwire.
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://kisoui.com">Docs</a> ·
13
+ <a href="https://lookbook.kisoui.com">Lookbook</a> ·
14
+ <a href="https://github.com/steveclarke/kiso/discussions">Discussions</a> ·
15
+ <a href="https://discord.gg/aMshcWAW">Discord</a>
16
+ </p>
4
17
 
5
18
  Add one gem and get badges, buttons, cards, alerts, and more. They all work with screen readers and dark mode.
6
19
 
@@ -16,7 +16,8 @@
16
16
  Count carefully — wrong paths fail SILENTLY (classes just won't generate). */
17
17
  @source "../../../views"; /* → app/views */
18
18
  @source "../../../helpers"; /* → app/helpers */
19
- @source "../../../../lib/kiso/themes"; /* → lib/kiso/themes */
19
+ @source "../../../../lib/kiso/themes"; /* → lib/kiso/themes */
20
+ @source "../../../../lib/kiso/presets"; /* → lib/kiso/presets */
20
21
 
21
22
  /* === Geist Font (by Vercel) ===
22
23
  Self-hosted variable fonts — no CDN dependency.
@@ -56,7 +57,7 @@
56
57
 
57
58
  @theme {
58
59
  /* Brand / action colors */
59
- --color-primary: var(--color-sky-600);
60
+ --color-primary: var(--color-rose-500);
60
61
  --color-primary-foreground: white;
61
62
 
62
63
  --color-secondary: var(--color-teal-600);
@@ -99,7 +100,7 @@
99
100
  Redefine tokens under .dark — components never use dark: prefixes. */
100
101
 
101
102
  .dark {
102
- --color-primary: var(--color-blue-400);
103
+ --color-primary: var(--color-rose-400);
103
104
  --color-primary-foreground: var(--color-zinc-950);
104
105
 
105
106
  --color-secondary: var(--color-teal-400);
@@ -0,0 +1,65 @@
1
+ /* Kiso Color Palette: Blue
2
+ A professional blue palette — classic SaaS/enterprise feel.
3
+ Based on shadcn/ui's Blue theme with OKLCH color values.
4
+
5
+ Usage:
6
+ 1. Import in your CSS: @import "kiso/palettes/blue.css";
7
+ 2. Add to your HTML: <html data-palette="blue"> or <body data-palette="blue">
8
+ */
9
+
10
+ [data-palette="blue"] {
11
+ /* Brand / action colors — vibrant blue */
12
+ --color-primary: oklch(0.488 0.243 264.376);
13
+ --color-primary-foreground: oklch(0.97 0.014 254.604);
14
+
15
+ --color-secondary: oklch(0.967 0.001 286.375);
16
+ --color-secondary-foreground: oklch(0.21 0.006 285.885);
17
+
18
+ /* Surface tokens — slate-tinted neutrals */
19
+ --color-background: oklch(1 0 0);
20
+ --color-foreground: oklch(0.13 0.028 261.692);
21
+
22
+ --color-muted: oklch(0.967 0.003 264.542);
23
+ --color-muted-foreground: oklch(0.551 0.027 264.364);
24
+
25
+ --color-accent: oklch(0.967 0.003 264.542);
26
+ --color-accent-foreground: oklch(0.21 0.034 264.665);
27
+
28
+ --color-inverted: oklch(0.21 0.034 264.665);
29
+ --color-inverted-foreground: oklch(0.985 0.002 247.839);
30
+ --color-elevated: oklch(0.967 0.003 264.542);
31
+ --color-accented: oklch(0.707 0.022 261.325);
32
+
33
+ --color-border: oklch(0.928 0.006 264.531);
34
+ --color-border-accented: oklch(0.707 0.022 261.325);
35
+
36
+ --color-ring: oklch(0.488 0.243 264.376);
37
+ }
38
+
39
+ .dark [data-palette="blue"],
40
+ [data-palette="blue"].dark {
41
+ --color-primary: oklch(0.42 0.18 266);
42
+ --color-primary-foreground: oklch(0.97 0.014 254.604);
43
+
44
+ --color-secondary: oklch(0.274 0.006 286.033);
45
+ --color-secondary-foreground: oklch(0.985 0 0);
46
+
47
+ --color-background: oklch(0.13 0.028 261.692);
48
+ --color-foreground: oklch(0.985 0.002 247.839);
49
+
50
+ --color-muted: oklch(0.278 0.033 256.848);
51
+ --color-muted-foreground: oklch(0.707 0.022 261.325);
52
+
53
+ --color-accent: oklch(0.278 0.033 256.848);
54
+ --color-accent-foreground: oklch(0.985 0.002 247.839);
55
+
56
+ --color-inverted: oklch(0.985 0.002 247.839);
57
+ --color-inverted-foreground: oklch(0.21 0.034 264.665);
58
+ --color-elevated: oklch(0.278 0.033 256.848);
59
+ --color-accented: oklch(0.551 0.027 264.364);
60
+
61
+ --color-border: oklch(0.278 0.033 256.848);
62
+ --color-border-accented: oklch(0.551 0.027 264.364);
63
+
64
+ --color-ring: oklch(0.488 0.243 264.376);
65
+ }
@@ -0,0 +1,65 @@
1
+ /* Kiso Color Palette: Green
2
+ A fresh, natural green palette — great for eco, health, or finance apps.
3
+ Based on shadcn/ui's Green theme with OKLCH color values.
4
+
5
+ Usage:
6
+ 1. Import in your CSS: @import "kiso/palettes/green.css";
7
+ 2. Add to your HTML: <html data-palette="green"> or <body data-palette="green">
8
+ */
9
+
10
+ [data-palette="green"] {
11
+ /* Brand / action colors — vivid green */
12
+ --color-primary: oklch(0.648 0.2 131.684);
13
+ --color-primary-foreground: oklch(0.986 0.031 120.757);
14
+
15
+ --color-secondary: oklch(0.967 0.001 286.375);
16
+ --color-secondary-foreground: oklch(0.21 0.006 285.885);
17
+
18
+ /* Surface tokens — zinc neutrals */
19
+ --color-background: oklch(1 0 0);
20
+ --color-foreground: oklch(0.141 0.005 285.823);
21
+
22
+ --color-muted: oklch(0.967 0.001 286.375);
23
+ --color-muted-foreground: oklch(0.552 0.016 285.938);
24
+
25
+ --color-accent: oklch(0.967 0.001 286.375);
26
+ --color-accent-foreground: oklch(0.21 0.006 285.885);
27
+
28
+ --color-inverted: oklch(0.21 0.006 285.885);
29
+ --color-inverted-foreground: oklch(0.985 0 0);
30
+ --color-elevated: oklch(0.967 0.001 286.375);
31
+ --color-accented: oklch(0.705 0.015 286.067);
32
+
33
+ --color-border: oklch(0.92 0.004 286.32);
34
+ --color-border-accented: oklch(0.705 0.015 286.067);
35
+
36
+ --color-ring: oklch(0.648 0.2 131.684);
37
+ }
38
+
39
+ .dark [data-palette="green"],
40
+ [data-palette="green"].dark {
41
+ --color-primary: oklch(0.648 0.2 131.684);
42
+ --color-primary-foreground: oklch(0.986 0.031 120.757);
43
+
44
+ --color-secondary: oklch(0.274 0.006 286.033);
45
+ --color-secondary-foreground: oklch(0.985 0 0);
46
+
47
+ --color-background: oklch(0.141 0.005 285.823);
48
+ --color-foreground: oklch(0.985 0 0);
49
+
50
+ --color-muted: oklch(0.274 0.006 286.033);
51
+ --color-muted-foreground: oklch(0.705 0.015 286.067);
52
+
53
+ --color-accent: oklch(0.274 0.006 286.033);
54
+ --color-accent-foreground: oklch(0.985 0 0);
55
+
56
+ --color-inverted: oklch(0.985 0 0);
57
+ --color-inverted-foreground: oklch(0.21 0.006 285.885);
58
+ --color-elevated: oklch(0.274 0.006 286.033);
59
+ --color-accented: oklch(0.552 0.016 285.938);
60
+
61
+ --color-border: oklch(0.274 0.006 286.033);
62
+ --color-border-accented: oklch(0.552 0.016 285.938);
63
+
64
+ --color-ring: oklch(0.648 0.2 131.684);
65
+ }
@@ -0,0 +1,65 @@
1
+ /* Kiso Color Palette: Orange
2
+ A warm, energetic palette — great for creative, food, or community apps.
3
+ Based on shadcn/ui's Orange theme with OKLCH color values.
4
+
5
+ Usage:
6
+ 1. Import in your CSS: @import "kiso/palettes/orange.css";
7
+ 2. Add to your HTML: <html data-palette="orange"> or <body data-palette="orange">
8
+ */
9
+
10
+ [data-palette="orange"] {
11
+ /* Brand / action colors — warm orange */
12
+ --color-primary: oklch(0.646 0.222 41.116);
13
+ --color-primary-foreground: oklch(0.98 0.016 73.684);
14
+
15
+ --color-secondary: oklch(0.97 0.001 106.424);
16
+ --color-secondary-foreground: oklch(0.216 0.006 56.043);
17
+
18
+ /* Surface tokens — warm stone neutrals */
19
+ --color-background: oklch(1 0 0);
20
+ --color-foreground: oklch(0.147 0.004 49.25);
21
+
22
+ --color-muted: oklch(0.97 0.001 106.424);
23
+ --color-muted-foreground: oklch(0.553 0.013 58.071);
24
+
25
+ --color-accent: oklch(0.97 0.001 106.424);
26
+ --color-accent-foreground: oklch(0.216 0.006 56.043);
27
+
28
+ --color-inverted: oklch(0.216 0.006 56.043);
29
+ --color-inverted-foreground: oklch(0.985 0.001 106.423);
30
+ --color-elevated: oklch(0.97 0.001 106.424);
31
+ --color-accented: oklch(0.709 0.01 56.259);
32
+
33
+ --color-border: oklch(0.923 0.003 48.717);
34
+ --color-border-accented: oklch(0.709 0.01 56.259);
35
+
36
+ --color-ring: oklch(0.646 0.222 41.116);
37
+ }
38
+
39
+ .dark [data-palette="orange"],
40
+ [data-palette="orange"].dark {
41
+ --color-primary: oklch(0.705 0.213 47.604);
42
+ --color-primary-foreground: oklch(0.98 0.016 73.684);
43
+
44
+ --color-secondary: oklch(0.268 0.007 34.298);
45
+ --color-secondary-foreground: oklch(0.985 0.001 106.423);
46
+
47
+ --color-background: oklch(0.147 0.004 49.25);
48
+ --color-foreground: oklch(0.985 0.001 106.423);
49
+
50
+ --color-muted: oklch(0.268 0.007 34.298);
51
+ --color-muted-foreground: oklch(0.709 0.01 56.259);
52
+
53
+ --color-accent: oklch(0.268 0.007 34.298);
54
+ --color-accent-foreground: oklch(0.985 0.001 106.423);
55
+
56
+ --color-inverted: oklch(0.985 0.001 106.423);
57
+ --color-inverted-foreground: oklch(0.216 0.006 56.043);
58
+ --color-elevated: oklch(0.268 0.007 34.298);
59
+ --color-accented: oklch(0.553 0.013 58.071);
60
+
61
+ --color-border: oklch(0.268 0.007 34.298);
62
+ --color-border-accented: oklch(0.553 0.013 58.071);
63
+
64
+ --color-ring: oklch(0.705 0.213 47.604);
65
+ }
@@ -0,0 +1,65 @@
1
+ /* Kiso Color Palette: Violet
2
+ A rich, creative purple palette — great for design tools or premium brands.
3
+ Based on shadcn/ui's Violet theme with OKLCH color values.
4
+
5
+ Usage:
6
+ 1. Import in your CSS: @import "kiso/palettes/violet.css";
7
+ 2. Add to your HTML: <html data-palette="violet"> or <body data-palette="violet">
8
+ */
9
+
10
+ [data-palette="violet"] {
11
+ /* Brand / action colors — vivid violet */
12
+ --color-primary: oklch(0.541 0.281 293.009);
13
+ --color-primary-foreground: oklch(0.969 0.016 293.756);
14
+
15
+ --color-secondary: oklch(0.967 0.001 286.375);
16
+ --color-secondary-foreground: oklch(0.21 0.006 285.885);
17
+
18
+ /* Surface tokens — gray neutrals */
19
+ --color-background: oklch(1 0 0);
20
+ --color-foreground: oklch(0.13 0.028 261.692);
21
+
22
+ --color-muted: oklch(0.967 0.003 264.542);
23
+ --color-muted-foreground: oklch(0.551 0.027 264.364);
24
+
25
+ --color-accent: oklch(0.967 0.003 264.542);
26
+ --color-accent-foreground: oklch(0.21 0.034 264.665);
27
+
28
+ --color-inverted: oklch(0.21 0.034 264.665);
29
+ --color-inverted-foreground: oklch(0.985 0.002 247.839);
30
+ --color-elevated: oklch(0.967 0.003 264.542);
31
+ --color-accented: oklch(0.707 0.022 261.325);
32
+
33
+ --color-border: oklch(0.928 0.006 264.531);
34
+ --color-border-accented: oklch(0.707 0.022 261.325);
35
+
36
+ --color-ring: oklch(0.541 0.281 293.009);
37
+ }
38
+
39
+ .dark [data-palette="violet"],
40
+ [data-palette="violet"].dark {
41
+ --color-primary: oklch(0.606 0.25 292.717);
42
+ --color-primary-foreground: oklch(0.969 0.016 293.756);
43
+
44
+ --color-secondary: oklch(0.274 0.006 286.033);
45
+ --color-secondary-foreground: oklch(0.985 0 0);
46
+
47
+ --color-background: oklch(0.13 0.028 261.692);
48
+ --color-foreground: oklch(0.985 0.002 247.839);
49
+
50
+ --color-muted: oklch(0.278 0.033 256.848);
51
+ --color-muted-foreground: oklch(0.707 0.022 261.325);
52
+
53
+ --color-accent: oklch(0.278 0.033 256.848);
54
+ --color-accent-foreground: oklch(0.985 0.002 247.839);
55
+
56
+ --color-inverted: oklch(0.985 0.002 247.839);
57
+ --color-inverted-foreground: oklch(0.21 0.034 264.665);
58
+ --color-elevated: oklch(0.278 0.033 256.848);
59
+ --color-accented: oklch(0.551 0.027 264.364);
60
+
61
+ --color-border: oklch(0.278 0.033 256.848);
62
+ --color-border-accented: oklch(0.551 0.027 264.364);
63
+
64
+ --color-ring: oklch(0.606 0.25 292.717);
65
+ }
@@ -0,0 +1,65 @@
1
+ /* Kiso Color Palette: Zinc
2
+ A neutral, cool-toned palette using the Zinc scale.
3
+ Based on shadcn/ui's Zinc theme with OKLCH color values.
4
+
5
+ Usage:
6
+ 1. Import in your CSS: @import "kiso/palettes/zinc.css";
7
+ 2. Add to your HTML: <html data-palette="zinc"> or <body data-palette="zinc">
8
+ */
9
+
10
+ [data-palette="zinc"] {
11
+ /* Brand / action colors — zinc primary (near-black in light, near-white in dark) */
12
+ --color-primary: oklch(0.21 0.006 285.885);
13
+ --color-primary-foreground: oklch(0.985 0 0);
14
+
15
+ --color-secondary: oklch(0.967 0.001 286.375);
16
+ --color-secondary-foreground: oklch(0.21 0.006 285.885);
17
+
18
+ /* Surface tokens */
19
+ --color-background: oklch(1 0 0);
20
+ --color-foreground: oklch(0.141 0.005 285.823);
21
+
22
+ --color-muted: oklch(0.967 0.001 286.375);
23
+ --color-muted-foreground: oklch(0.552 0.016 285.938);
24
+
25
+ --color-accent: oklch(0.967 0.001 286.375);
26
+ --color-accent-foreground: oklch(0.21 0.006 285.885);
27
+
28
+ --color-inverted: oklch(0.21 0.006 285.885);
29
+ --color-inverted-foreground: oklch(0.985 0 0);
30
+ --color-elevated: oklch(0.967 0.001 286.375);
31
+ --color-accented: oklch(0.705 0.015 286.067);
32
+
33
+ --color-border: oklch(0.92 0.004 286.32);
34
+ --color-border-accented: oklch(0.705 0.015 286.067);
35
+
36
+ --color-ring: oklch(0.705 0.015 286.067);
37
+ }
38
+
39
+ .dark [data-palette="zinc"],
40
+ [data-palette="zinc"].dark {
41
+ --color-primary: oklch(0.92 0.004 286.32);
42
+ --color-primary-foreground: oklch(0.21 0.006 285.885);
43
+
44
+ --color-secondary: oklch(0.274 0.006 286.033);
45
+ --color-secondary-foreground: oklch(0.985 0 0);
46
+
47
+ --color-background: oklch(0.141 0.005 285.823);
48
+ --color-foreground: oklch(0.985 0 0);
49
+
50
+ --color-muted: oklch(0.274 0.006 286.033);
51
+ --color-muted-foreground: oklch(0.705 0.015 286.067);
52
+
53
+ --color-accent: oklch(0.274 0.006 286.033);
54
+ --color-accent-foreground: oklch(0.985 0 0);
55
+
56
+ --color-inverted: oklch(0.985 0 0);
57
+ --color-inverted-foreground: oklch(0.21 0.006 285.885);
58
+ --color-elevated: oklch(0.274 0.006 286.033);
59
+ --color-accented: oklch(0.552 0.016 285.938);
60
+
61
+ --color-border: oklch(0.274 0.006 286.033);
62
+ --color-border-accented: oklch(0.552 0.016 285.938);
63
+
64
+ --color-ring: oklch(0.552 0.016 285.938);
65
+ }
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kiso
4
+ # View helpers for rendering host app components.
5
+ #
6
+ # Mirrors {ComponentHelper#kui} but resolves partials from
7
+ # +app/views/components/+ and themes from +AppThemes::+.
8
+ # No global config layer — host apps own the source directly.
9
+ #
10
+ # Included in all views automatically by {Engine}.
11
+ module AppComponentHelper
12
+ # Renders a host app component partial.
13
+ #
14
+ # Components live in +app/views/components/+. Sub-parts are nested
15
+ # in a directory matching the parent component name.
16
+ #
17
+ # @param component [Symbol] the component name (e.g. +:pricing_card+)
18
+ # @param part [Symbol, nil] optional sub-part name (e.g. +:header+, +:footer+)
19
+ # @param collection [Array, nil] renders the partial once per item when present
20
+ # @param ui [Hash{Symbol => String}, nil] per-slot class overrides keyed by sub-part name.
21
+ # For parent components, the hash is pushed onto a context stack so sub-parts
22
+ # inherit overrides automatically. For self-rendering components, the hash is
23
+ # also passed as a local so the partial can apply overrides to internally
24
+ # rendered elements.
25
+ # @param kwargs [Hash] locals passed to the partial (e.g. +css_classes:+)
26
+ # @yield optional block for component content
27
+ # @return [ActiveSupport::SafeBuffer] rendered HTML
28
+ #
29
+ # @example Render a pricing card
30
+ # appui(:pricing_card) { "Content" }
31
+ #
32
+ # @example Render a pricing card with sub-parts
33
+ # appui(:pricing_card) do
34
+ # appui(:pricing_card, :header) { "Header" }
35
+ # end
36
+ #
37
+ # @example Render with per-slot overrides
38
+ # appui(:pricing_card, ui: { header: "p-8" }) do
39
+ # appui(:pricing_card, :header) { "Header" }
40
+ # end
41
+ #
42
+ # @example Render a collection
43
+ # appui(:pricing_card, collection: @plans)
44
+ def appui(component, part = nil, collection: nil, ui: nil, **kwargs, &block)
45
+ kiso_render_component(
46
+ component, part,
47
+ path_prefix: "components",
48
+ collection: collection, ui: ui, merge_global_ui: false,
49
+ **kwargs, &block
50
+ )
51
+ end
52
+ end
53
+ end
@@ -11,6 +11,11 @@ module Kiso
11
11
  # @param component [Symbol] the component name (e.g. +:badge+, +:card+)
12
12
  # @param part [Symbol, nil] optional sub-part name (e.g. +:header+, +:footer+)
13
13
  # @param collection [Array, nil] renders the partial once per item when present
14
+ # @param ui [Hash{Symbol => String}, nil] per-slot class overrides keyed by sub-part name.
15
+ # For parent components, the hash is pushed onto a context stack so sub-parts
16
+ # inherit overrides automatically. For self-rendering components, the hash is
17
+ # also passed as a local so the partial can apply overrides to internally
18
+ # rendered elements.
14
19
  # @param kwargs [Hash] locals passed to the partial (e.g. +color:+, +variant:+, +css_classes:+)
15
20
  # @yield optional block for component content
16
21
  # @return [ActiveSupport::SafeBuffer] rendered HTML
@@ -18,33 +23,25 @@ module Kiso
18
23
  # @example Render a badge
19
24
  # kui(:badge, color: :success, variant: :soft) { "Active" }
20
25
  #
21
- # @example Render a card sub-part
22
- # kui(:card, :header) { "Title" }
26
+ # @example Render a card with per-slot overrides
27
+ # kui(:card, ui: { header: "p-8", title: "text-xl" }) do
28
+ # kui(:card, :header) do
29
+ # kui(:card, :title) { "Dashboard" }
30
+ # end
31
+ # end
32
+ #
33
+ # @example Render an alert with inner element overrides
34
+ # kui(:alert, icon: "info", ui: { close: "opacity-50" })
23
35
  #
24
36
  # @example Render a collection
25
37
  # kui(:badge, collection: @tags)
26
- def kui(component, part = nil, collection: nil, **kwargs, &block)
27
- path = if part
28
- "kiso/components/#{component}/#{part}"
29
- else
30
- "kiso/components/#{component}"
31
- end
32
-
33
- # Prevent yield from bubbling up the ERB rendering chain when no block
34
- # is passed. Without this, partials that use `capture { yield }.presence`
35
- # to support optional block overrides (e.g., toggle/collapse/separator)
36
- # would have their `yield` bubble through nested content_tag blocks all
37
- # the way to the layout's `<%= yield %>`, capturing the entire page
38
- # template content. An explicit empty proc gives `yield` something to
39
- # call, returning empty string → `.presence` returns nil → default
40
- # content renders correctly.
41
- block ||= proc {}
42
-
43
- if collection
44
- render partial: path, collection: collection, locals: kwargs, &block
45
- else
46
- render path, **kwargs, &block
47
- end
38
+ def kui(component, part = nil, collection: nil, ui: nil, **kwargs, &block)
39
+ kiso_render_component(
40
+ component, part,
41
+ path_prefix: "kiso/components",
42
+ collection: collection, ui: ui, merge_global_ui: true,
43
+ **kwargs, &block
44
+ )
48
45
  end
49
46
 
50
47
  # Prepares +component_options+ for use with +content_tag+.
@@ -72,5 +69,94 @@ module Kiso
72
69
 
73
70
  (component_options.delete(:data) || {}).merge(slot: slot, **data_attrs)
74
71
  end
72
+
73
+ private
74
+
75
+ # Shared rendering pipeline for both kui() and appui().
76
+ #
77
+ # @param component [Symbol] the component name
78
+ # @param part [Symbol, nil] optional sub-part name
79
+ # @param path_prefix [String] partial path prefix (e.g. "kiso/components" or "components")
80
+ # @param collection [Array, nil] renders the partial once per item when present
81
+ # @param ui [Hash, nil] per-slot class overrides
82
+ # @param merge_global_ui [Boolean] whether to merge global config ui layer
83
+ # @param kwargs [Hash] locals passed to the partial
84
+ # @param block [Proc] optional block for component content
85
+ # @return [ActiveSupport::SafeBuffer] rendered HTML
86
+ def kiso_render_component(component, part, path_prefix:, collection:, ui:, merge_global_ui: true, **kwargs, &block)
87
+ path = if part
88
+ "#{path_prefix}/#{component}/#{part}"
89
+ else
90
+ "#{path_prefix}/#{component}"
91
+ end
92
+
93
+ # Prevent yield from bubbling up the ERB rendering chain when no block
94
+ # is passed. Without this, partials that use `capture { yield }.presence`
95
+ # to support optional block overrides (e.g., toggle/collapse/separator)
96
+ # would have their `yield` bubble through nested content_tag blocks all
97
+ # the way to the layout's `<%= yield %>`, capturing the entire page
98
+ # template content. An explicit empty proc gives `yield` something to
99
+ # call, returning empty string → `.presence` returns nil → default
100
+ # content renders correctly.
101
+ block ||= proc {}
102
+
103
+ if part
104
+ # Sub-part: merge slot override from parent's ui context
105
+ parent_ui = kiso_current_ui(component)
106
+ if (slot_classes = parent_ui[part].presence)
107
+ existing = kwargs[:css_classes] || ""
108
+ kwargs[:css_classes] = existing.blank? ? slot_classes : "#{existing} #{slot_classes}"
109
+ end
110
+
111
+ # Forward ui: to sub-part partial when explicitly provided
112
+ kwargs[:ui] = ui if ui
113
+
114
+ if collection
115
+ render partial: path, collection: collection, locals: kwargs, &block
116
+ else
117
+ render path, **kwargs, &block
118
+ end
119
+ else
120
+ # Parent component: merge global ui config with instance ui (or use instance ui directly)
121
+ merged_ui = if merge_global_ui
122
+ kiso_merge_ui_layers(component, ui)
123
+ else
124
+ ui || {}
125
+ end
126
+ has_ui = merged_ui.present?
127
+
128
+ # Push context for composed sub-parts to read (skip when empty)
129
+ kiso_push_ui_context(component, merged_ui) if has_ui
130
+ begin
131
+ locals = has_ui ? kwargs.merge(ui: merged_ui) : kwargs
132
+
133
+ if collection
134
+ render partial: path, collection: collection, locals: locals, &block
135
+ else
136
+ render path, **locals, &block
137
+ end
138
+ ensure
139
+ kiso_pop_ui_context(component) if has_ui
140
+ end
141
+ end
142
+ end
143
+
144
+ # Merge global config ui overrides with instance ui overrides.
145
+ # Global config is Layer 2, instance +ui:+ is Layer 3.
146
+ #
147
+ # @param component [Symbol] the component name
148
+ # @param instance_ui [Hash, nil] per-instance ui overrides
149
+ # @return [Hash{Symbol => String}] merged ui hash
150
+ def kiso_merge_ui_layers(component, instance_ui)
151
+ global_ui = Kiso.config.theme.dig(component, :ui)
152
+ return instance_ui || {} if global_ui.nil? || global_ui.empty?
153
+ return global_ui if instance_ui.nil? || instance_ui.empty?
154
+
155
+ # Instance wins. For slots in both, concatenate — tailwind_merge
156
+ # resolves conflicts when .render(class:) is called.
157
+ global_ui.merge(instance_ui) do |_slot, global_classes, instance_classes|
158
+ "#{global_classes} #{instance_classes}"
159
+ end
160
+ end
75
161
  end
76
162
  end