nitro_kit 2.0.0.alpha.3 → 2.0.0.alpha.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +179 -0
- data/README.md +22 -26
- data/STYLE_GUIDE.md +10 -0
- data/app/assets/stylesheets/nitro_kit-tailwind-v4.css +3 -3
- data/app/assets/stylesheets/nitro_kit.css +1220 -572
- data/app/components/nitro_kit/accordion.rb +1 -19
- data/app/components/nitro_kit/alert.rb +1 -11
- data/app/components/nitro_kit/app_navigation.rb +44 -9
- data/app/components/nitro_kit/appearance_picker.rb +10 -1
- data/app/components/nitro_kit/badge.rb +13 -4
- data/app/components/nitro_kit/combobox.rb +1 -17
- data/app/components/nitro_kit/command_palette.rb +1 -0
- data/app/components/nitro_kit/dropzone.rb +1 -1
- data/app/components/nitro_kit/form_builder.rb +1 -1
- data/app/components/nitro_kit/select.rb +1 -14
- data/app/components/nitro_kit/tabs.rb +1 -0
- data/app/javascript/controllers/nk/command_palette_controller.js +4 -0
- data/app/javascript/controllers/nk/tabs_controller.js +13 -1
- data/docs/agent_guide.md +63 -138
- data/docs/agent_native_spec.md +72 -400
- data/docs/browser_support.md +77 -188
- data/docs/component_contracts.md +56 -36
- data/docs/customization.md +675 -89
- data/docs/hotwire.md +61 -99
- data/docs/initialization_prompt.md +27 -57
- data/docs/migration_1_to_2.md +34 -18
- data/docs/patterns/application_foundation.md +45 -121
- data/docs/patterns/crud_resource.md +44 -129
- data/docs/patterns/destructive_action.md +45 -102
- data/docs/patterns/flash_and_toast.md +18 -36
- data/docs/patterns/inline_edit.md +21 -44
- data/docs/patterns/queryable_collection.md +65 -161
- data/docs/patterns/resource_form.md +33 -81
- data/docs/rails_conventions.md +38 -78
- data/docs/rails_integration.md +96 -474
- data/lib/nitro_kit/installation.rb +11 -3
- data/lib/nitro_kit/migration_inventory.rb +15 -8
- data/lib/nitro_kit/version.rb +1 -1
- data/plugins/nitro-kit/skills/nitro-kit-rails/SKILL.md +7 -0
- data/plugins/nitro-kit/skills/nitro-kit-ui/SKILL.md +15 -8
- data/src/stylesheets/nitro_kit/components/accordion.css +4 -4
- data/src/stylesheets/nitro_kit/components/alert.css +20 -29
- data/src/stylesheets/nitro_kit/components/app_navigation.css +74 -2
- data/src/stylesheets/nitro_kit/components/app_shell.css +3 -3
- data/src/stylesheets/nitro_kit/components/appearance_picker.css +20 -8
- data/src/stylesheets/nitro_kit/components/auth_shell.css +2 -2
- data/src/stylesheets/nitro_kit/components/avatar.css +12 -8
- data/src/stylesheets/nitro_kit/components/avatar_stack.css +12 -10
- data/src/stylesheets/nitro_kit/components/badge.css +13 -9
- data/src/stylesheets/nitro_kit/components/button.css +42 -25
- data/src/stylesheets/nitro_kit/components/card.css +2 -2
- data/src/stylesheets/nitro_kit/components/checkbox.css +29 -46
- data/src/stylesheets/nitro_kit/components/checkbox_group.css +3 -3
- data/src/stylesheets/nitro_kit/components/combobox.css +6 -6
- data/src/stylesheets/nitro_kit/components/command_palette.css +62 -4
- data/src/stylesheets/nitro_kit/components/container.css +6 -6
- data/src/stylesheets/nitro_kit/components/control_group.css +9 -9
- data/src/stylesheets/nitro_kit/components/danger_zone.css +6 -6
- data/src/stylesheets/nitro_kit/components/data_section.css +4 -4
- data/src/stylesheets/nitro_kit/components/details_table.css +7 -5
- data/src/stylesheets/nitro_kit/components/dialog.css +3 -3
- data/src/stylesheets/nitro_kit/components/dropdown.css +7 -7
- data/src/stylesheets/nitro_kit/components/dropzone.css +7 -7
- data/src/stylesheets/nitro_kit/components/empty_state.css +4 -4
- data/src/stylesheets/nitro_kit/components/field.css +2 -2
- data/src/stylesheets/nitro_kit/components/fieldset.css +2 -2
- data/src/stylesheets/nitro_kit/components/flex.css +1 -1
- data/src/stylesheets/nitro_kit/components/grid.css +1 -1
- data/src/stylesheets/nitro_kit/components/icon.css +5 -5
- data/src/stylesheets/nitro_kit/components/input.css +33 -6
- data/src/stylesheets/nitro_kit/components/page_header.css +4 -4
- data/src/stylesheets/nitro_kit/components/pagination.css +3 -3
- data/src/stylesheets/nitro_kit/components/pagination_bar.css +2 -2
- data/src/stylesheets/nitro_kit/components/palette.css +140 -72
- data/src/stylesheets/nitro_kit/components/progressive_image.css +1 -1
- data/src/stylesheets/nitro_kit/components/radio_button.css +28 -33
- data/src/stylesheets/nitro_kit/components/radio_button_group.css +6 -6
- data/src/stylesheets/nitro_kit/components/rich_text_area.css +2 -2
- data/src/stylesheets/nitro_kit/components/select.css +24 -8
- data/src/stylesheets/nitro_kit/components/settings_layout.css +5 -5
- data/src/stylesheets/nitro_kit/components/settings_section.css +2 -2
- data/src/stylesheets/nitro_kit/components/sheet.css +10 -10
- data/src/stylesheets/nitro_kit/components/stat_grid.css +1 -1
- data/src/stylesheets/nitro_kit/components/switch.css +34 -40
- data/src/stylesheets/nitro_kit/components/table.css +8 -4
- data/src/stylesheets/nitro_kit/components/tabs.css +5 -1
- data/src/stylesheets/nitro_kit/components/textarea.css +20 -5
- data/src/stylesheets/nitro_kit/components/toast.css +11 -58
- data/src/stylesheets/nitro_kit/components/toolbar.css +2 -2
- data/src/stylesheets/nitro_kit/components/tooltip.css +4 -0
- data/src/stylesheets/nitro_kit/components/typeset.css +4 -4
- data/src/stylesheets/nitro_kit/reset.css +6 -6
- data/src/stylesheets/nitro_kit/tokens.css +497 -74
- metadata +1 -2
- data/docs/new_app_strategy.md +0 -22
|
@@ -141,13 +141,13 @@ module NitroKit
|
|
|
141
141
|
|
|
142
142
|
def inspect_table(node)
|
|
143
143
|
constructor = positional_arguments(node).first
|
|
144
|
-
return unless node.name == :render && table_constructor?(constructor)
|
|
144
|
+
return unless node.name == :render && table_constructor?(constructor)
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
return unless
|
|
148
|
-
return if
|
|
146
|
+
receiver_name = required_block_parameter_name(node)
|
|
147
|
+
return unless receiver_name
|
|
148
|
+
return if receiver_name == :table
|
|
149
149
|
|
|
150
|
-
visitor = TableCompoundVisitor.new(
|
|
150
|
+
visitor = TableCompoundVisitor.new(receiver_name)
|
|
151
151
|
visitor.visit(node.block.body) if node.block.body
|
|
152
152
|
issues.concat(visitor.issues)
|
|
153
153
|
end
|
|
@@ -166,14 +166,21 @@ module NitroKit
|
|
|
166
166
|
component = constructor.receiver.full_name.delete_prefix("NitroKit::")
|
|
167
167
|
return unless %w[Dropdown Sheet].include?(component)
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
return unless
|
|
169
|
+
receiver_name = required_block_parameter_name(node)
|
|
170
|
+
return unless receiver_name
|
|
171
171
|
|
|
172
|
-
visitor = IconTriggerVisitor.new(
|
|
172
|
+
visitor = IconTriggerVisitor.new(receiver_name, component)
|
|
173
173
|
visitor.visit(node.block.body) if node.block.body
|
|
174
174
|
issues.concat(visitor.issues)
|
|
175
175
|
end
|
|
176
176
|
|
|
177
|
+
def required_block_parameter_name(node)
|
|
178
|
+
return unless node.block.is_a?(Prism::BlockNode)
|
|
179
|
+
|
|
180
|
+
parameter = node.block.parameters&.parameters&.requireds&.first
|
|
181
|
+
parameter.name if parameter.is_a?(Prism::RequiredParameterNode)
|
|
182
|
+
end
|
|
183
|
+
|
|
177
184
|
def table_constructor?(node)
|
|
178
185
|
node.is_a?(Prism::CallNode) && node.name == :new &&
|
|
179
186
|
node.receiver&.respond_to?(:full_name) && node.receiver.full_name == "NitroKit::Table"
|
data/lib/nitro_kit/version.rb
CHANGED
|
@@ -29,6 +29,13 @@ contract as a substitute for the installed API.
|
|
|
29
29
|
|
|
30
30
|
## Follow the application grammar
|
|
31
31
|
|
|
32
|
+
- In a greenfield application, run `bin/rails generate phlex:install` and use
|
|
33
|
+
Phlex for the application layout, route-level views, and reusable UI. Render
|
|
34
|
+
`Views::*` objects from controllers instead of creating ERB wrappers around
|
|
35
|
+
Phlex. In an established application, preserve its view architecture and
|
|
36
|
+
introduce Phlex only at the requested boundary unless an application-wide
|
|
37
|
+
migration is explicitly authorized. Judge this from existing view code, not
|
|
38
|
+
the Rails version or apparent age.
|
|
32
39
|
- Scope tenant data through `Current.team` or `Current.account`; record
|
|
33
40
|
`Current.user` as the actor.
|
|
34
41
|
- Put domain behavior on the model before introducing another abstraction.
|
|
@@ -31,19 +31,26 @@ If the gem is not installed, say that the skill requires Nitro Kit and follow th
|
|
|
31
31
|
|
|
32
32
|
## Build the interface
|
|
33
33
|
|
|
34
|
-
1.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
1. In a greenfield application, run `bin/rails generate phlex:install` and use
|
|
35
|
+
Phlex for the application layout, route-level `Views::*`, and reusable UI.
|
|
36
|
+
Do not add ERB wrappers whose only purpose is to render Phlex. In an
|
|
37
|
+
established application with meaningful view conventions, preserve them
|
|
38
|
+
and introduce Phlex and Nitro Kit only at the requested boundary unless an
|
|
39
|
+
application-wide migration is explicitly authorized. Determine this from
|
|
40
|
+
the existing view architecture, not the Rails version or apparent age.
|
|
41
|
+
2. Reuse the highest-level Nitro block that matches the page region, then compose components inside it.
|
|
42
|
+
3. Include `NitroKit` once in the application's base Phlex component and use capitalized Kit methods such as `Button(...)` and `Card(...)`. Use `.new` only when another API needs a component object. Keep product-specific components under the application's namespace, commonly `UI::*`.
|
|
43
|
+
4. Use `NitroKit::FormBuilder` explicitly with Rails `form_with` for model-backed forms.
|
|
44
|
+
5. Keep routes, authorization, records, query policy, DOM IDs, Turbo boundaries, and response semantics in the application.
|
|
45
|
+
6. Translate the application's semantic theme into documented `--nk-*` properties instead of choosing similar raw palette values. Use `--nk-button-radius` when Button shape intentionally differs from inputs and surfaces.
|
|
46
|
+
7. Verify closed options and required compound declarations before rendering.
|
|
47
|
+
8. For authenticated CRUD, prefer a hybrid `AppShell` with a `Toolbar` that
|
|
41
48
|
owns the route's single `h1` and basic actions. The shell main region owns
|
|
42
49
|
one content gutter. Do not repeat that heading in `PageHeader`, or wrap each
|
|
43
50
|
table, form, and detail region in another Card. At narrow widths, preserve
|
|
44
51
|
the full title and persistent actions by stacking the trailing actions below
|
|
45
52
|
the title rather than clipping either region.
|
|
46
|
-
|
|
53
|
+
9. For team administration and account settings, read
|
|
47
54
|
`docs/patterns/application_foundation.md`. Put Settings after an
|
|
48
55
|
`AppNavigation` spacer and use `SettingsLayout` with plain `SettingsSection`
|
|
49
56
|
regions instead of a stack of Cards.
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
> [data-slot="accordion-trigger"]
|
|
19
19
|
) {
|
|
20
20
|
display: flex;
|
|
21
|
-
|
|
22
|
-
min-
|
|
21
|
+
inline-size: 100%;
|
|
22
|
+
min-block-size: var(--nk-control-height-lg);
|
|
23
23
|
align-items: center;
|
|
24
24
|
justify-content: space-between;
|
|
25
25
|
gap: calc(var(--nk-space) * 3);
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
> [data-slot="accordion-icon"]
|
|
59
59
|
) {
|
|
60
60
|
flex: none;
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
inline-size: var(--nk-icon-size-sm);
|
|
62
|
+
block-size: var(--nk-icon-size-sm);
|
|
63
63
|
color: var(--nk-color-muted-foreground);
|
|
64
64
|
transition:
|
|
65
65
|
color var(--nk-duration-fast) var(--nk-ease),
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
--_nk-alert-background: var(--nk-color-surface);
|
|
4
4
|
--_nk-alert-border: var(--nk-color-border);
|
|
5
5
|
--_nk-alert-foreground: var(--nk-color-foreground);
|
|
6
|
-
--_nk-alert-tint-strength: 12%;
|
|
7
6
|
|
|
8
7
|
position: relative;
|
|
9
8
|
display: grid;
|
|
@@ -20,8 +19,8 @@
|
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
:where([data-nk="alert"] > [data-slot="alert-title"]) {
|
|
23
|
-
font-size: var(--nk-
|
|
24
|
-
font-weight: var(--nk-
|
|
22
|
+
font-size: var(--nk-title-compact-size);
|
|
23
|
+
font-weight: var(--nk-title-compact-weight);
|
|
25
24
|
line-height: var(--nk-leading-tight);
|
|
26
25
|
text-wrap: balance;
|
|
27
26
|
}
|
|
@@ -30,11 +29,20 @@
|
|
|
30
29
|
grid-template-columns: auto minmax(0, 1fr);
|
|
31
30
|
}
|
|
32
31
|
|
|
32
|
+
/* Centered on the title first line, whatever size the title role
|
|
33
|
+
resolves to, instead of a hand-tuned nudge for one size. */
|
|
33
34
|
:where([data-nk="alert"] > [data-slot="alert-icon"]) {
|
|
35
|
+
--_nk-alert-icon-size: var(--nk-icon-size-md);
|
|
36
|
+
|
|
34
37
|
grid-row: 1 / -1;
|
|
35
|
-
inline-size:
|
|
36
|
-
block-size:
|
|
37
|
-
margin-block-start:
|
|
38
|
+
inline-size: var(--_nk-alert-icon-size);
|
|
39
|
+
block-size: var(--_nk-alert-icon-size);
|
|
40
|
+
margin-block-start: calc(
|
|
41
|
+
(
|
|
42
|
+
var(--nk-title-compact-size) * var(--nk-leading-tight) -
|
|
43
|
+
var(--_nk-alert-icon-size)
|
|
44
|
+
) / 2
|
|
45
|
+
);
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
:where(
|
|
@@ -54,29 +62,12 @@
|
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
@layer nitro-kit.variant {
|
|
65
|
+
/* Colour, tint strength, and appearance switching all come from the shared
|
|
66
|
+
semantic palette, so an Alert and a Toast of the same variant render
|
|
67
|
+
identically. */
|
|
57
68
|
:where([data-nk="alert"][data-variant]) {
|
|
58
|
-
--_nk-alert-background:
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
transparent
|
|
62
|
-
);
|
|
63
|
-
--_nk-alert-border: color-mix(
|
|
64
|
-
in oklab,
|
|
65
|
-
var(--_nk-palette-tint) 45%,
|
|
66
|
-
transparent
|
|
67
|
-
);
|
|
68
|
-
--_nk-alert-foreground: var(--_nk-palette-light);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
:where([data-theme="dark"] [data-nk="alert"][data-variant]) {
|
|
72
|
-
--_nk-alert-foreground: var(--_nk-palette-dark);
|
|
73
|
-
--_nk-alert-tint-strength: 20%;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
@media (prefers-color-scheme: dark) {
|
|
77
|
-
:where(:root:not([data-theme]) [data-nk="alert"][data-variant]) {
|
|
78
|
-
--_nk-alert-foreground: var(--_nk-palette-dark);
|
|
79
|
-
--_nk-alert-tint-strength: 20%;
|
|
80
|
-
}
|
|
69
|
+
--_nk-alert-background: var(--_nk-semantic-surface);
|
|
70
|
+
--_nk-alert-border: var(--_nk-semantic-border);
|
|
71
|
+
--_nk-alert-foreground: var(--_nk-semantic-content);
|
|
81
72
|
}
|
|
82
73
|
}
|
|
@@ -65,6 +65,58 @@
|
|
|
65
65
|
line-height: var(--nk-leading-tight);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/* A collapsible label is a row like the items around it: same height,
|
|
69
|
+
same inline padding, symmetric block margins, and the same hover
|
|
70
|
+
treatment, so the disclosure target is as easy to hit as a destination. */
|
|
71
|
+
:where(
|
|
72
|
+
[data-nk="app-navigation"]
|
|
73
|
+
summary[data-slot="app-navigation-section-label"]
|
|
74
|
+
) {
|
|
75
|
+
display: flex;
|
|
76
|
+
gap: var(--nk-space);
|
|
77
|
+
align-items: center;
|
|
78
|
+
min-block-size: var(--nk-control-height-md);
|
|
79
|
+
margin: var(--nk-space) 0;
|
|
80
|
+
padding: calc(var(--nk-space) * 2) calc(var(--nk-space) * 3);
|
|
81
|
+
list-style: none;
|
|
82
|
+
user-select: none;
|
|
83
|
+
cursor: pointer;
|
|
84
|
+
border-radius: var(--nk-radius-lg);
|
|
85
|
+
transition:
|
|
86
|
+
color var(--nk-duration-normal) var(--nk-ease),
|
|
87
|
+
background-color var(--nk-duration-normal) var(--nk-ease);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
:where(
|
|
91
|
+
[data-nk="app-navigation"]
|
|
92
|
+
summary[data-slot="app-navigation-section-label"]::-webkit-details-marker
|
|
93
|
+
) {
|
|
94
|
+
display: none;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
:where([data-nk="app-navigation"] [data-slot="app-navigation-section-icon"]) {
|
|
98
|
+
flex: none;
|
|
99
|
+
inline-size: var(--nk-icon-size-xs);
|
|
100
|
+
block-size: var(--nk-icon-size-xs);
|
|
101
|
+
transition: transform var(--nk-duration-fast) var(--nk-ease);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
:where(
|
|
105
|
+
[data-nk="app-navigation"]
|
|
106
|
+
[data-slot="app-navigation-section-disclosure"]:not([open])
|
|
107
|
+
[data-slot="app-navigation-section-icon"]
|
|
108
|
+
) {
|
|
109
|
+
transform: rotate(-90deg);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@media (prefers-reduced-motion: reduce) {
|
|
113
|
+
:where(
|
|
114
|
+
[data-nk="app-navigation"] [data-slot="app-navigation-section-icon"]
|
|
115
|
+
) {
|
|
116
|
+
transition-duration: 0.01ms;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
68
120
|
:where([data-nk="app-navigation"] [data-slot="app-navigation-item"]) {
|
|
69
121
|
flex: 0 0 auto;
|
|
70
122
|
min-inline-size: 0;
|
|
@@ -80,7 +132,7 @@
|
|
|
80
132
|
font-weight: var(--nk-font-weight-medium);
|
|
81
133
|
line-height: var(--nk-leading-tight);
|
|
82
134
|
text-decoration: none;
|
|
83
|
-
border-radius: var(--nk-radius-
|
|
135
|
+
border-radius: var(--nk-radius-lg);
|
|
84
136
|
transition:
|
|
85
137
|
color var(--nk-duration-normal) var(--nk-ease),
|
|
86
138
|
background-color var(--nk-duration-normal) var(--nk-ease);
|
|
@@ -96,6 +148,7 @@
|
|
|
96
148
|
|
|
97
149
|
:where(
|
|
98
150
|
[data-nk="app-navigation"] [data-slot="app-navigation-item-icon"],
|
|
151
|
+
[data-nk="app-navigation"] [data-slot="app-navigation-item-icon-end"],
|
|
99
152
|
[data-nk="app-navigation"] [data-slot="app-navigation-item-badge"]
|
|
100
153
|
) {
|
|
101
154
|
flex: 0 0 auto;
|
|
@@ -133,13 +186,32 @@
|
|
|
133
186
|
|
|
134
187
|
@media (hover: hover) {
|
|
135
188
|
:where(
|
|
136
|
-
[data-nk="app-navigation"] [data-slot="app-navigation-item-link"]:hover
|
|
189
|
+
[data-nk="app-navigation"] [data-slot="app-navigation-item-link"]:hover,
|
|
190
|
+
[data-nk="app-navigation"]
|
|
191
|
+
summary[data-slot="app-navigation-section-label"]:hover
|
|
137
192
|
) {
|
|
138
193
|
color: var(--nk-app-shell-sidebar-accent-foreground);
|
|
139
194
|
background: var(--nk-app-shell-sidebar-accent);
|
|
140
195
|
}
|
|
141
196
|
}
|
|
142
197
|
|
|
198
|
+
:where(
|
|
199
|
+
[data-nk="app-navigation"]
|
|
200
|
+
summary[data-slot="app-navigation-section-label"]:focus-visible
|
|
201
|
+
) {
|
|
202
|
+
outline: var(--nk-focus-width) solid var(--nk-color-focus);
|
|
203
|
+
outline-offset: calc(var(--nk-focus-offset) * -1);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
@media (prefers-reduced-motion: reduce) {
|
|
207
|
+
:where(
|
|
208
|
+
[data-nk="app-navigation"]
|
|
209
|
+
summary[data-slot="app-navigation-section-label"]
|
|
210
|
+
) {
|
|
211
|
+
transition-duration: 0.01ms;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
143
215
|
:where(
|
|
144
216
|
[data-nk="app-navigation"]
|
|
145
217
|
[data-slot="app-navigation-item-link"]:focus-visible
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
color: var(--nk-color-primary-foreground);
|
|
25
25
|
text-decoration: none;
|
|
26
26
|
background: var(--nk-color-primary);
|
|
27
|
-
border-radius: var(--nk-radius-
|
|
27
|
+
border-radius: var(--nk-radius-lg);
|
|
28
28
|
outline: var(--nk-focus-width) solid var(--nk-color-focus);
|
|
29
29
|
transform: translateY(calc(-100% - (var(--nk-space) * 4)));
|
|
30
30
|
transition: transform var(--nk-duration-fast) var(--nk-ease);
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
cursor: pointer;
|
|
80
80
|
background: transparent;
|
|
81
81
|
border: 0;
|
|
82
|
-
border-radius: var(--nk-radius-
|
|
82
|
+
border-radius: var(--nk-radius-lg);
|
|
83
83
|
transition:
|
|
84
84
|
background-color var(--nk-duration-fast) var(--nk-ease),
|
|
85
85
|
scale var(--nk-duration-fast) var(--nk-ease);
|
|
@@ -542,7 +542,7 @@
|
|
|
542
542
|
flex-direction: column;
|
|
543
543
|
inline-size: min(
|
|
544
544
|
var(--nk-app-shell-sidebar-width),
|
|
545
|
-
calc(
|
|
545
|
+
calc(100% - (var(--nk-space) * 12))
|
|
546
546
|
);
|
|
547
547
|
max-inline-size: 100%;
|
|
548
548
|
block-size: 100vh;
|
|
@@ -10,16 +10,24 @@
|
|
|
10
10
|
[data-nk="appearance-picker"] > [data-slot="appearance-picker-legend"]
|
|
11
11
|
) {
|
|
12
12
|
padding: 0;
|
|
13
|
-
font-size: var(--nk-
|
|
14
|
-
font-weight: var(--nk-
|
|
13
|
+
font-size: var(--nk-title-compact-size);
|
|
14
|
+
font-weight: var(--nk-title-compact-weight);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/* The gap below the label exists only when there is a label. */
|
|
17
18
|
:where(
|
|
18
19
|
[data-nk="appearance-picker"] > [data-slot="appearance-picker-options"]
|
|
19
20
|
) {
|
|
20
21
|
display: flex;
|
|
21
22
|
flex-wrap: wrap;
|
|
22
23
|
gap: calc(var(--nk-space) * 3);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
:where(
|
|
27
|
+
[data-nk="appearance-picker"]
|
|
28
|
+
> [data-slot="appearance-picker-legend"]
|
|
29
|
+
+ [data-slot="appearance-picker-options"]
|
|
30
|
+
) {
|
|
23
31
|
margin-block-start: calc(var(--nk-space) * 2);
|
|
24
32
|
}
|
|
25
33
|
|
|
@@ -30,15 +38,17 @@
|
|
|
30
38
|
display: grid;
|
|
31
39
|
}
|
|
32
40
|
|
|
41
|
+
/* Like every other control, the segmented row fills its container and the
|
|
42
|
+
parent owns the available width; the segments share it equally. */
|
|
33
43
|
:where(
|
|
34
44
|
[data-nk="appearance-picker"][data-presentation="segmented"]
|
|
35
45
|
> [data-slot="appearance-picker-options"]
|
|
36
46
|
) {
|
|
37
|
-
display:
|
|
47
|
+
display: flex;
|
|
38
48
|
gap: 0;
|
|
39
49
|
padding: var(--nk-space);
|
|
40
50
|
background: var(--nk-color-muted);
|
|
41
|
-
border-radius: var(--nk-radius-
|
|
51
|
+
border-radius: var(--nk-radius-lg);
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
:where([data-nk="appearance-picker"] [data-slot="appearance-picker-option"]) {
|
|
@@ -53,8 +63,8 @@
|
|
|
53
63
|
:where(
|
|
54
64
|
[data-nk="appearance-picker"] [data-slot="appearance-picker-control"]
|
|
55
65
|
) {
|
|
56
|
-
inline-size:
|
|
57
|
-
block-size:
|
|
66
|
+
inline-size: var(--nk-choice-size-md);
|
|
67
|
+
block-size: var(--nk-choice-size-md);
|
|
58
68
|
margin: 0;
|
|
59
69
|
accent-color: var(--nk-color-primary);
|
|
60
70
|
cursor: pointer;
|
|
@@ -65,8 +75,10 @@
|
|
|
65
75
|
[data-slot="appearance-picker-option"]
|
|
66
76
|
) {
|
|
67
77
|
position: relative;
|
|
78
|
+
flex: 1 1 0;
|
|
79
|
+
justify-content: center;
|
|
68
80
|
padding-inline: calc(var(--nk-space) * 3);
|
|
69
|
-
border-radius: calc(var(--nk-radius-
|
|
81
|
+
border-radius: calc(var(--nk-radius-lg) - var(--nk-space));
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
:where(
|
|
@@ -90,7 +102,7 @@
|
|
|
90
102
|
font: inherit;
|
|
91
103
|
background: var(--nk-color-surface);
|
|
92
104
|
border: var(--nk-border-width) solid var(--nk-color-border);
|
|
93
|
-
border-radius: var(--nk-radius-
|
|
105
|
+
border-radius: var(--nk-radius-lg);
|
|
94
106
|
}
|
|
95
107
|
}
|
|
96
108
|
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
@layer nitro-kit.base {
|
|
2
2
|
:where([data-nk="avatar"]) {
|
|
3
3
|
position: relative;
|
|
4
|
+
/* The ring below carries a z-index, so without a stacking context it
|
|
5
|
+
would paint above overlapping siblings — in a stack, every ring showed
|
|
6
|
+
through the avatar covering it. Isolation keeps each avatar atomic. */
|
|
7
|
+
isolation: isolate;
|
|
4
8
|
display: inline-grid;
|
|
5
9
|
flex: none;
|
|
6
10
|
place-items: center;
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
inline-size: var(--_nk-avatar-size);
|
|
12
|
+
block-size: var(--_nk-avatar-size);
|
|
9
13
|
overflow: hidden;
|
|
10
14
|
font-size: var(--_nk-avatar-font-size);
|
|
11
15
|
font-weight: var(--nk-font-weight-medium);
|
|
@@ -32,8 +36,8 @@
|
|
|
32
36
|
[data-nk="avatar"] > [data-slot="avatar-image"]
|
|
33
37
|
) {
|
|
34
38
|
grid-area: 1 / 1;
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
inline-size: 100%;
|
|
40
|
+
block-size: 100%;
|
|
37
41
|
border-radius: inherit;
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -60,22 +64,22 @@
|
|
|
60
64
|
|
|
61
65
|
@layer nitro-kit.size {
|
|
62
66
|
:where([data-nk="avatar"][data-size="xs"]) {
|
|
63
|
-
--_nk-avatar-size:
|
|
67
|
+
--_nk-avatar-size: var(--nk-avatar-size-xs);
|
|
64
68
|
--_nk-avatar-font-size: calc(var(--nk-text-xs) * 0.875);
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
:where([data-nk="avatar"][data-size="sm"]) {
|
|
68
|
-
--_nk-avatar-size:
|
|
72
|
+
--_nk-avatar-size: var(--nk-avatar-size-sm);
|
|
69
73
|
--_nk-avatar-font-size: var(--nk-text-xs);
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
:where([data-nk="avatar"][data-size="md"]) {
|
|
73
|
-
--_nk-avatar-size:
|
|
77
|
+
--_nk-avatar-size: var(--nk-avatar-size-md);
|
|
74
78
|
--_nk-avatar-font-size: var(--nk-text-sm);
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
:where([data-nk="avatar"][data-size="lg"]) {
|
|
78
|
-
--_nk-avatar-size:
|
|
82
|
+
--_nk-avatar-size: var(--nk-avatar-size-lg);
|
|
79
83
|
--_nk-avatar-font-size: var(--nk-text-lg);
|
|
80
84
|
}
|
|
81
85
|
}
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
margin-inline-start: 0;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/* The chip is one of the heads: same fill as the avatar fallbacks and the
|
|
49
|
+
same hairline ring, drawn as a real border since nothing overlaps it. */
|
|
48
50
|
:where([data-nk="avatar-stack"] > [data-slot="avatar-stack-overflow"]) {
|
|
49
|
-
--_nk-avatar-stack-fill: var(--nk-color-elevated);
|
|
50
|
-
|
|
51
51
|
/* Preceding avatars are positioned, so the overflow chip must be too or
|
|
52
52
|
their paint order covers its leading "+". */
|
|
53
53
|
position: relative;
|
|
@@ -56,6 +56,8 @@
|
|
|
56
56
|
font-weight: var(--nk-font-weight-semibold);
|
|
57
57
|
line-height: 1;
|
|
58
58
|
color: var(--nk-color-muted-foreground);
|
|
59
|
+
border: var(--nk-border-width) solid
|
|
60
|
+
color-mix(in oklab, var(--nk-color-foreground) 10%, transparent);
|
|
59
61
|
border-radius: var(--nk-radius-full);
|
|
60
62
|
}
|
|
61
63
|
|
|
@@ -63,8 +65,8 @@
|
|
|
63
65
|
[data-nk="avatar-stack"][data-size="xs"]
|
|
64
66
|
> [data-slot="avatar-stack-overflow"]
|
|
65
67
|
) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
inline-size: var(--nk-avatar-size-xs);
|
|
69
|
+
block-size: var(--nk-avatar-size-xs);
|
|
68
70
|
font-size: calc(var(--nk-text-xs) * 0.875);
|
|
69
71
|
}
|
|
70
72
|
|
|
@@ -72,8 +74,8 @@
|
|
|
72
74
|
[data-nk="avatar-stack"][data-size="sm"]
|
|
73
75
|
> [data-slot="avatar-stack-overflow"]
|
|
74
76
|
) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
inline-size: var(--nk-avatar-size-sm);
|
|
78
|
+
block-size: var(--nk-avatar-size-sm);
|
|
77
79
|
font-size: var(--nk-text-xs);
|
|
78
80
|
}
|
|
79
81
|
|
|
@@ -81,8 +83,8 @@
|
|
|
81
83
|
[data-nk="avatar-stack"][data-size="md"]
|
|
82
84
|
> [data-slot="avatar-stack-overflow"]
|
|
83
85
|
) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
inline-size: var(--nk-avatar-size-md);
|
|
87
|
+
block-size: var(--nk-avatar-size-md);
|
|
86
88
|
font-size: var(--nk-text-sm);
|
|
87
89
|
}
|
|
88
90
|
|
|
@@ -90,8 +92,8 @@
|
|
|
90
92
|
[data-nk="avatar-stack"][data-size="lg"]
|
|
91
93
|
> [data-slot="avatar-stack-overflow"]
|
|
92
94
|
) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
inline-size: var(--nk-avatar-size-lg);
|
|
96
|
+
block-size: var(--nk-avatar-size-lg);
|
|
95
97
|
font-size: var(--nk-text-base);
|
|
96
98
|
}
|
|
97
99
|
}
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
@layer nitro-kit.base {
|
|
2
2
|
:where([data-nk="badge"]) {
|
|
3
|
-
--_nk-badge-color: var(--_nk-palette-light);
|
|
4
3
|
--_nk-badge-tint-strength: 20%;
|
|
5
4
|
|
|
6
5
|
display: inline-flex;
|
|
7
6
|
align-items: center;
|
|
8
|
-
max-
|
|
7
|
+
max-inline-size: 100%;
|
|
9
8
|
font-weight: var(--nk-font-weight-medium);
|
|
10
9
|
line-height: var(--nk-leading-tight);
|
|
11
|
-
color: var(--_nk-
|
|
10
|
+
color: var(--_nk-semantic-content);
|
|
12
11
|
white-space: nowrap;
|
|
13
12
|
vertical-align: middle;
|
|
14
13
|
background-color: color-mix(
|
|
15
14
|
in oklab,
|
|
16
|
-
var(--_nk-
|
|
15
|
+
var(--_nk-semantic-accent) var(--_nk-badge-tint-strength),
|
|
17
16
|
transparent
|
|
18
17
|
);
|
|
19
18
|
border: var(--nk-border-width) solid transparent;
|
|
@@ -21,7 +20,7 @@
|
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
:where([data-nk="badge"] > [data-slot="badge-label"]) {
|
|
24
|
-
min-
|
|
23
|
+
min-inline-size: 0;
|
|
25
24
|
overflow: hidden;
|
|
26
25
|
white-space: nowrap;
|
|
27
26
|
text-overflow: ellipsis;
|
|
@@ -31,17 +30,22 @@
|
|
|
31
30
|
@layer nitro-kit.variant {
|
|
32
31
|
:where([data-nk="badge"][data-variant="outline"]) {
|
|
33
32
|
background-color: transparent;
|
|
34
|
-
border-color: color-mix(
|
|
33
|
+
border-color: color-mix(
|
|
34
|
+
in oklab,
|
|
35
|
+
var(--_nk-semantic-accent) 50%,
|
|
36
|
+
transparent
|
|
37
|
+
);
|
|
35
38
|
}
|
|
36
39
|
|
|
40
|
+
/* Only the tint strength changes with appearance. The colours themselves come
|
|
41
|
+
from the `--nk-palette-*` roles, whose `-content` half already resolves per
|
|
42
|
+
appearance. */
|
|
37
43
|
:where([data-theme="dark"] [data-nk="badge"]) {
|
|
38
|
-
--_nk-badge-color: var(--_nk-palette-dark);
|
|
39
44
|
--_nk-badge-tint-strength: 40%;
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
@media (prefers-color-scheme: dark) {
|
|
43
48
|
:where(:root:not([data-theme]) [data-nk="badge"]) {
|
|
44
|
-
--_nk-badge-color: var(--_nk-palette-dark);
|
|
45
49
|
--_nk-badge-tint-strength: 40%;
|
|
46
50
|
}
|
|
47
51
|
}
|
|
@@ -60,7 +64,7 @@
|
|
|
60
64
|
|
|
61
65
|
@layer nitro-kit.size {
|
|
62
66
|
:where([data-nk="badge"][data-size="xs"]) {
|
|
63
|
-
padding: 0
|
|
67
|
+
padding: 0 var(--nk-space);
|
|
64
68
|
font-size: var(--nk-text-xs);
|
|
65
69
|
}
|
|
66
70
|
|