kmaterialize 2.3.3-1.0.13 → 2.3.3-1.0.16
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.
- package/components/air-datepicker/_air-datepicker.scss +137 -0
- package/components/air-datepicker/air-datepicker.ts +192 -0
- package/components/appbar/appbar.css +204 -1
- package/components/button/_buttons.scss +3 -0
- package/components/checkbox/_checkboxes.scss +120 -229
- package/components/color-input/_color-input.scss +124 -0
- package/components/color-input/color-input.ts +203 -0
- package/components/file-input/_file-input-enhanced.scss +61 -0
- package/components/file-input/file-input.ts +203 -0
- package/components/number-input/number-input.ts +103 -0
- package/components/password-input/password-input.ts +72 -0
- package/components/textfield/_input-fields.scss +1 -1
- package/components/textfield/_select.scss +54 -0
- package/components/tom-select/_tom-select-field.scss +256 -0
- package/components/tom-select/tom-select-field.ts +175 -0
- package/components/toolbar/_toolbar.scss +108 -3
- package/dist/css/materialize.colors.min.css +1 -1
- package/dist/css/materialize.css +1093 -251
- package/dist/css/materialize.min.css +2 -2
- package/dist/css/materialize.min.css.map +1 -1
- package/dist/js/materialize.cjs.js +822 -46
- package/dist/js/materialize.d.ts +143 -2
- package/dist/js/materialize.js +822 -46
- package/dist/js/materialize.min.js +2 -2
- package/dist/js/materialize.mjs +817 -47
- package/package.json +45 -1
- package/sass/_colors.scss +18 -14
- package/sass/materialize.scss +4 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// @implement /Users/kzarshenas/Sites/RodeoFx/rodeo_toolkit_2/app/Front/style/scss/enhancement/airdatepicker_materializecss.scss
|
|
2
|
+
// Remaps air-datepicker's own --adp-* custom properties onto MD3 tokens so
|
|
3
|
+
// its calendar popup auto-themes with the rest of kmaterialize, instead of
|
|
4
|
+
// theming the popup's own markup directly. Requires the consumer to
|
|
5
|
+
// separately import air-datepicker's own base CSS (`air-datepicker/air-datepicker.css`) -
|
|
6
|
+
// kmaterialize can't reach into an optional peer's package at build time
|
|
7
|
+
// without turning it into a hard dependency, so this partial only overrides
|
|
8
|
+
// the custom properties that stylesheet defines.
|
|
9
|
+
//
|
|
10
|
+
// This is the richer Rodeo toolkit variant of the port (rounded corners,
|
|
11
|
+
// circular day cells, weekend/other-month readability fixes, a two-line
|
|
12
|
+
// nav title) rather than CrazyPHP's plainer original.
|
|
13
|
+
input[data-date-picker='air-datepicker'][readonly] {
|
|
14
|
+
caret-color: transparent;
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.input-field:has(input[data-date-picker='air-datepicker']) {
|
|
19
|
+
> label,
|
|
20
|
+
.prefix,
|
|
21
|
+
.suffix {
|
|
22
|
+
z-index: 1;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.air-datepicker {
|
|
28
|
+
--adp-z-index: 100001; // above modals/SweetAlert-style overlays
|
|
29
|
+
--adp-transition-duration: 0.11s;
|
|
30
|
+
|
|
31
|
+
--adp-font-family: 'Roboto', sans-serif;
|
|
32
|
+
--adp-background-color: var(--md-sys-color-surface);
|
|
33
|
+
--adp-color: var(--md-sys-color-on-surface);
|
|
34
|
+
--adp-color-secondary: var(--md-sys-color-on-surface-variant);
|
|
35
|
+
--adp-border-color: var(--md-sys-color-outline-variant);
|
|
36
|
+
--adp-border-color-inner: var(--md-sys-color-outline-variant);
|
|
37
|
+
|
|
38
|
+
--adp-color-current-date: var(--md-sys-color-primary);
|
|
39
|
+
|
|
40
|
+
--adp-background-color-hover: var(--md-sys-color-surface-variant);
|
|
41
|
+
--adp-background-color-active: var(--md-sys-color-surface-variant);
|
|
42
|
+
|
|
43
|
+
--adp-cell-background-color-selected: var(--md-sys-color-primary);
|
|
44
|
+
--adp-cell-background-color-selected-hover: var(--md-sys-color-primary-container);
|
|
45
|
+
--adp-cell-border-color-in-range: var(--md-sys-color-primary);
|
|
46
|
+
--adp-cell-background-color-in-range: var(--md-sys-color-primary-container);
|
|
47
|
+
--adp-cell-background-color-in-range-hover: var(--md-sys-color-primary-container);
|
|
48
|
+
--adp-color-other-month: var(--md-sys-color-outline);
|
|
49
|
+
--adp-color-other-month-hover: var(--md-sys-color-on-surface-variant);
|
|
50
|
+
|
|
51
|
+
--adp-btn-color: var(--md-sys-color-primary);
|
|
52
|
+
--adp-btn-color-hover: var(--md-sys-color-on-primary);
|
|
53
|
+
--adp-btn-background-color-hover: var(--md-sys-color-primary-container);
|
|
54
|
+
--adp-btn-background-color-active: var(--md-sys-color-primary-container);
|
|
55
|
+
|
|
56
|
+
--adp-time-track-color: var(--md-sys-color-outline-variant);
|
|
57
|
+
--adp-time-track-color-hover: var(--md-sys-color-primary);
|
|
58
|
+
--adp-time-day-period-color: var(--md-sys-color-on-surface-variant);
|
|
59
|
+
|
|
60
|
+
// Shape - rounded popup, circular day cells, generous padding, matching
|
|
61
|
+
// the rest of kmaterialize's MD3 shape language (pill toolbars, rounded
|
|
62
|
+
// cards) rather than air-datepicker's own square default.
|
|
63
|
+
--adp-border-radius: 24px;
|
|
64
|
+
--adp-cell-border-radius: 50%;
|
|
65
|
+
--adp-padding: 16px;
|
|
66
|
+
|
|
67
|
+
--adp-color-disabled: var(--md-sys-color-outline);
|
|
68
|
+
--adp-color-disabled-in-range: var(--md-sys-color-on-surface-variant);
|
|
69
|
+
|
|
70
|
+
.air-datepicker-nav {
|
|
71
|
+
height: auto;
|
|
72
|
+
min-height: 32px;
|
|
73
|
+
padding: 0px;
|
|
74
|
+
box-shadow: initial;
|
|
75
|
+
background-color: inherit;
|
|
76
|
+
color: var(--adp-nav-color-secondary) !important;
|
|
77
|
+
|
|
78
|
+
.air-datepicker-nav--title {
|
|
79
|
+
display: flex;
|
|
80
|
+
flex-direction: column;
|
|
81
|
+
align-items: center;
|
|
82
|
+
font-size: 14px;
|
|
83
|
+
line-height: 1.25;
|
|
84
|
+
|
|
85
|
+
i {
|
|
86
|
+
font-size: 14px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// A second line under the month/year, for context (e.g. what range
|
|
90
|
+
// is about to apply) - opt-in, air-datepicker doesn't emit this
|
|
91
|
+
// itself, a consumer's own `dateFormatter` can inject it.
|
|
92
|
+
small {
|
|
93
|
+
font-size: 10.5px;
|
|
94
|
+
font-weight: 500;
|
|
95
|
+
letter-spacing: 0.03em;
|
|
96
|
+
font-variant-numeric: tabular-nums;
|
|
97
|
+
color: var(--adp-color-secondary);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Material icons sit larger than the arrows they replace.
|
|
102
|
+
.air-datepicker-nav--action i {
|
|
103
|
+
font-size: 18px;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.air-datepicker-cell {
|
|
108
|
+
font-variant-numeric: tabular-nums;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// air-datepicker tags weekends and ships no style for them.
|
|
112
|
+
.air-datepicker-cell.-day-.-weekend- {
|
|
113
|
+
color: var(--md-sys-color-outline);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.air-datepicker-body--day-name.-weekend- {
|
|
117
|
+
opacity: 0.7;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Inside a selected range a weekend has to stay readable.
|
|
121
|
+
.air-datepicker-cell.-day-.-weekend-.-in-range-,
|
|
122
|
+
.air-datepicker-cell.-day-.-weekend-.-selected- {
|
|
123
|
+
color: inherit;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// The view holds still when a greyed (other-month) day is picked, so the
|
|
127
|
+
// selection can land off-month - without this it reads as nothing
|
|
128
|
+
// selected.
|
|
129
|
+
.air-datepicker-cell.-day-.-other-month-.-selected- {
|
|
130
|
+
color: var(--md-sys-color-on-primary);
|
|
131
|
+
background: var(--md-sys-color-primary);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
i.air-datepicker--pointer {
|
|
135
|
+
display: none;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import type AirDatepickerCtor from 'air-datepicker';
|
|
2
|
+
import type { AirDatepickerOptions } from 'air-datepicker';
|
|
3
|
+
import { Component, BaseOptions, InitElements, MElement } from '../../src/component';
|
|
4
|
+
import { loadPeer } from '../../src/peer-loader';
|
|
5
|
+
|
|
6
|
+
export interface AirDatepickerFieldOptions extends BaseOptions {
|
|
7
|
+
locale?: unknown;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const _defaults: AirDatepickerFieldOptions = {};
|
|
11
|
+
let activeAirDatepickerField: AirDatepickerField | undefined;
|
|
12
|
+
|
|
13
|
+
// @implement /Users/kzarshenas/Sites/CrazyProject/CrazyPHP/src/Front/Library/Utility/Form/Date.ts
|
|
14
|
+
// Enhances `<input type="text" data-type="date" data-date-picker="air-datepicker">`
|
|
15
|
+
// with the air-datepicker calendar/range picker - deliberately separate from
|
|
16
|
+
// kmaterialize's own native `components/datepicker/` (a different, already
|
|
17
|
+
// existing class-based component); this one is opted into per-input via the
|
|
18
|
+
// `data-date-picker` attribute so it never collides with `.datepicker`
|
|
19
|
+
// elements. The `multiple` attribute switches the picker into range mode,
|
|
20
|
+
// `data-date-format`/`data-date-lang` (only "fr-FR" ported so far) mirror
|
|
21
|
+
// CrazyPHP's own dataset convention.
|
|
22
|
+
//
|
|
23
|
+
// air-datepicker is an optional peerDependency, loaded on demand via
|
|
24
|
+
// peer-loader. Its own base stylesheet (air-datepicker/air-datepicker.css)
|
|
25
|
+
// must be imported separately by the consumer - see the docs page.
|
|
26
|
+
export class AirDatepickerField extends Component<AirDatepickerFieldOptions> {
|
|
27
|
+
declare el: HTMLInputElement;
|
|
28
|
+
picker: AirDatepickerCtor | undefined;
|
|
29
|
+
ready: Promise<void>;
|
|
30
|
+
private _triggers: HTMLElement[];
|
|
31
|
+
private _handleOutsideClick = (e: MouseEvent) => {
|
|
32
|
+
const calendarEl = document.querySelector('.air-datepicker');
|
|
33
|
+
const clickedTrigger = this._triggers.some(trigger => trigger.contains(e.target as Node));
|
|
34
|
+
if (
|
|
35
|
+
calendarEl instanceof HTMLElement &&
|
|
36
|
+
!calendarEl.contains(e.target as Node) &&
|
|
37
|
+
!this.el.contains(e.target as Node) &&
|
|
38
|
+
!clickedTrigger
|
|
39
|
+
) {
|
|
40
|
+
this.picker?.hide();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
constructor(el: HTMLInputElement, options: Partial<AirDatepickerFieldOptions>) {
|
|
45
|
+
super(el, options, AirDatepickerField);
|
|
46
|
+
(this.el as any).M_AirDatepickerField = this;
|
|
47
|
+
|
|
48
|
+
this.options = {
|
|
49
|
+
...AirDatepickerField.defaults,
|
|
50
|
+
...options
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const labels = Array.from(document.querySelectorAll('label')).filter(
|
|
54
|
+
label => label.htmlFor === this.el.id
|
|
55
|
+
);
|
|
56
|
+
const icons = Array.from(
|
|
57
|
+
this.el.parentElement?.querySelectorAll<HTMLElement>('.prefix, .suffix') ?? []
|
|
58
|
+
);
|
|
59
|
+
this._triggers = [...labels, ...icons];
|
|
60
|
+
this._triggers.forEach(trigger => trigger.addEventListener('click', this._handleTriggerClick));
|
|
61
|
+
this.ready = this._setup();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static get defaults(): AirDatepickerFieldOptions {
|
|
65
|
+
return _defaults;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static init(el: HTMLInputElement, options?: Partial<AirDatepickerFieldOptions>): AirDatepickerField;
|
|
69
|
+
static init(
|
|
70
|
+
els: InitElements<HTMLInputElement | MElement>,
|
|
71
|
+
options?: Partial<AirDatepickerFieldOptions>
|
|
72
|
+
): AirDatepickerField[];
|
|
73
|
+
static init(
|
|
74
|
+
els: HTMLInputElement | InitElements<HTMLInputElement | MElement>,
|
|
75
|
+
options: Partial<AirDatepickerFieldOptions> = {}
|
|
76
|
+
): AirDatepickerField | AirDatepickerField[] {
|
|
77
|
+
return super.init(els, options, AirDatepickerField);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static getInstance(el: HTMLInputElement): AirDatepickerField {
|
|
81
|
+
return (el as any).M_AirDatepickerField;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
destroy() {
|
|
85
|
+
document.removeEventListener('click', this._handleOutsideClick);
|
|
86
|
+
this._triggers.forEach(trigger => trigger.removeEventListener('click', this._handleTriggerClick));
|
|
87
|
+
this.picker?.destroy();
|
|
88
|
+
if (activeAirDatepickerField === this) activeAirDatepickerField = undefined;
|
|
89
|
+
(this.el as any).M_AirDatepickerField = undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private _handleTriggerClick = (event: MouseEvent) => {
|
|
93
|
+
event.preventDefault();
|
|
94
|
+
event.stopPropagation();
|
|
95
|
+
void this.ready.then(() => this.picker?.show());
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
async _setup(): Promise<void> {
|
|
99
|
+
const AirDatepicker = await loadPeer<typeof AirDatepickerCtor>(
|
|
100
|
+
{
|
|
101
|
+
specifier: 'air-datepicker',
|
|
102
|
+
globalName: 'AirDatepicker',
|
|
103
|
+
feature: 'Date input (air-datepicker) enhancement',
|
|
104
|
+
cdnHint:
|
|
105
|
+
'<link rel="stylesheet" href="path/to/air-datepicker.css">\n' +
|
|
106
|
+
' <script src="path/to/air-datepicker.js"></script>\n' +
|
|
107
|
+
' (self-hosted - copy from node_modules/air-datepicker/, or a CDN of your choice)'
|
|
108
|
+
},
|
|
109
|
+
() => import('air-datepicker')
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const dataset = this.el.dataset;
|
|
113
|
+
const builtInLocale = dataset.dateLang === 'fr-FR'
|
|
114
|
+
? (await import('air-datepicker/locale/fr')).default
|
|
115
|
+
: (await import('air-datepicker/locale/en')).default;
|
|
116
|
+
const pickerOptions: AirDatepickerOptions = {
|
|
117
|
+
dateFormat: dataset.dateFormat || 'yyyy-MM-dd',
|
|
118
|
+
autoClose: dataset.dateAutoClose !== 'false',
|
|
119
|
+
locale: (this.options.locale ?? builtInLocale) as AirDatepickerOptions['locale'],
|
|
120
|
+
onShow: isAnimationComplete => {
|
|
121
|
+
if (isAnimationComplete) return;
|
|
122
|
+
if (activeAirDatepickerField && activeAirDatepickerField !== this) {
|
|
123
|
+
activeAirDatepickerField.picker?.hide();
|
|
124
|
+
}
|
|
125
|
+
activeAirDatepickerField = this;
|
|
126
|
+
},
|
|
127
|
+
onHide: isAnimationComplete => {
|
|
128
|
+
if (isAnimationComplete && activeAirDatepickerField === this) {
|
|
129
|
+
activeAirDatepickerField = undefined;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
let multiple = false;
|
|
135
|
+
if (this.el.multiple || dataset.dateRange === 'true') {
|
|
136
|
+
pickerOptions.range = true;
|
|
137
|
+
pickerOptions.multipleDatesSeparator = ' - ';
|
|
138
|
+
multiple = true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const initialValue = this.el.getAttribute('value')?.trim();
|
|
142
|
+
if (initialValue) {
|
|
143
|
+
pickerOptions.selectedDates = multiple
|
|
144
|
+
? initialValue.split(' - ').map(value => value.trim())
|
|
145
|
+
: [initialValue];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (dataset.dateTimepicker === 'true') {
|
|
149
|
+
pickerOptions.timepicker = true;
|
|
150
|
+
if (dataset.dateTimeFormat) pickerOptions.timeFormat = dataset.dateTimeFormat;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const supportedViews = ['days', 'months', 'years'];
|
|
154
|
+
if (supportedViews.includes(dataset.dateView ?? '')) {
|
|
155
|
+
pickerOptions.view = dataset.dateView as AirDatepickerOptions['view'];
|
|
156
|
+
}
|
|
157
|
+
if (supportedViews.includes(dataset.dateMinView ?? '')) {
|
|
158
|
+
pickerOptions.minView = dataset.dateMinView as AirDatepickerOptions['minView'];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (dataset.dateMobile === 'true') pickerOptions.isMobile = true;
|
|
162
|
+
if (dataset.datePosition) {
|
|
163
|
+
pickerOptions.position = dataset.datePosition as AirDatepickerOptions['position'];
|
|
164
|
+
}
|
|
165
|
+
if (dataset.dateButtons) {
|
|
166
|
+
const supportedButtons = ['today', 'clear'];
|
|
167
|
+
pickerOptions.buttons = dataset.dateButtons
|
|
168
|
+
.split(',')
|
|
169
|
+
.map(button => button.trim())
|
|
170
|
+
.filter(button => supportedButtons.includes(button)) as AirDatepickerOptions['buttons'];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (this.el.hasAttribute('min') && this.el.getAttribute('min')) {
|
|
174
|
+
pickerOptions.minDate = new Date(this.el.getAttribute('min') as string);
|
|
175
|
+
}
|
|
176
|
+
if (this.el.hasAttribute('max') && this.el.getAttribute('max')) {
|
|
177
|
+
pickerOptions.maxDate = new Date(this.el.getAttribute('max') as string);
|
|
178
|
+
}
|
|
179
|
+
if (!this.el.required && !pickerOptions.buttons) {
|
|
180
|
+
pickerOptions.buttons = ['clear'];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
pickerOptions.onSelect = ({ date }: any) => {
|
|
184
|
+
if (multiple && Array.isArray(date) && date.length === 1) return;
|
|
185
|
+
this.el.dispatchEvent(new Event('input', { bubbles: true }));
|
|
186
|
+
this.el.dispatchEvent(new Event('change', { bubbles: true }));
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
this.picker = new AirDatepicker(this.el, pickerOptions);
|
|
190
|
+
document.addEventListener('click', this._handleOutsideClick);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -142,10 +142,35 @@
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
.navbar .brand-logo.center {
|
|
145
|
+
position: absolute;
|
|
145
146
|
left: 50%;
|
|
146
147
|
transform: translateX(-50%);
|
|
147
148
|
}
|
|
148
149
|
|
|
150
|
+
/* Collision-safe centered app bar: the left link region and the generated
|
|
151
|
+
right spacer share the available width, keeping the logo truly centered
|
|
152
|
+
without taking it out of the flex layout. */
|
|
153
|
+
.navbar.appbar-bordered .nav-wrapper.nav-wrapper-centered::after {
|
|
154
|
+
content: '';
|
|
155
|
+
order: 3;
|
|
156
|
+
flex: 1 1 0;
|
|
157
|
+
min-width: 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.navbar.appbar-bordered .nav-wrapper.nav-wrapper-centered > ul {
|
|
161
|
+
order: 1;
|
|
162
|
+
flex: 1 1 0;
|
|
163
|
+
min-width: 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.navbar.appbar-bordered .nav-wrapper.nav-wrapper-centered > .brand-logo.center {
|
|
167
|
+
position: static;
|
|
168
|
+
order: 2;
|
|
169
|
+
flex: 0 0 auto;
|
|
170
|
+
left: auto;
|
|
171
|
+
transform: none;
|
|
172
|
+
}
|
|
173
|
+
|
|
149
174
|
.navbar .brand-logo.right {
|
|
150
175
|
right: 0.5rem;
|
|
151
176
|
padding: 0;
|
|
@@ -168,11 +193,188 @@
|
|
|
168
193
|
margin-right: 15px;
|
|
169
194
|
}
|
|
170
195
|
|
|
196
|
+
/* Structured MD3 app-bar content. These hooks keep branded demos and app
|
|
197
|
+
shells from falling back to bare, loosely spaced anchor elements. */
|
|
198
|
+
.navbar.appbar-bordered {
|
|
199
|
+
overflow: hidden;
|
|
200
|
+
background: var(--md-sys-color-surface-variant);
|
|
201
|
+
border: 1px solid var(--md-sys-color-outline-variant);
|
|
202
|
+
border-radius: 16px;
|
|
203
|
+
box-shadow: 0 1px 2px color-mix(in srgb, var(--md-sys-color-shadow) 18%, transparent);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* Extended app bars may contain tabs and a halfway FAB. Keep the rounded
|
|
207
|
+
surface on its children, but let the FAB extend below the bar. */
|
|
208
|
+
.navbar.appbar-bordered.nav-extended {
|
|
209
|
+
overflow: visible;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.navbar.appbar-bordered.nav-extended .nav-wrapper {
|
|
213
|
+
border-radius: 15px 15px 0 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.navbar.appbar-bordered.nav-extended .nav-content {
|
|
217
|
+
color: var(--md-sys-color-on-surface);
|
|
218
|
+
background: var(--md-sys-color-surface-variant);
|
|
219
|
+
border-radius: 0 0 15px 15px;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.navbar.appbar-bordered .nav-wrapper {
|
|
223
|
+
gap: 12px;
|
|
224
|
+
padding-inline: 12px;
|
|
225
|
+
background: var(--md-sys-color-surface-variant);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.navbar .brand-logo .brand-logo-image {
|
|
229
|
+
box-sizing: border-box;
|
|
230
|
+
width: 40px;
|
|
231
|
+
height: 40px;
|
|
232
|
+
margin-right: 10px;
|
|
233
|
+
padding: 8px;
|
|
234
|
+
object-fit: contain;
|
|
235
|
+
background: var(--md-sys-color-primary-container);
|
|
236
|
+
border-radius: 12px;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.navbar .nav-separator {
|
|
240
|
+
flex: 0 0 1px;
|
|
241
|
+
width: 1px;
|
|
242
|
+
height: 32px;
|
|
243
|
+
margin-inline: 4px;
|
|
244
|
+
background: var(--md-sys-color-outline-variant);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.navbar .nav-context {
|
|
248
|
+
color: var(--md-sys-color-on-surface-variant);
|
|
249
|
+
font-size: 14px;
|
|
250
|
+
white-space: nowrap;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.navbar ul.nav-actions:not(.dropdown-content) {
|
|
254
|
+
gap: 8px;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.navbar.appbar-bordered ul:not(.dropdown-content):not(.nav-actions):not(.tabs) > li > a:not(.btn):not(.btn-floating) {
|
|
258
|
+
box-sizing: border-box;
|
|
259
|
+
height: 40px;
|
|
260
|
+
padding-inline: 12px;
|
|
261
|
+
line-height: 40px;
|
|
262
|
+
border-radius: 20px;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.navbar.appbar-bordered ul:not(.dropdown-content):not(.nav-actions):not(.tabs) > li > a:not(.btn):not(.btn-floating):hover {
|
|
266
|
+
background: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.navbar.appbar-bordered ul:not(.dropdown-content):not(.nav-actions):not(.tabs) > li.active > a:not(.btn):not(.btn-floating) {
|
|
270
|
+
color: var(--md-sys-color-on-primary-container);
|
|
271
|
+
background: var(--md-sys-color-primary-container);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* Text links use the same centred row as the app bar. The global navbar icon
|
|
275
|
+
rule intentionally sizes standalone icons to the full bar; undo that for
|
|
276
|
+
icons embedded beside link text. */
|
|
277
|
+
.navbar.appbar-bordered ul:not(.dropdown-content):not(.tabs) > li > a:not(.btn):not(.btn-floating):has(> .material-icons.left),
|
|
278
|
+
.navbar.appbar-bordered ul:not(.dropdown-content):not(.tabs) > li > a:not(.btn):not(.btn-floating):has(> .material-icons.right),
|
|
279
|
+
.navbar.appbar-bordered .dropdown-trigger:has(> .material-icons) {
|
|
280
|
+
display: inline-flex;
|
|
281
|
+
align-items: center;
|
|
282
|
+
gap: 8px;
|
|
283
|
+
min-height: 40px;
|
|
284
|
+
font-size: 16px;
|
|
285
|
+
line-height: 1;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.navbar.appbar-bordered ul:not(.dropdown-content):not(.tabs) > li > a > .material-icons:is(.left, .right) {
|
|
289
|
+
width: 24px;
|
|
290
|
+
height: 24px;
|
|
291
|
+
margin: 0;
|
|
292
|
+
line-height: 24px;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.navbar.appbar-bordered ul:not(.dropdown-content):not(.tabs) > li > a > .material-icons.right {
|
|
296
|
+
order: 1;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* Tabs retain their component geometry and click target instead of inheriting
|
|
300
|
+
navigation-pill spacing. */
|
|
301
|
+
.navbar.appbar-bordered .tabs {
|
|
302
|
+
gap: 0;
|
|
303
|
+
background: transparent;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.navbar.appbar-bordered .tabs .tab > a {
|
|
307
|
+
height: 48px;
|
|
308
|
+
min-height: 48px;
|
|
309
|
+
padding-inline: 24px;
|
|
310
|
+
line-height: 48px;
|
|
311
|
+
border-radius: 0;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* Buttons must remain legible and vertically centred in the constrained app
|
|
315
|
+
bar row, including legacy examples using btn-large. */
|
|
316
|
+
.navbar.appbar-bordered ul:not(.dropdown-content) > li > :is(.btn, .btn-large) {
|
|
317
|
+
box-sizing: border-box;
|
|
318
|
+
max-height: 48px;
|
|
319
|
+
margin: 0;
|
|
320
|
+
color: var(--md-sys-color-on-primary);
|
|
321
|
+
white-space: nowrap;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.navbar.appbar-bordered ul:not(.dropdown-content) > li > :is(.btn, .btn-large) > .material-icons {
|
|
325
|
+
width: 20px;
|
|
326
|
+
height: 20px;
|
|
327
|
+
margin-left: 8px;
|
|
328
|
+
line-height: 20px;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.navbar.appbar-bordered ul:not(.dropdown-content) > li > a:has(> .material-icons:only-child) {
|
|
332
|
+
display: grid;
|
|
333
|
+
place-items: center;
|
|
334
|
+
width: 40px;
|
|
335
|
+
padding: 0;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.navbar.appbar-bordered ul:not(.dropdown-content) > li > a:has(> .material-icons:only-child) > .material-icons {
|
|
339
|
+
width: 24px;
|
|
340
|
+
height: 24px;
|
|
341
|
+
line-height: 24px;
|
|
342
|
+
text-align: center;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.navbar ul.nav-actions:not(.dropdown-content) > li > :is(.btn, .btn-floating) {
|
|
346
|
+
margin: 0;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.navbar .nav-actions .btn-floating {
|
|
350
|
+
display: inline-grid;
|
|
351
|
+
place-items: center;
|
|
352
|
+
width: 40px;
|
|
353
|
+
height: 40px;
|
|
354
|
+
padding: 0;
|
|
355
|
+
border-radius: 50%;
|
|
356
|
+
box-shadow: none;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.navbar .nav-actions .btn-floating > .material-icons {
|
|
360
|
+
display: block;
|
|
361
|
+
width: 24px;
|
|
362
|
+
height: 24px;
|
|
363
|
+
line-height: 24px;
|
|
364
|
+
text-align: center;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.navbar .nav-actions .btn > .material-icons {
|
|
368
|
+
height: 16px;
|
|
369
|
+
line-height: 16px;
|
|
370
|
+
}
|
|
371
|
+
|
|
171
372
|
/* Title */
|
|
172
373
|
.navbar .nav-title {
|
|
173
374
|
display: inline-block;
|
|
375
|
+
color: var(--md-sys-color-on-surface);
|
|
174
376
|
font-size: 32px;
|
|
175
|
-
padding: 28px
|
|
377
|
+
padding: 20px 24px 28px;
|
|
176
378
|
}
|
|
177
379
|
|
|
178
380
|
/* Navbar Search Form */
|
|
@@ -235,6 +437,7 @@
|
|
|
235
437
|
}
|
|
236
438
|
|
|
237
439
|
.nav,
|
|
440
|
+
.navbar,
|
|
238
441
|
.navbar .nav-wrapper i,
|
|
239
442
|
nav a.sidenav-trigger,
|
|
240
443
|
.navbar a.sidenav-trigger i {
|