From 63a0ff6b22f51d6ca71312329c2a88726ff4805b Mon Sep 17 00:00:00 2001 From: Brian Hanson Date: Mon, 28 Sep 2026 16:27:31 -0500 Subject: [PATCH 01/45] Update changelog Staring to port the Shopify plugin and had to make these undocumented changes --- CHANGELOG.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bafc24ff76e..806d5226709 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,6 +88,9 @@ - Added Markdown comments to element activity timelines, with support for editing, removing, structured user mentions, and email notifications. - Added `CraftCms\Cms\Activity\Contracts\ShouldBeRetained`, allowing activity event types such as comments to opt out of activity garbage collection. - Restored expand/collapse and drag interactions on structure element index views. ([#19691](https://github.com/craftcms/cms/pull/19691)) +- `CraftCms\Cms\Element\Element::searchableAttributes()` is now `final`. `defineSearchableAttributes()` should be overridden instead, including by element types extending `craft\base\Element` through the Yii adapter. +- `CraftCms\Cms\Element\Element::prepareEditScreen()` now accepts a `Symfony\Component\HttpFoundation\Response|CraftCms\Cms\Http\Responses\CpScreenResponse` argument, rather than `yii\web\Response`. Overrides must update their signatures. +- `CraftCms\Cms\Element\Queries\ElementQuery::statusCondition()` now returns a `Closure` which modifies an `Illuminate\Database\Query\Builder`, rather than a Yii query condition. Overrides must update their signatures and return closures. - Fixed a bug where plugin-provided download element actions didn’t trigger file downloads from element indexes. ([#19730](https://github.com/craftcms/cms/pull/19730)) - Fixed a bug where saving an element draft could send a redundant autosave request. ([#19704](https://github.com/craftcms/cms/pull/19704)) - Fixed a bug where `resave` and `update-statuses` commands reported skipped revisions as root element lookup errors. @@ -111,11 +114,15 @@ ### Plugins & Extensibility - Added support for fluent plugin settings classes. ([#19574](https://github.com/craftcms/cms/pull/19574)) - Added support for refreshable standard plugin settings forms and conditional configuration of core form nodes. ([#19545](https://github.com/craftcms/cms/pull/19545)) -- Added `CraftCms\Cms\Contracts\PluginInterface::createSettings()`, which replaces `createSettingsModel()`. ([#19574](https://github.com/craftcms/cms/pull/19574)) +- Added `CraftCms\Cms\Plugin\Concerns\HasSettings::createSettings()`, a static method which replaces `createSettingsModel()`. ([#19574](https://github.com/craftcms/cms/pull/19574)) - Added `CraftCms\Cms\Dashboard\Widgets\Widget::component()` and `props()`, which replace `getBodyHtml()`. ([#19564](https://github.com/craftcms/cms/pull/19564)) - Added `CraftCms\Cms\Support\Url::stripCpTrigger()`. ([#19724](https://github.com/craftcms/cms/pull/19724)) +- Plugin settings models must now extend `CraftCms\Cms\Plugin\PluginSettings` rather than `craft\base\Model`. +- Plugin settings are now validated using Laravel validation rules returned by `CraftCms\Cms\Plugin\PluginSettings::getRules()`, rather than Yii validation rules returned by `rules()`. Validation errors are added via the `$fail` callback or `errors()`, rather than `addError()`. +- Plugin settings are now persisted based on the settings model’s public properties, via `CraftCms\Cms\Plugin\PluginSettings::configData()`. Settings stored in private properties with getter and setter methods must be redeclared as public properties, or included by overriding `configData()`. +- `craft\base\Model::attributes()` now declares an `array` return type. Overrides must update their signatures. - `CraftCms\Cms\Support\Url::removeParam()` now accepts an array of param names. ([#19724](https://github.com/craftcms/cms/pull/19724)) -- Removed `CraftCms\Cms\Contracts\PluginInterface::createSettingsModel()`. `createSettings()` must be implemented instead. ([#19574](https://github.com/craftcms/cms/pull/19574)) +- Removed `CraftCms\Cms\Plugin\Contracts\PluginInterface::createSettingsModel()`. The static `createSettings()` must be implemented instead. (`createSettingsModel()` remains supported for plugins extending `craft\base\Plugin` through the Yii adapter.) ([#19574](https://github.com/craftcms/cms/pull/19574)) - Removed `CraftCms\Cms\Dashboard\Widgets\Widget::getBodyHtml()`. `component()` and `props()` must be implemented instead. (`getBodyHtml()` remains supported through the Yii adapter.) ([#19564](https://github.com/craftcms/cms/pull/19564)) - Removed `CraftCms\Cms\Support\Url::baseUrl()`, `cpHost()`, `encodeParams()`, `host()`, `isFullUrl()`, `removeParams()`, and `rootRelativeUrl()`. (They remain available on `craft\helpers\UrlHelper` through the Yii adapter.) ([#19724](https://github.com/craftcms/cms/pull/19724)) - Added `Cp.$elementDetailsTabs`, allowing plugins to register control panel element-details tabs. ([#19646](https://github.com/craftcms/cms/pull/19646)) From 91b27dab1f5a9a6a5488293598d8c07e001fb563 Mon Sep 17 00:00:00 2001 From: Brian Hanson Date: Wed, 30 Sep 2026 16:46:35 -0500 Subject: [PATCH 02/45] Render autosuggest inputs as craft-combobox --- CHANGELOG.md | 6 + .../src/components/combobox/combobox.ts | 8 + .../_includes/forms/autosuggest.twig | 192 +----------------- .../_includes/forms/editableTable.twig | 2 - src/Cp/Components/Combobox.php | 19 +- src/Cp/FormFields.php | 145 +++++++++++++ src/Cp/SelectOptions.php | 17 +- src/Twig/Variables/Cp.php | 13 ++ 8 files changed, 213 insertions(+), 189 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 806d5226709..1798b84f356 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ - Improved the overall accessibility of the control panel. ([#19699](https://github.com/craftcms/cms/pull/19699)) - Improved the accessibility of element indexes. ([#19520](https://github.com/craftcms/cms/pull/19520)) - Replaced core inline element editing inputs with Form API controls rendered by Vue, with plugin field HTML compatibility handled by the Yii adapter. ([#19590](https://github.com/craftcms/cms/pull/19590)) +- Autosuggest inputs are now rendered as `` web components, rather than Vue 2 `vue-autosuggest` instances. +- Autosuggest inputs now match suggestions on their hint as well as their label, and no longer cap each suggestion group at five items. - Improved the styling for collapsible field groups. - Improved disabled secondary form actions with explanatory tooltips. - The “Assets” system settings nav item is now listed under “Content”, and “Globals”, “Categories”, and “Tags” are now listed under a new “Deprecated” heading, if those concepts are supported for the project. ([#19670](https://github.com/craftcms/cms/pull/19670)) @@ -25,6 +27,7 @@ - Fixed a bug where pressing Ctrl/Cmd + S in a slideout could also save the page behind it. ([#19705](https://github.com/craftcms/cms/pull/19705)) - Fixed a bug where Shift-selecting a shorter range didn’t deselect items outside the new range. ([#19727](https://github.com/craftcms/cms/pull/19727)) - Fixed a bug where select inputs could lose their selected value if their options were loaded asynchronously. ([#19728](https://github.com/craftcms/cms/pull/19728)) +- Fixed a bug where environment variable, alias, and template suggestions weren’t sorted alphabetically. ### Assets - Migrated Control Panel uploads to the native Uppy picker and shared upload sessions, including user photos. @@ -117,6 +120,8 @@ - Added `CraftCms\Cms\Plugin\Concerns\HasSettings::createSettings()`, a static method which replaces `createSettingsModel()`. ([#19574](https://github.com/craftcms/cms/pull/19574)) - Added `CraftCms\Cms\Dashboard\Widgets\Widget::component()` and `props()`, which replace `getBodyHtml()`. ([#19564](https://github.com/craftcms/cms/pull/19564)) - Added `CraftCms\Cms\Support\Url::stripCpTrigger()`. ([#19724](https://github.com/craftcms/cms/pull/19724)) +- Added `craft.cp.autosuggest()` and `CraftCms\Cms\Cp\FormFields::autosuggestFromConfig()`, which render the legacy autosuggest variables as a combobox. Craft 5’s `suggestions` shape is still accepted. +- Added `CraftCms\Cms\Cp\Components\Combobox::labelledBy()`, for a combobox labelled by an element the caller renders itself. - Plugin settings models must now extend `CraftCms\Cms\Plugin\PluginSettings` rather than `craft\base\Model`. - Plugin settings are now validated using Laravel validation rules returned by `CraftCms\Cms\Plugin\PluginSettings::getRules()`, rather than Yii validation rules returned by `rules()`. Validation errors are added via the `$fail` callback or `errors()`, rather than `addError()`. - Plugin settings are now persisted based on the settings model’s public properties, via `CraftCms\Cms\Plugin\PluginSettings::configData()`. Settings stored in private properties with getter and setter methods must be redeclared as public properties, or included by overriding `configData()`. @@ -126,6 +131,7 @@ - Removed `CraftCms\Cms\Dashboard\Widgets\Widget::getBodyHtml()`. `component()` and `props()` must be implemented instead. (`getBodyHtml()` remains supported through the Yii adapter.) ([#19564](https://github.com/craftcms/cms/pull/19564)) - Removed `CraftCms\Cms\Support\Url::baseUrl()`, `cpHost()`, `encodeParams()`, `host()`, `isFullUrl()`, `removeParams()`, and `rootRelativeUrl()`. (They remain available on `craft\helpers\UrlHelper` through the Yii adapter.) ([#19724](https://github.com/craftcms/cms/pull/19724)) - Added `Cp.$elementDetailsTabs`, allowing plugins to register control panel element-details tabs. ([#19646](https://github.com/craftcms/cms/pull/19646)) +- Removed the `data` and `methods` blocks from the `_includes/forms/autosuggest.twig` template, along with the Vue instance they configured. Templates that overrode them should pass `suggestions` instead. - Stopped loading the deprecated `XRegExp` library by default. Plugins that require it can register `craft\web\assets\xregexp\XregexpAsset`. ([#19621](https://github.com/craftcms/cms/pull/19621)) ### System diff --git a/packages/craftcms-ui/src/components/combobox/combobox.ts b/packages/craftcms-ui/src/components/combobox/combobox.ts index c20a73fb97e..569d7266b7d 100644 --- a/packages/craftcms-ui/src/components/combobox/combobox.ts +++ b/packages/craftcms-ui/src/components/combobox/combobox.ts @@ -271,6 +271,14 @@ export default class CraftCombobox extends HasLabel(LionCombobox) { override updated(changed: Map) { super.updated(changed); + // An `aria-labelledby` on the host names a label the consumer renders + // itself — a table column heading, say — rather than one in the `label` + // slot. Lion rewrites the textbox's own `aria-labelledby` from its (empty) + // label on every update, so this has to be reapplied after `super`. + const labelledBy = this.getAttribute('aria-labelledby'); + if (labelledBy) { + this._inputNode?.setAttribute('aria-labelledby', labelledBy); + } // Lion names the listbox after its own label only, which is empty when a // wrapping craft-field provides the label. this._listboxNode?.setAttribute( diff --git a/resources/templates/_includes/forms/autosuggest.twig b/resources/templates/_includes/forms/autosuggest.twig index 6f9f6bdc531..32b359773d0 100644 --- a/resources/templates/_includes/forms/autosuggest.twig +++ b/resources/templates/_includes/forms/autosuggest.twig @@ -1,184 +1,14 @@ -{% import '_includes/forms.twig' as forms %} +{# Renders a `` from the legacy autosuggest variables + (`suggestions`, `suggestTemplates`, `suggestEnvVars`, `suggestAliases`, + `suggestionFilter`, `id`, `name`, `value`, `placeholder`, `disabled`, + `readonly`, `required`, `limit`, `describedBy`, `labelledBy`). -{% do registerLegacyAsset("CraftCms\\Cms\\View\\LegacyAssets\\VueAsset") %} + Craft 5 rendered a Vue 2 `vue-autosuggest` instance here. The mapping onto + the combobox — and the legacy variables that have no equivalent — is + documented on FormFields::autosuggestFromConfig(). -{% set suggestions = (suggestions ?? []) - |merge((suggestTemplates ?? false) ? cpTemplateSuggestions() : []) - |merge((suggestEnvVars ?? false) ? cpEnvSuggestions( - suggestAliases ?? false, - suggestionFilter ?? null - ) : []) %} + `{% block data %}` and `{% block methods %}` are gone with the Vue instance + they configured. Nothing in Craft overrode them, and a template that did will + need to supply `suggestions` instead. #} -{%- set id = id ?? "autosuggest#{random()}" %} -{%- set previewInputId = "#{id}-preview" %} -{%- set containerId = "#{id}-container" %} -{%- set autosuggestId = "#{id}-autosuggest" %} -{%- set describedBy = describedBy ?? null -%} -{%- set labelledBy = labelledBy ?? null -%} - -{%- set class = (class ?? [])|explodeClass|merge([ - 'text', - not (size ?? false) ? 'fullwidth' : null, -]|filter) %} - -
- {{ forms.text({ - id: previewInputId, - class: class|join(' '), - value: value ?? '', - style: style ?? '', - size: size ?? '', - disabled: true, - title: title ?? '', - placeholder: placeholder ?? '', - }) }} - - {% verbatim %} - - - - {% endverbatim %} -
- -{% js %} -(() => { -$("#{{ previewInputId|namespaceInputId|e('js') }}").remove(); - -new Vue({ - el: "#{{ containerId|namespaceInputId|e('js') }}", - - data() { - {% block data %} - var data = {{ { - query: (value ?? '')|lower, - selected: '', - filteredOptions: [], - suggestions, - id: autosuggestId, - inputProps: { - class: class|join(' '), - initialValue: value ?? '', - style: style ?? '', - id: id|namespaceInputId, - name: (name ?? '')|namespaceInputName, - size: size ?? '', - maxlength: maxlength ?? '', - autofocus: (autofocus ?? false) and currentUser and currentUser.getAutofocusPreferred() and not Request.isMobileBrowser(true), - disabled: disabled ?? false, - title: title ?? '', - placeholder: placeholder ?? '', - 'aria-describedby': describedBy ? describedBy|split(' ')|map(id => id|namespaceInputId)|join(' ') : false, - 'aria-labelledby': labelledBy ? labelledBy|split(' ')|map(id => id|namespaceInputId)|join(' ') : false, - }|merge(inputProps ?? inputAttributes ?? [], recursive=true)|filter, - limit: limit ?? 5 - }|json_encode|raw }}; - {% endblock %} - return data; - }, - - methods: { - {% block methods %} - onInputChange(q) { - this.query = (q || '').toLowerCase(); - this.updateFilteredOptions(); - }, - updateFilteredOptions() { - if (this.query === '') { - this.filteredOptions = this.suggestions; - return; - } - - var filtered = []; - var i, j, sectionFilter, item, name; - var that = this; - - for (i = 0; i < this.suggestions.length; i++) { - sectionFilter = []; - for (j = 0; j < this.suggestions[i].data.length; j++) { - item = this.suggestions[i].data[j]; - if ( - (item.name || item).toLowerCase().indexOf(this.query) !== -1 || - (item.hint && item.hint.toLowerCase().indexOf(this.query) !== -1) - ) { - sectionFilter.push(item.name ? item : {name: item}); - } - } - if (sectionFilter.length) { - sectionFilter.sort(function(a, b) { - var scoreA = that.scoreItem(a); - var scoreB = that.scoreItem(b); - if (scoreA === scoreB) { - return 0; - } - return scoreA < scoreB ? 1 : -1; - }); - filtered.push({ - label: this.suggestions[i].label || null, - data: sectionFilter.slice(0, this.limit) - }); - } - } - - this.filteredOptions = filtered; - }, - scoreItem(item) { - var score = 0; - if (item.name.toLowerCase().indexOf(this.query) !== -1) { - score += 100 + this.query.length / item.name.length; - } - if (item.hint && item.hint.toLowerCase().indexOf(this.query) !== -1) { - score += this.query.length / item.hint.length; - } - return score; - }, - onSelected(option) { - if (!option) { - return; - } - - this.selected = option.item; - - // Bring focus back to the input if they selected an alias - if (option.item.name[0] == '@') { - var input = this.$el.querySelector('input'); - input.focus(); - input.selectionStart = input.selectionEnd = input.value.length; - } - }, - getSuggestionValue(suggestion) { - return suggestion.item.name || suggestion.item; - }, - onBlur(e) { - // Related target - element clicked or that focused moved to. - // Current target - the input element that is losing focus. - const { currentTarget, relatedTarget } = e; - - // Click event bubbles from listbox to the .autosuggest-container (requires tabindex="-1") - // We only want to clear the filteredOptions if the focus moved outside the autosuggest container - // (i.e. not to the listbox or one of its children) - - const targetIsOutsideAutosuggestContainer = relatedTarget && !relatedTarget.contains(currentTarget); - - if (targetIsOutsideAutosuggestContainer) { - this.filteredOptions = []; - } - }, - {% endblock %} - } -}); -})(); -{% endjs %} +{{- craft.cp.autosuggest(_context)|raw -}} diff --git a/resources/templates/_includes/forms/editableTable.twig b/resources/templates/_includes/forms/editableTable.twig index ad8b3df02bf..b4ee972d294 100644 --- a/resources/templates/_includes/forms/editableTable.twig +++ b/resources/templates/_includes/forms/editableTable.twig @@ -55,8 +55,6 @@ {%- switch col.type %} {%- case 'time' %} {%- do registerLegacyAsset('CraftCms\\Cms\\View\\LegacyAssets\\TimepickerAsset') %} - {%- case 'template' %} - {%- do registerLegacyAsset("CraftCms\\Cms\\View\\LegacyAssets\\VueAsset") %} {%- endswitch %} {% endfor %} diff --git a/src/Cp/Components/Combobox.php b/src/Cp/Components/Combobox.php index d91db23b918..9ac6eda0f4a 100644 --- a/src/Cp/Components/Combobox.php +++ b/src/Cp/Components/Combobox.php @@ -45,6 +45,8 @@ class Combobox extends ViewComponent protected ?string $describedBy = null; + protected ?string $labelledBy = null; + protected function tagName(): string { return 'craft-combobox'; @@ -154,6 +156,18 @@ public function describedBy(?string $describedBy): static return $this; } + /** + * Names the element labelling this combobox, for a caller that provides the + * label itself rather than through the `label` slot — a table column + * heading, say. + */ + public function labelledBy(?string $labelledBy): static + { + $this->labelledBy = $labelledBy; + + return $this; + } + #[\Override] protected function hostAttributes(): array { @@ -174,7 +188,10 @@ protected function hostAttributes(): array 'show-all-on-empty' => $this->showAllOnEmpty, 'show-selected-hint' => $this->showSelectedHint, 'dir' => $this->orientation, - 'aria' => ['describedby' => $this->describedBy], + 'aria' => [ + 'describedby' => $this->describedBy, + 'labelledby' => $this->labelledBy, + ], ]; } } diff --git a/src/Cp/FormFields.php b/src/Cp/FormFields.php index 4789a8e5f2a..778db7a26c0 100644 --- a/src/Cp/FormFields.php +++ b/src/Cp/FormFields.php @@ -12,6 +12,7 @@ use CraftCms\Cms\Cp\Components\Checkbox; use CraftCms\Cms\Cp\Components\CheckboxGroup; use CraftCms\Cms\Cp\Components\CheckboxSelect; +use CraftCms\Cms\Cp\Components\Combobox; use CraftCms\Cms\Cp\Components\Field; use CraftCms\Cms\Cp\Components\FieldGroup; use CraftCms\Cms\Cp\Components\Input; @@ -1350,6 +1351,150 @@ public static function entryTypeSelectFieldHtml(array $config): string return self::fieldHtml('template:_includes/forms/entryTypeSelect', $config); } + /** + * Builds a `` from the legacy autosuggest variables. + * + * Craft 5 rendered these with a Vue 2 `vue-autosuggest` instance. The + * combobox matches that behavior where it counts: the value is free text + * (`requireOptionMatch` off), every suggestion is listed as soon as the + * field is focused (`showAllOnEmpty`), sections keep their headings, and a + * suggestion's hint is both shown and matched. + * + * Three legacy config keys have no equivalent and are ignored: `inputProps` + * /`inputAttributes`, `style`, and `class` — the combobox owns its own + * markup. `size`, `maxlength` and `autofocus` are likewise dropped, since + * Lion owns the textbox. + * + * `limit` changes meaning: Craft 5 capped each section separately + * (defaulting to 5), while the combobox caps the whole rendered list. A + * caller that passes one still gets it honored; callers that don't now see + * every match rather than the first five per section. + * + * @param array $config + */ + public static function autosuggestFromConfig(array $config): Combobox + { + $suggestions = self::normalizeSuggestions($config['suggestions'] ?? []); + + if ($config['suggestTemplates'] ?? false) { + $suggestions = [...$suggestions, ...SelectOptions::getTemplateSuggestions()]; + } + + if ($config['suggestEnvVars'] ?? false) { + $suggestions = [...$suggestions, ...SelectOptions::getEnvSuggestions( + (bool) ($config['suggestAliases'] ?? false), + $config['suggestionFilter'] ?? null, + )]; + } + + $component = Combobox::make() + ->id($config['id'] ?? 'autosuggest'.mt_rand()) + ->name($config['name'] ?? null) + ->value(($config['value'] ?? '') === false ? '' : (string) ($config['value'] ?? '')) + ->options($suggestions) + ->placeholder(($config['placeholder'] ?? false) ?: null) + ->disabled((bool) ($config['disabled'] ?? false)) + ->readOnly((bool) ($config['readonly'] ?? false)) + ->required((bool) ($config['required'] ?? false)) + ->describedBy(($config['describedBy'] ?? false) ?: null) + ->labelledBy(($config['labelledBy'] ?? false) ?: null) + ->requireOptionMatch(false) + ->showAllOnEmpty(); + + if (($config['limit'] ?? null) !== null) { + $component = $component->limit((int) $config['limit']); + } + + return $component; + } + + /** + * Brings a `suggestions` array into the shape `` takes. + * + * Core passes {@see SelectOptions} output, which is already that shape. A + * plugin may pass Craft 5's instead — groups as `['label' => …, 'data' => + * [['name' => …, 'hint' => …], …]]`, with a bare string standing in for an + * item — either hand-written or from the deprecated + * `craft.cp.getEnvSuggestions()`. Both are accepted, so a plugin's existing + * call keeps working untouched. + * + * @param array $suggestions + * @return list> + */ + private static function normalizeSuggestions(array $suggestions): array + { + $normalized = []; + + foreach ($suggestions as $entry) { + if (! is_array($entry)) { + $normalized[] = self::normalizeSuggestionOption($entry); + + continue; + } + + // A Craft 5 section: a label plus a *list* of items under `data`. + // A combobox option also has `data`, but as a keyed map, and always + // carries a `value` — so the two never collide. + $isLegacyGroup = ! isset($entry['value']) + && isset($entry['data']) + && is_array($entry['data']) + && array_is_list($entry['data']); + + if (($entry['type'] ?? null) === 'optgroup' || $isLegacyGroup) { + $options = $entry['options'] ?? $entry['data'] ?? []; + + $normalized[] = [ + 'type' => 'optgroup', + 'label' => $entry['label'] ?? '', + 'options' => array_map( + self::normalizeSuggestionOption(...), + array_values(is_array($options) ? $options : []), + ), + ]; + + continue; + } + + $normalized[] = self::normalizeSuggestionOption($entry); + } + + return $normalized; + } + + /** + * @return array + */ + private static function normalizeSuggestionOption(mixed $option): array + { + if (! is_array($option)) { + $value = (string) $option; + + return ['label' => $value, 'value' => $value]; + } + + // Already a combobox option. + if (isset($option['value'])) { + return [ + ...$option, + 'label' => (string) ($option['label'] ?? $option['value']), + 'value' => (string) $option['value'], + ]; + } + + $value = (string) ($option['name'] ?? $option['label'] ?? ''); + $hint = $option['hint'] ?? null; + + return [ + 'label' => $value, + 'value' => $value, + 'data' => [ + 'hint' => $hint, + // Craft 5 matched the hint as well as the name. + 'keywords' => is_string($hint) ? $hint : null, + ], + ]; + } + /** @param array $config */ public static function autosuggestFieldHtml(array $config): string { diff --git a/src/Cp/SelectOptions.php b/src/Cp/SelectOptions.php index 3d30e33db71..07ab96af2c4 100644 --- a/src/Cp/SelectOptions.php +++ b/src/Cp/SelectOptions.php @@ -34,7 +34,7 @@ /** * @phpstan-import-type TextExpanderTrigger from HasTextExpander * - * @phpstan-type SuggestionOption array{label: string, value: string, data: array{hint: mixed}} + * @phpstan-type SuggestionOption array{label: string, value: string, data: array{hint: mixed, keywords?: string|null}} */ class SelectOptions { @@ -62,11 +62,16 @@ public static function getEnvSuggestions(bool $includeAliases = false, ?callable is_scalar($env = Env::get($var)) && (! $filter || $filter($env)) ) { + $hint = Security::redactIfSensitive($var, Aliases::get((string) $env, false)); $envSuggestions[] = [ 'label' => '$'.$var, 'value' => '$'.$var, 'data' => [ - 'hint' => Security::redactIfSensitive($var, Aliases::get((string) $env, false)), + 'hint' => $hint, + // The hint is a variable's value, and Craft 5's autosuggest + // matched against it — so you can find `$PRIMARY_SITE_URL` + // by typing part of the URL it holds. + 'keywords' => $hint, ], ]; } @@ -75,7 +80,7 @@ public static function getEnvSuggestions(bool $includeAliases = false, ?callable $suggestions[] = [ 'type' => 'optgroup', 'label' => t('Environment Variables'), - 'options' => array_values(Arr::sort($envSuggestions, 'name')), + 'options' => array_values(Arr::sort($envSuggestions, 'label')), ]; if ($includeAliases) { @@ -87,6 +92,7 @@ public static function getEnvSuggestions(bool $includeAliases = false, ?callable 'value' => $alias, 'data' => [ 'hint' => $path, + 'keywords' => is_string($path) ? $path : null, ], ]; } @@ -94,7 +100,7 @@ public static function getEnvSuggestions(bool $includeAliases = false, ?callable $suggestions[] = [ 'type' => 'optgroup', 'label' => t('Aliases'), - 'options' => array_values(Arr::sort($aliasSuggestions, 'name')), + 'options' => array_values(Arr::sort($aliasSuggestions, 'label')), ]; } @@ -568,6 +574,7 @@ public static function getTemplateSuggestions(): array 'value' => $template, 'data' => [ 'hint' => $hint, + 'keywords' => $hint, ], ]; } @@ -578,7 +585,7 @@ public static function getTemplateSuggestions(): array [ 'label' => t('Templates'), 'type' => 'optgroup', - 'options' => array_values(Arr::sort($suggestions, 'name')), + 'options' => array_values(Arr::sort($suggestions, 'label')), ], ]; } diff --git a/src/Twig/Variables/Cp.php b/src/Twig/Variables/Cp.php index f58d691988b..fdc1dc95d4d 100644 --- a/src/Twig/Variables/Cp.php +++ b/src/Twig/Variables/Cp.php @@ -331,6 +331,19 @@ public function text(array $config = []): string return FormFields::textFromConfig($config)->toHtml(); } + /** + * Renders an autosuggest input's HTML from the legacy autosuggest variables. + * + * Emits a ``; see + * {@see FormFields::autosuggestFromConfig()} for how the legacy variables + * map onto it and which have no equivalent. + */ + /** @param array $config */ + public function autosuggest(array $config = []): string + { + return FormFields::autosuggestFromConfig($config)->toHtml(); + } + /** * Renders a copy-text input's HTML from the legacy copytext variables. */ From 2522a63191c9bbe55f2eaeffd407662065f79962 Mon Sep 17 00:00:00 2001 From: Brian Hanson Date: Tue, 6 Oct 2026 09:47:29 -0500 Subject: [PATCH 03/45] Save legacy screen bridge work in progress before merging 6.x --- CHANGELOG-WIP.md | 3 + .../craftcms-legacy/cp/src/css.bkup/_cp.scss | 1864 ++++ .../cp/src/css.bkup/_craft-spinner.scss | 10 + .../cp/src/css.bkup/_craft-tooltip.scss | 67 + .../cp/src/css.bkup/_debug_toolbar.scss | 3 + .../cp/src/css.bkup/_entry-type-select.scss | 39 + .../cp/src/css.bkup/_global-sidebar.scss | 436 + .../css.bkup/_grouped-entry-type-select.scss | 66 + .../cp/src/css.bkup/_image_editor.scss | 368 + .../cp/src/css.bkup/_login.scss | 199 + .../cp/src/css.bkup/_main.scss | 8064 +++++++++++++++++ .../cp/src/css.bkup/_preview.scss | 340 + .../cp/src/css.bkup/_range.scss | 108 + .../cp/src/css.bkup/_shame.scss | 11 + .../cp/src/css.bkup/_skip-links.scss | 26 + .../cp/src/css.bkup/_variables.scss | 96 + .../cp/src/css.bkup/charts.scss | 65 + .../cp/src/css.bkup/craft.scss | 19 + .../cp/src/css/_color-palette.scss | 224 + .../cp/src/css/_craft-disclosure.scss | 17 + packages/craftcms-legacy/cp/src/css/_fld.scss | 469 + .../craftcms-legacy/cp/src/css/_tokens.scss | 131 + .../cp/src/js/BaseElementIndex.js | 10 +- packages/craftcms-legacy/cp/src/js/Craft.js | 30 +- .../cp/src/js/ElementEditor.js | 43 +- packages/craftcms-legacy/cp/src/js/UI.js | 10 +- .../combobox/combobox-form.browser.test.ts | 73 + .../src/components/combobox/combobox.ts | 38 + .../craftcms-ui/src/styles/shared/base.css | 1 + packages/craftcms-ui/src/utilities/dom.ts | 17 +- resources/css/legacy.css | 198 + .../js/common/composables/useAppLayout.ts | 2 + .../js/common/layouts/screens/PageScreen.vue | 48 +- .../layouts/screens/page/ContentFooter.vue | 13 + resources/js/common/layouts/screens/types.ts | 19 + resources/js/cp.ts | 2 + resources/js/legacy.ts | 6 +- .../components/LegacyAdminTable.test.ts | 183 + .../components/LegacyAdminTable.vue | 152 + .../admin-table/legacy-admin-table.test.ts | 220 + .../modules/admin-table/legacy-admin-table.ts | 158 + .../js/modules/admin-table/types/legacy.ts | 95 + resources/js/modules/forms/runtime.test.ts | 105 +- resources/js/modules/forms/runtime.ts | 115 +- resources/js/pages/cp/ElementIndex.vue | 80 + resources/js/pages/cp/Screen.vue | 169 +- resources/js/pages/utilities/Show.test.ts | 82 + resources/js/pages/utilities/Show.vue | 45 +- .../templates/_layouts/cp-fragments.twig | 56 + resources/templates/_layouts/cp.twig | 10 +- .../templates/_layouts/elementindex.twig | 51 +- resources/views/app.blade.php | 4 + src/Cp/Data/ActionItem.php | 23 +- src/Cp/LegacyTabsShim.php | 68 + src/Cp/Navigation.php | 55 +- src/Element/Queries/ElementQuery.php | 32 + src/Http/Middleware/HandleInertiaRequests.php | 40 +- src/Http/Middleware/RenderBridgedScreen.php | 56 + src/Http/Responses/BridgedScreen.php | 176 + src/Http/Responses/CpScreenResponse.php | 94 +- .../LegacyElementIndexViewModel.php | 30 + src/Route/RouteServiceProvider.php | 4 + src/Twig/Variables/Cp.php | 55 + src/View/HtmlStack.php | 36 +- src/View/LegacyReadyShim.php | 97 + src/View/LegacyScreenFragments.php | 105 + src/View/PageLifecycle.php | 29 +- .../ElementRedirectControllerTest.php | 10 +- .../ElementRevisionsControllerTest.php | 15 +- yii2-adapter/legacy/models/FieldLayout.php | 2 +- yii2-adapter/legacy/queue/BaseBatchedJob.php | 8 +- yii2-adapter/legacy/queue/Queue.php | 9 +- yii2-adapter/legacy/web/Application.php | 76 + yii2-adapter/legacy/web/BridgedScreen.php | 53 + .../legacy/web/CpScreenResponseFormatter.php | 95 +- .../legacy/web/TemplateResponseFormatter.php | 29 +- .../legacy/web/assets/htmx/HtmxAsset.php | 38 + yii2-adapter/src/ClassAliases.php | 2 +- yii2-adapter/src/CompatibilityMixins.php | 3 + yii2-adapter/src/FieldLayout/FieldLayout.php | 28 - .../Http/CaptureOriginalActionRequestUri.php | 11 + yii2-adapter/src/Mixins/ElementQueryMixin.php | 24 + yii2-adapter/src/Mixins/FieldLayoutMixin.php | 58 + yii2-adapter/src/Web/Response.php | 65 +- 84 files changed, 15851 insertions(+), 235 deletions(-) create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_cp.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_craft-spinner.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_craft-tooltip.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_debug_toolbar.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_entry-type-select.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_global-sidebar.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_grouped-entry-type-select.scss create mode 100755 packages/craftcms-legacy/cp/src/css.bkup/_image_editor.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_login.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_main.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_preview.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_range.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_shame.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_skip-links.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/_variables.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/charts.scss create mode 100644 packages/craftcms-legacy/cp/src/css.bkup/craft.scss create mode 100644 packages/craftcms-legacy/cp/src/css/_color-palette.scss create mode 100644 packages/craftcms-legacy/cp/src/css/_craft-disclosure.scss create mode 100644 packages/craftcms-legacy/cp/src/css/_fld.scss create mode 100644 packages/craftcms-legacy/cp/src/css/_tokens.scss create mode 100644 packages/craftcms-ui/src/components/combobox/combobox-form.browser.test.ts create mode 100644 resources/css/legacy.css create mode 100644 resources/js/modules/admin-table/components/LegacyAdminTable.test.ts create mode 100644 resources/js/modules/admin-table/components/LegacyAdminTable.vue create mode 100644 resources/js/modules/admin-table/legacy-admin-table.test.ts create mode 100644 resources/js/modules/admin-table/legacy-admin-table.ts create mode 100644 resources/js/modules/admin-table/types/legacy.ts create mode 100644 resources/js/pages/cp/ElementIndex.vue create mode 100644 resources/js/pages/utilities/Show.test.ts create mode 100644 resources/templates/_layouts/cp-fragments.twig create mode 100644 src/Cp/LegacyTabsShim.php create mode 100644 src/Http/Middleware/RenderBridgedScreen.php create mode 100644 src/Http/Responses/BridgedScreen.php create mode 100644 src/Http/ViewModels/LegacyElementIndexViewModel.php create mode 100644 src/View/LegacyReadyShim.php create mode 100644 src/View/LegacyScreenFragments.php create mode 100644 yii2-adapter/legacy/web/BridgedScreen.php create mode 100644 yii2-adapter/legacy/web/assets/htmx/HtmxAsset.php delete mode 100644 yii2-adapter/src/FieldLayout/FieldLayout.php create mode 100644 yii2-adapter/src/Mixins/FieldLayoutMixin.php diff --git a/CHANGELOG-WIP.md b/CHANGELOG-WIP.md index 727e2783cdb..643fb110682 100644 --- a/CHANGELOG-WIP.md +++ b/CHANGELOG-WIP.md @@ -546,6 +546,9 @@ Craft 6 introduces a new validation system that uses Laravel's Validator instead - Deprecated `\craft\elements\db\ElementQueryInterface` - Deprecated `\craft\elements\db\EntryQuery` `\CraftCms\Cms\Element\Queries\EntryQuery` should be used instead. - Deprecated `\craft\elements\db\UserQuery` `\CraftCms\Cms\Element\Queries\UserQuery` should be used instead. +- Removed `craft\elements\db\ElementQuery::beforePrepare()`. `CraftCms\Cms\Element\Queries\ElementQuery::elementQueryBeforeQuery()` should be overridden instead. +- Removed `craft\elements\db\ElementQuery::joinElementTable()`. Element queries should now declare their element table via the `$table` property, which is joined automatically. +- Removed `craft\elements\db\ElementQuery::$subQuery`. Element queries are now a single query, so joins and conditions should be applied to `$query`. ### Entries & Entry Types diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_cp.scss b/packages/craftcms-legacy/cp/src/css.bkup/_cp.scss new file mode 100644 index 00000000000..d523754dca3 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_cp.scss @@ -0,0 +1,1864 @@ +@charset "UTF-8"; +@use 'sass:color'; +@use '@craftcms/sass/mixins'; + +$sidebarWidth: calc(226rem / 16); +$sidebarZIndex: 100; +$detailsWidth: 350px; +$minFullUiWidth: calc(1200rem / 16); +$minXlUiWidth: calc(1536rem / 16); +$minDesktopWidth: calc(600rem / 16); +$minHorizontalUiWidth: $minFullUiWidth - $sidebarWidth; + +// Colors +$badgeBackgroundColor: var(--gray-200); +$badgeColor: var(--gray-800); + +:root { + --sidebar-width: #{$sidebarWidth}; + --cp-sidebar-width: #{$sidebarWidth}; + --details-width: #{$detailsWidth}; +} + +html { + text-size-adjust: 100%; + min-height: 100vh; +} + +body { + min-height: 100vh; + + &.dragging * { + cursor: move !important; + cursor: grabbing !important; + } +} + +#global-container { + position: relative; + display: flex; + min-height: 100vh; + + @media screen and (prefers-reduced-motion: no-preference) { + transition: inset-inline-start 100ms cubic-bezier(0.33, 1, 0.68, 1); + } +} + +#global-header { + display: grid; + grid-template-columns: 1fr min-content min-content; + align-items: center; +} + +/* global sidebar */ +$sidebarLinkStaticColor: var(--gray-100); +$sidebarLinkSecondaryColor: var(--gray-200); +$systemInfoBgColor: color.adjust(mixins.$grey800, $lightness: -5%); +$systemInfoHoverBgColor: color.adjust(mixins.$grey800, $lightness: -10%); + +#system-info { + display: grid; + grid-template-columns: var(--nav-item-prefix-width) auto; + gap: 10px; + height: 100%; + padding-block: 0; + padding-inline: var(--nav-item-gutter-width); + position: relative; + flex-direction: row; + align-items: center; + color: currentcolor; + background-clip: padding-box; + + &::after { + display: none; + } + + #global-sidebar & { + border-block-end: 1px solid var(--border-hairline); + } +} + +div#system-info { + cursor: default; +} + +a#system-info { + &:focus, + &:hover { + text-decoration: none; + background-color: var(--gray-200); + } +} + +#site-icon { + --size: var(--nav-item-prefix-width); // Matches .sidebar-action__prefix + height: var(--size); + + img, + svg { + display: block; + width: var(--size); + height: var(--size); + border-radius: 4px; + } + + svg { + @include mixins.svg-mask(var(--fg-subtle)); + } +} + +#system-name { + h2, + .h2 { + margin: 0; + width: 100%; + overflow: hidden; + max-height: 40px; + position: relative; + + // Multi-line text overflow ellipsis + // (https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-line-clamp) + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + } +} + +@media only screen and (min-width: $minFullUiWidth) { + [data-sidebar='collapsed'] { + #system-info:hover #system-name { + opacity: 1; + transform: translateY(-50%) translateX(0); + } + + #system-name { + position: absolute; + inset-inline-start: calc(100% + (var(--s) * 2)); + inset-block-start: 50%; + transform: translateY(-50%) translateX(-5px); + opacity: 0; + @include mixins.pane; + color: var(--text-color); + border-radius: var(--radius-md); + padding-block: var(--xs); + padding-inline: var(--s); + white-space: nowrap; + pointer-events: none; + + @media screen and (prefers-reduced-motion: no-preference) { + transition: + opacity 50ms cubic-bezier(0.33, 1, 0.68, 1), + transform 150ms cubic-bezier(0.33, 1, 0.68, 1); + } + } + } +} + +#global-footer { + --link-color: #1453db; + display: flex; + flex-direction: column; + align-items: center; + padding-block: var(--m) var(--xl); + padding-inline: var(--m); + gap: var(--m); + + body.has-debug-toolbar & { + padding-block-end: calc(var(--xl) + 42px); + } + + a { + white-space: nowrap; + } +} + +#app-info { + display: flex; + flex-direction: row; + justify-content: center; + gap: var(--m); +} + +#trial-info { + padding-block: 16px; + padding-inline: var(--xl); + border-radius: var(--radius-lg); + background-color: var(--gray-150); + box-shadow: + inset 0 1px 0 rgb(255 255 255 / 50%), + 0 0 0 1px hsl(212deg 30% 80%), + 0 2px 12px color.adjust(mixins.$grey200, $alpha: -0.5); + text-align: center; +} + +#app-version { + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + color: var(--gray-600); + text-align: center; + gap: var(--s); + + a { + color: var(--gray-600); + text-decoration: underline; + + &.go:hover::after { + color: var(--gray-600); + } + } +} + +#edition-logo { + user-select: none; + border: 1px solid var(--gray-600); + border-radius: 3px; + display: inline-flex; + box-sizing: content-box; + font-size: 11px; + padding-block: 6px; + padding-inline: 7px 5px; + line-height: 8px; + font-weight: 600; + letter-spacing: 1.7px; + text-transform: uppercase; +} + +#devmode { + margin-block-start: auto; + flex: 0 0 4px; + width: 100%; + min-height: 4px; // fixes Windows scaling bug (https://github.com/craftcms/cms/issues/3259) + background: + url('../images/dev-mode.svg') repeat-x 21px 0, + var(--gray-900); + cursor: help; +} + +#page-container { + display: flex; + flex-direction: column; + flex-grow: 1; +} + +#alerts { + position: relative; // to keep it above #global-header's shadow + background-color: var(--red-050); + border-inline-start: 6px solid var(--fg-error); + color: var(--fg-error); + + & > li { + padding-block: 7px 8px; + padding-inline: 24px; + box-shadow: inset 0 -1px 0 0 var(--red-100); + min-height: var(--header-height); + display: flex; + align-items: center; + + span[data-icon]::before { + margin-block-start: -3px !important; + } + + .resolvable-alert-buttons { + margin-block-start: var(--m); + } + + .btn, + a.go { + display: inline-flex; + align-items: center; + border: 1px solid color.adjust(mixins.$errorColor, $alpha: -0.5); + border-radius: var(--radius-md); + padding-block: 4px; + padding-inline: 5px; + margin-block: 0; + margin-inline: 2px; + color: var(--fg-error); + min-height: var(--input-height); + + .flex & { + margin: 0; + } + + &:hover { + border-color: var(--fg-error); + } + } + + a:not(.btn) { + color: var(--fg-error); + text-decoration: underline; + + &.go { + text-decoration: none; + white-space: nowrap; + + &::after { + color: var(--fg-error); + font-size: 15px; + margin-block-start: 1px; + } + } + } + + .btn { + background-color: transparent; + } + } +} + +#global-header .btn.menubtn, +li.crumb .btn.menubtn, +.btn.action-btn { + padding: 0; + + &:not(:hover, :active, [aria-expanded='true']) { + background-color: transparent; + } + + &:not(.m) { + width: var(--touch-target-size); + height: var(--touch-target-size); + min-height: auto; + } + + &.m { + width: var(--ui-control-height); + height: var(--ui-control-height); + } +} + +#global-header { + width: 100%; + margin-block-end: var(--m); + border-block-end: 1px solid var(--border-hairline); + + .flex { + height: var(--header-height); + align-items: center; + } + + .btn { + --ui-control-color: var(--gray-400); + --ui-control-hover-color: var(--gray-800); + --ui-control-active-color: var(--gray-700); + + &:hover { + color: var(--ui-control-hover-color); + } + } +} + +.nav-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 44px; + min-width: 44px; + height: var(--header-height); + border-inline-end: 1px solid var(--border-hairline-medium); + line-height: 26px; + color: currentcolor; + text-align: center; + + &::before { + @include mixins.icon; + content: 'menu'; + font-size: 16px; + line-height: 0; + } + + &:hover { + color: var(--link-color); + } +} + +#crumbs { + display: flex; + flex-direction: row; + align-items: center; + font-size: 13px; + margin: 0 !important; + max-width: 100%; + overflow: hidden; + + &.empty { + display: none; + } + + nav { + margin: 0; + } +} + +#primary-nav-toggle { + &:focus-visible { + box-shadow: var(--focus-ring-inner); + } +} + +#crumb-list { + display: flex; + flex-flow: row nowrap; + align-items: stretch; + max-width: 100%; + height: var(--header-height); + + --arrow-padding: 10; + --arrow-height: 22; + --arrow-angle: 35; + --arrow-width: 17.1111; // height/(45/angle) + --arrow-c: 27.871; // sqrt(height^2+width^2) + + body.rtl & { + --arrow-angle: -35; + } + + li.crumb { + position: relative; + padding-inline-start: calc(var(--arrow-width) * 0.5rem / 16); + cursor: default; + color: var(--light-text-color); + + &:not(.current) { + padding-inline-end: calc(var(--arrow-width) * 1.125rem / 16); + + &::before, + &::after { + display: block; + content: ''; + width: 1px; + height: calc(var(--arrow-c) * 1rem / 16); + position: absolute; + inset-inline-end: calc(var(--arrow-width) * 0.5rem / 16); + background: var(--border-hairline-medium); + pointer-events: none; + } + + &::before { + inset-block-start: calc( + (var(--arrow-height) - var(--arrow-c)) / 2 * 1rem / 16 + ); + transform: rotate(calc(var(--arrow-angle) * -1deg)); + } + + &::after { + inset-block-end: calc( + (var(--arrow-height) - var(--arrow-c)) / 2 * 1rem / 16 + ); + transform: rotate(calc(var(--arrow-angle) * 1deg)); + } + } + } + + & .menu--disclosure { + li { + display: block; + + &::after { + content: none; + } + } + } +} + +#crumb-menu-trigger { + min-width: var(--touch-target-size); + + &::before { + width: 100%; + } +} + +#crumb-menu { + .chip { + min-height: 44px; + } +} + +li.crumb { + display: flex; + align-items: center; + flex-wrap: nowrap; + gap: var(--xs); + + [data-icon] { + position: relative; + inset-block-start: -1px; + } + + .menubtn { + position: relative; + margin-block: 0; + margin-inline: calc(var(--xs) * -1 / 2); + } + + [data-icon='ellipsis']::before { + margin-block-start: 3px; + font-size: 17px; + } + + .chip { + .label-link { + max-width: 15em; + + &:focus-visible { + box-shadow: var(--focus-ring-inner); + } + + & > span:not(.context-label) { + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + } + + &:has(.menubtn) > a { + margin-inline-end: 0 !important; + padding-inline-end: var(--xs) !important; + } + + & > a { + flex: 1; + display: flex !important; + align-items: center; + flex-wrap: nowrap; + gap: var(--xs); + white-space: nowrap; + + .menu--disclosure & { + min-height: 34px; + } + } + + a, + button { + display: inline-flex; + align-items: center; + min-height: var(--touch-target-size); + + &:not(:hover) { + color: var(--text-color); + + svg { + @include mixins.svg-mask(var(--text-color)); + } + } + + &:hover { + text-decoration: none; + } + } + + a:not(:hover) { + text-decoration: underline; + } + + a { + position: relative; + } + + button { + cursor: pointer; + } +} + +li.breadcrumb-toggle-wrapper { + &::after { + content: none; + } +} + +#account-menu { + ul { + li { + a { + max-width: calc(100% + 28px) !important; + } + } + } +} + +#user-info { + display: flex; + flex-direction: row; + align-items: center; + padding-inline: var(--s) calc(var(--padding) + 1px); + padding-block: 5px; + height: 100%; + background-color: transparent; + border-radius: 0; + + &::after { + border-color: var(--ui-control-color); + transition: border-color linear 100ms; + } + + &:hover::after { + border-color: var(--ui-control-hover-color); + } + + &[aria-expanded='true']::after { + border-color: var(--ui-control-active-color); + } +} + +.header-photo { + img, + svg { + display: block; + width: calc(30rem / 16); + height: calc(30rem / 16); + max-width: none; + border-radius: 50%; + box-shadow: + 0 0 0 1px color.adjust(mixins.$grey900, $alpha: -0.95), + 0 0 0 color.adjust(mixins.$grey900, $alpha: -1); + transition: box-shadow linear 150ms; + + #user-info:hover & { + box-shadow: + 0 0 0 1px color.adjust(mixins.$grey900, $alpha: -0.95), + 0 2px 10px -2px color.adjust(mixins.$grey900, $alpha: -0.7); + } + } +} + +/* main container */ +#main-container { + position: relative; + flex-grow: 1; +} + +#notifications { + position: fixed; + inset-block-end: 8px; + inset-inline-start: 8px; + display: flex; + flex-direction: column; + gap: 12px; + width: calc(100% - 16px); + z-index: 101; + + // top + body.notifications--start-start &, + body.notifications--start-end & { + inset-block: 8px auto; + flex-direction: column-reverse; + } + + // right + body.notifications--start-end &, + body.notifications--end-end & { + inset-inline: auto 8px; + } + + // bottom + toolbar + body.notifications--end-start.has-debug-toolbar &, + body.notifications--end-end.has-debug-toolbar & { + inset-block-end: 50px; + } + + @media only screen and (min-width: $minDesktopWidth) { + width: 350px; + } + + .notification { + position: relative; + @include mixins.pane; + border-radius: var(--radius-lg); + box-shadow: + 0 0 0 1px color.adjust(mixins.$grey1000, $alpha: -0.85), + 0 2px 12px color.adjust(mixins.$grey1000, $alpha: -0.85); + + &[data-type='success'] { + .notification-icon { + --icon-color: var(--fg-success); + } + } + + &[data-type='error'] { + .notification-icon { + --icon-color: var(--fg-error); + } + } + + .notification-inner { + display: flex; + padding-block: 10px; + padding-inline: 14px; + } + + .notification-icon { + --icon-color: var(--fg-notice); + margin-block-start: 2px; + } + + .notification-main { + margin: -10px; + padding: 10px; + overflow: hidden; + } + + .notification-body { + display: grid; + grid-template-columns: 20px 1fr; + gap: var(--s); + width: 100%; + + .notification-message { + font-weight: bold; + word-break: normal; + overflow-wrap: anywhere; + } + + .notification-details { + margin-block-start: var(--xs); + } + } + + .notification-close-btn { + position: relative; + inset-block-start: -2px; + margin-inline-start: 10px; + } + } + + .copied-elements-notification { + padding: 2px; + background: linear-gradient( + 135deg, + var(--fuchsia-600), + var(--violet-600), + var(--indigo-600) + ); + + .notification-icon { + --icon-color: var(--fuchsia-500); + } + + .notification-inner { + border-radius: var(--radius-sm); + background: var(--white); + } + + .copied-elements { + overflow: hidden; + margin-block-end: -10px; + padding-block-end: 10px; + position: relative; + pointer-events: none; + + .chip:not(:first-child) { + position: absolute; + + &::after { + content: ''; + position: absolute; + display: block; + inset: -1px; + background: rgb(255 255 255 / var(--overlay-opacity)); + } + } + } + } +} + +.paste-btn { + background: linear-gradient( + 135deg, + var(--fuchsia-600), + var(--violet-600), + var(--indigo-600) + ); + color: var(--white); + text-shadow: 0 1px 2px rgb(0 0 0 / 25%); + + --focus-ring: var(--focus-ring-outset); + + &:hover, + &.loading { + background: linear-gradient( + 135deg, + var(--fuchsia-700), + var(--violet-700), + var(--indigo-700) + ); + } +} + +#header-container { + margin-block-end: var(--m); +} + +@media only screen and (min-width: $minFullUiWidth) { + #primary-nav-toggle { + display: none; + } + + #crumbs:not(.empty) #primary-nav-toggle + nav ul li:first-child, + #crumbs.empty + .context-menu-container { + margin-inline-start: var(--padding); + padding-inline-start: 0; + } +} + +#global-header, +#header { + .flex { + max-width: 100%; + + &.flex-nowrap { + min-width: 0; + } + } +} + +#header { + display: flex; + align-items: flex-start; + place-content: stretch space-between; + flex-wrap: nowrap; + gap: var(--s); + padding-block: 5px; + padding-inline: var(--padding); + position: relative; + isolation: isolate; + box-sizing: border-box; + background-color: color.adjust(mixins.$grey300, $alpha: -1); + box-shadow: 0 1px 0 color.adjust(mixins.$grey800, $alpha: -1); + transition: + background-color linear 100ms, + box-shadow linear 100ms; + + body.fixed-header & { + position: fixed; + z-index: 12; + inset-block-start: 0; + background-color: var(--gray-100); + box-shadow: 0 1px 0 color.adjust(mixins.$grey700, $alpha: -0.9); + } + + @supports (backdrop-filter: blur(10px)) { + & { + transition: + background-color linear 100ms, + box-shadow linear 100ms, + backdrop-filter linear 100ms; + + body.fixed-header & { + background-color: color.adjust(mixins.$grey100, $alpha: -0.25); + backdrop-filter: blur(10px); + } + } + } + + h1 { + line-height: 1.3; + margin-block: 0; + min-width: 0; + } + + .buttons, + .btngroup { + margin-block-start: 0; + } +} + +#page-title { + --page-title-columns: 1fr 34px; + min-height: 34px; + display: grid; + grid-template-columns: var(--page-title-columns); + align-items: center; + gap: var(--s); + + &.has-toolbar { + @media only screen and (min-width: $minHorizontalUiWidth) { + min-width: calc(#{$sidebarWidth} - var(--xl) - var(--s)) !important; + } + } +} + +#content-heading { + font-size: 0.875rem; + font-weight: normal; + + &::before { + content: '/'; + display: inline-block; + margin-inline: 0.5rem; + } + + @media only screen and (min-width: $minHorizontalUiWidth) { + display: none; + } +} + +#toolbar { + flex: 1; + align-items: flex-start; + justify-content: space-between; + min-height: 34px; + + #main-form & { + align-items: center; + } + + .icon::before, + .texticon::before, + .menubtn::after, + [data-icon]::before, + [data-icon-after]::after { + color: currentcolor; + opacity: 0.8; + } + + .text { + border-radius: var(--radius-lg); + + &::placeholder { + color: var(--light-text-color); + } + + &:not(:focus) { + background-clip: border-box; + } + } +} + +#revision-indicators { + min-width: 34px; + min-height: 34px; + display: flex; + align-items: center; + align-self: start; +} + +#action-buttons { + flex-shrink: 0; + + @media only screen and (width <= 400px) { + .btngroup .btn:first-child { + flex-basis: 100%; + } + } + + @media only screen and (max-width: $minHorizontalUiWidth - calc(1rem / 16)) { + flex-direction: row-reverse; + justify-content: flex-start; + margin-block-start: 10px; + } +} + +#main-content { + display: flex; + flex-direction: row; + align-items: flex-start; + padding-block: 0 48px; + padding-inline: var(--padding); + box-sizing: border-box; + + // for the Dashboard and any other full-page grids: + & > .grid:only-child { + flex: 1; + } +} + +#sidebar-toggle-container { + display: none; +} + +#sidebar-container { + flex: 0 0 $sidebarWidth; + width: $sidebarWidth; + box-sizing: border-box; + + @media only screen and (min-width: $minFullUiWidth) { + margin-inline-start: calc(var(--xl) * -1); + } +} + +#sidebar { + position: relative; + box-sizing: border-box; + padding-block: 0 var(--m); + padding-inline: 40px; + width: $sidebarWidth; + background-color: transparent; + + &.fixed { + position: fixed; + } + + nav { + margin-inline: -31px; + + li { + a { + position: relative; + + &:focus { + z-index: 1; + } + + &:not(.sel) { + &:hover { + background-color: var(--gray-200); + } + } + } + } + } + + .skip-link { + margin-block: 0; + margin-inline: var(--s); + } + + @media only screen and (min-width: $minFullUiWidth) { + padding-block: 0 var(--m); + padding-inline: 31px; + } +} + +#content-container { + flex: 1 1 auto; + + /* + Admittedly I'm not totally sure why this is necessary, but it seems to be. + We have to give #content-container some kind of "hard" width for it to properly + clip the content when table cells are long. + */ + width: 400px; +} + +.content-grid { + --size-main-content: 100%; + position: relative; + display: grid; + grid-template-columns: minmax(var(--size-main-content), 1fr) var( + --touch-target-size + ); + + &:has(.content-grid__toggle) { + --size-main-content: calc(100% - var(--touch-target-size)); + } +} + +.content-grid__main { + grid-column: 1/1; +} + +.content-pane { + @include mixins.pane; + + --border-radius: var(--radius-lg); + border-radius: var(--border-radius); + position: relative; + background-clip: padding-box; + padding: var(--padding); + + --pane-padding: var(--padding); + word-wrap: break-word; + + & > hr { + margin-inline: calc(var(--padding) * -1); + } +} + +.content-pane:has(.flex-fields) { + container-type: inline-size; +} + +#footer, +.footer { + padding-block: 6px; + padding-inline: var(--pane-padding, var(--xl)); + min-height: 44px; + line-height: calc(32rem / 16); + + .buttons { + height: 32px; + display: flex; + align-items: center; + } + + .btn { + padding-block: 4px; + height: var(--ui-control-height--small); + } +} + +#footer { + position: sticky; + inset-block-end: 0; + z-index: 1; + margin-block: var(--padding) calc(var(--padding) * -1 + 2px); + margin-inline: calc(var(--padding) * -1 + 2px); + background-color: var(--gray-050); + border-radius: var(--radius-sm); + box-sizing: border-box; + border-block-start: 2px solid var(--white); + + &:empty { + display: none; + } + + &.stuck { + border-radius: 0; + + @supports (backdrop-filter: blur(10px)) { + & { + background-color: color.adjust(mixins.$grey100, $alpha: -0.25); + backdrop-filter: blur(10px); + } + } + } + + .has-debug-toolbar & { + transition: padding linear 100ms; + + &.stuck { + padding-block-end: 52px; + } + } + + & > *, + .flex > * { + margin-block-end: 0; + } +} + +#details-container[data-state='collapsed'] { + display: none; +} + +#details-toggle > button { + --disclosure-icon-transform-active: rotate(180deg); + position: sticky; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + inset-block-start: 0; + height: 100%; + max-height: 100vh; + width: var(--touch-target-size); + border-radius: var(--ui-control-border-radius); + + .details-toggle__inner { + display: inline-flex; + justify-content: center; + align-items: center; + border: 1px solid var(--border-hairline); + width: calc(var(--touch-target-size) - var(--s)); + height: calc(var(--touch-target-size) * 2); + border-radius: var(--ui-control-border-radius); + background-color: var(--gray-100); + position: relative; + z-index: 10; + } + + &::before { + content: ''; + position: absolute; + inset-block: 0; + height: 100%; + width: 1px; + background-color: var(--border-hairline); + } + + &:hover, + &:focus, + &:focus-visible { + .details-toggle__inner { + background-color: var(--gray-200); + } + + &::before { + transform: scaleX(300%); + } + } + + &:focus-visible, + &:focus { + box-shadow: none; + + .details-toggle__inner { + box-shadow: var(--focus-ring); + } + } + + body.rtl & { + --disclosure-icon-transform: rotate(180deg); + --disclosure-icon-transform-active: rotate(0); + } +} + +#details-container { + display: block; + flex: 0 1 auto; + width: calc(var(--details-width)); + position: sticky; + inset-block-start: 0; +} + +#details { + display: none; +} + +#details { + display: block; + width: $detailsWidth; + z-index: 1; + + &.fixed { + position: fixed; + } + + .details { + .meta { + border-radius: var(--radius-lg); + + &:not(.read-only, .warning) { + @include mixins.pane; + } + + &.read-only { + color: var(--fg-subtle); + background-color: transparent !important; + } + + & > .field, + & > .data { + &:first-child { + &, + & > .status-badge { + border-start-start-radius: var(--radius-lg); + } + + border-start-end-radius: var(--radius-lg); + } + + &:last-child { + &, + & > .status-badge { + border-end-start-radius: var(--radius-lg); + } + + border-end-end-radius: var(--radius-lg); + } + } + } + + & > .field { + & > .input > .text.fullwidth { + @include mixins.pane; + } + } + + .notes { + border-radius: var(--radius-lg); + padding-block: var(--m); + } + } +} + +// Hide the sidebar at < 1200 +@media only screen and (max-width: $minFullUiWidth - calc(1rem/16)) { + #global-container { + inset-inline-start: -$sidebarWidth; + width: calc(100vw + #{$sidebarWidth}); + + .showing-nav & { + inset-inline-start: 0; + } + } + + #crumbs { + display: flex !important; + } + + #header { + width: 100vw; + } + + #main-content { + width: 100vw; + + &.has-sidebar { + padding-inline-start: 0; + } + } +} + +// Rearrange #main-content to flow vertically at < 999 +@media only screen and (max-width: $minHorizontalUiWidth - calc(1rem/16)) { + #header { + display: block; + + .flex:not(#toolbar) { + margin-block-start: 10px; + } + } + + #toolbar { + flex-wrap: wrap !important; + + & > * { + margin-block-start: 10px !important; + } + } + + body.fixed-header #header .flex:first-child { + margin-block-start: 0; + } + + #main-content { + display: block; + + &.has-sidebar { + padding-block: 0 48px; + padding-inline: var(--padding); + } + } + + #sidebar { + nav { + margin-inline: -40px; + } + + .skip-link { + margin: 0; + } + } + + #source-actions { + margin-block-start: var(--s); + margin-inline-start: -9px; + } + + #sidebar-toggle-container { + display: block; + margin-block-end: var(--s); + } + + #sidebar-toggle { + &::after { + inset-block-start: 0; + transform: rotate(45deg); + + body.rtl & { + transform: rotate(135deg); + } + } + } + + #content-container { + min-height: 0 !important; + } + + .content-grid, + .content-grid:has(.content-grid__toggle) { + --size-main-content: 100%; + } + + #sidebar-container, + #details-container { + width: auto !important; + padding-inline-start: 0 !important; + display: block; + } + + .content-grid__toggle { + display: none; + } + + #sidebar, + #details { + position: relative !important; + overflow-y: visible !important; + max-height: none !important; + width: auto; + } + + #sidebar { + margin-block-end: var(--m); + + body.showing-sidebar & { + @include mixins.pane; + padding-block: 0.5rem; + border-radius: var(--radius-lg); + } + + body:not(.showing-sidebar) & { + display: none; + } + } + + #details-container { + margin-inline-end: 0; + } + + #content-container { + width: auto !important; + max-width: none !important; + } + + #details { + padding: 0 !important; + margin-block-start: var(--m); + + .details { + margin-block-end: auto; + } + } +} + +// Tighten up the padding at < 768 +@media only screen and (width <= 767px) { + :root { + --padding: var(--s); + --neg-padding: calc(var(--s) * -1); + } + + #tabs ul li { + a { + padding-inline: var(--m); + } + + & + li { + margin-inline-start: -7px; + } + } + + .card-grid { + display: flex !important; + flex-direction: column; + } +} + +#settingsmenu ul li a { + padding-inline-start: 46px; + + &::before { + margin-inline: -22px 0; + margin-block: 1px 0; + font-size: 15px; + } + + img { + width: 16px; + height: 16px; + position: absolute; + margin-inline-start: -23px; + margin-block-start: 1px; + } +} + +%type-heading-small { + text-transform: uppercase; + color: var(--medium-text-color); + font-size: 11px; + font-weight: bold; +} + +.sources-list { + --source-item-toggle-size: calc(20rem / 16); +} + +.collapsible .sources-list { + position: relative; + padding-inline-start: var(--m); + + &::before { + content: ''; + display: inline-block; + position: absolute; + inset-block-start: 0; + inset-inline-start: calc(var(--source-item-toggle-size) / 2); + width: 1px; + height: 100%; + background-color: var(--border-hairline); + } +} + +.source-item { + position: relative; + + // Toggle button + .source-item__toggle { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + position: absolute; + inset-inline-start: 0; + inset-block-start: 50%; + transform: translateY(-50%); + width: var(--source-item-toggle-size); + height: var(--source-item-toggle-size); + z-index: 1; + color: inherit; + } + + &:has(.sel) { + --icon-color: var(--white); + } +} + +.source-item--heading { + @extend %type-heading-small; + margin-block-end: var(--s); + padding-block-end: var(--xs); + + & > craft-disclosure > .source-item__toggle { + inset-block-start: calc(1lh * 0.5 - var(--source-item-toggle-size) / 2); + transform: none; + } +} + +/* Sidebar */ +.sidebar { + width: $sidebarWidth; + box-sizing: border-box; + font-size: calc(13rem / 16); + + &:not(.drag-helper) { + padding-block: var(--m); + padding-inline: 0; + background-color: var(--gray-050); + } + + .heading { + position: relative; + margin-block: 0; + line-height: 1.2; + + &:not(:first-child) { + margin-block-start: var(--m); + } + + .type-heading-small, + & > span { + // Backwards compatibility + @extend %type-heading-small; + display: inline-block; + position: relative; + z-index: 1; + padding-block: 0; + padding-inline: var(--xl) var(--m); + margin-block: 0; + } + + & > ul { + margin-block: var(--xs) 2px; + } + } + + @mixin nav-level($level) { + & > a, + .type-heading-small, + [data-source-item] { + padding-inline-start: calc(24px + (var(--s) * #{$level})); + } + + & > .toggle, + [aria-controls] { + inset-inline-start: calc(var(--m) * #{$level}); + } + } + + nav { + padding-block: 0; + padding-inline: var(--s); + + li { + position: relative; + + &:not(.has-subnav) > a, + &:not(.has-subnav) [data-source-item] { + &:not(.sel):hover { + text-decoration: none; + } + + &.sel, + &.active-drop-target { + cursor: default; + background-color: var(--gray-500); + + --focus-ring: var(--focus-ring-outset); + + &, + & + .toggle { + color: var(--white); + } + } + + &.sel { + @include mixins.light-on-dark-text; + + --focus-ring: var(--focus-ring-outset); + } + } + + a { + position: relative; + margin-block-end: 1px; + display: flex; + flex-direction: row; + align-items: center; + padding-block: 7px; + padding-inline: var(--xl) var(--m); + min-height: var(--xl); + box-sizing: border-box; + color: var(--text-color); + cursor: pointer; + user-select: none; + border-radius: var(--radius-lg); + word-break: break-word; + + .status { + flex-shrink: 1; + } + + .icon { + position: relative; + inset-block-start: 1px; + margin-inline-end: 10px; + flex-shrink: 1; + width: calc(18 / 16 * 1rem); + height: calc(18 / 16 * 1rem); + word-break: normal; + transition: + margin-inline-start linear 150ms, + margin-inline-end linear 150ms; + opacity: 0.85; + + &.icon-mask { + svg { + @include mixins.svg-mask(currentColor); + } + + span[data-icon] { + color: currentcolor; + } + } + + svg { + width: 1rem; + height: 1rem; + } + + span[data-icon] { + font-size: 16px; + + &::before { + display: block; + } + } + } + + .label { + flex: 1; + } + + .badge { + margin-inline: 10px -4px; + margin-block: 0; + flex-shrink: 1; + font-size: calc(10rem / 16); + line-height: 1rem; + min-width: 1.1rem; + height: 1rem; + padding-block: 0; + padding-inline: var(--xs); + border-radius: var(--s); + background-color: var(--fg-subtle); + color: var(--white); + } + } + + .toggle { + position: absolute; + z-index: 1; + height: 34px; + inset-block-start: 0; + width: var(--xl); + display: flex; + align-items: center; + justify-content: center; + } + } + } +} + +.sources-list { + &[data-state='collapsed'] { + li:not(:has(.sel)) { + display: none; + } + + .source-item:has(craft-disclosure) > * { + padding-inline-start: var(--s); + } + + .source-item__toggle { + display: none; + } + } +} + +.error-summary { + @include mixins.pane; + margin-block-end: var(--l); + padding-block: var(--l); + padding-inline: var(--xl); + border-radius: var(--radius-lg); + background-color: var(--gray-050); + + .notification-icon { + color: var(--fg-error); + margin-block: -2px 0; + margin-inline: 0 6px; + float: inline-start; + } + + h2 { + margin-block-start: 0; + } + + & > ul.errors li, + & > ul.errors li a { + color: var(--text-color); + + em { + font-weight: 600; + } + + &:hover { + color: var(--link-color); + } + } +} + +.slideout { + .error-summary { + border: 1px solid var(--fg-error); + box-shadow: none; + background-color: rgb(from var(--fg-error) r g b / 3%); + padding: var(--m); + } + + // Slideouts with tabs need slightly different margins + .flex-fields .error-summary { + margin-block: 0 var(--row-gap); + margin-inline: var(--row-gap); + } +} + +.content.has-sidebar:not(.hiding-sidebar) { + margin-inline-start: $sidebarWidth; +} + +#content-notice { + margin-block: 0; + margin-inline: calc(var(--xl) * -1); + padding-block: 0; + padding-inline: var(--xl); + + &:not(:last-child) { + padding-block-end: 5px; + border-block-end: 1px solid var(--border-hairline); + margin-block-end: 5px; + } +} + +/* flexbox field layouts */ +.flex-fields { + --row-gap: var(--xl); + display: flex; + flex-wrap: wrap; + align-content: flex-start; + margin-block: 0 calc(var(--padding) * -1); + margin-inline: calc(var(--padding) * -1); + width: calc(100% + var(--padding) * 2); + container-type: inline-size; + + & > :not(.error-summary) { + margin-block: 0 var(--row-gap) !important; + margin-inline: 0 !important; + padding-block: 0; + padding-inline: var(--padding); + box-sizing: border-box; + } + + & > h2 { + flex: 4 0 100%; + + &:not(:nth-child(-n + 1 of :not(.hidden))) { + padding-block-start: var(--xl); + border-block-start: 1px solid var(--border-hairline); + } + } + + & > hr, + & > .line-break { + flex: 4 0 100%; + } + + & > .line-break:not(:first-child) { + margin-block-end: 0 !important; + } + + & > :not(h2, hr, .line-break) { + &, + &:last-child { + position: relative; + width: 100%; + + &::before { + position: absolute; + inset-block-start: 0; + inset-inline-start: -1px; + width: 1px; + height: 100%; + content: ''; + + // same BG color as the hairline around the content pane’s 1px shadow + background-color: color.adjust(mixins.$grey200, $alpha: -0.5); + } + } + } + + & > :not(h2, hr, .line-break) { + &, + &:last-child { + // 4 cols for container width >= 800px + @container (min-width: calc(800rem/16)) { + &.width-25 { + width: 25%; + } + + &.width-50 { + width: 50%; + } + + &.width-75 { + width: 75%; + } + } + + // 2 cols when container width >= 400px and < 800px + @container (min-width: calc(400rem/16)) and (max-width: calc(800rem/16 - 1px)) { + &.width-25 { + width: 50%; + } + } + } + } +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_craft-spinner.scss b/packages/craftcms-legacy/cp/src/css.bkup/_craft-spinner.scss new file mode 100644 index 00000000000..fe4f0df37a7 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_craft-spinner.scss @@ -0,0 +1,10 @@ +craft-spinner { + display: flex; + justify-content: center; + + .wrapper { + display: flex; + flex-direction: column; + align-items: center; + } +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_craft-tooltip.scss b/packages/craftcms-legacy/cp/src/css.bkup/_craft-tooltip.scss new file mode 100644 index 00000000000..da402e2495a --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_craft-tooltip.scss @@ -0,0 +1,67 @@ +.craft-tooltip { + position: fixed; + white-space: normal; + opacity: 0; + width: max-content; + max-width: 240px; + transition: + opacity 100ms ease-in-out, + transform 150ms ease-in-out; + /* stylelint-disable */ + /* We need to keep these non-logical so floating-ui can override them */ + top: 0; + left: 0; + /* stylelint-enable */ + z-index: 99; + + [placement^='bottom'] &, + [placement^='top'] & { + text-align: center; + } +} + +.craft-tooltip > .inner { + position: relative; + display: inline-block; + background-color: var(--white); + color: var(--gray-700); + border: 1px solid var(--border-hairline-dark); + box-shadow: 0 0 10px rgb(0 0 0 / 20%); + border-radius: var(--radius-md); + padding-block: var(--xs); + padding-inline: var(--s); + user-select: none; + font-weight: 400; +} + +.craft-tooltip .arrow { + position: absolute; + background: var(--white); + width: 8px; + height: 8px; + transform: rotate(45deg); + border-style: solid; + border-width: 1px; + border-color: transparent; + + // Not using logical properties here because `data-placement` will change based on direction via JS + &[data-placement^='bottom'] { + border-color: var(--border-hairline-dark) transparent transparent + var(--border-hairline-dark); + } + + &[data-placement^='top'] { + border-color: transparent var(--border-hairline-dark) + var(--border-hairline-dark) transparent; + } + + &[data-placement^='right'] { + border-color: transparent transparent var(--border-hairline-dark) + var(--border-hairline-dark); + } + + &[data-placement^='left'] { + border-color: var(--border-hairline-dark) var(--border-hairline-dark) + transparent transparent; + } +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_debug_toolbar.scss b/packages/craftcms-legacy/cp/src/css.bkup/_debug_toolbar.scss new file mode 100644 index 00000000000..c699ceadd29 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_debug_toolbar.scss @@ -0,0 +1,3 @@ +.yii-debug-toolbar__title a { + display: block !important; +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_entry-type-select.scss b/packages/craftcms-legacy/cp/src/css.bkup/_entry-type-select.scss new file mode 100644 index 00000000000..af3ebe6b942 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_entry-type-select.scss @@ -0,0 +1,39 @@ +@charset "UTF-8"; +@use 'sass:color'; +@use '@craftcms/sass/mixins'; + +.entry-type-override-settings-body { + flex: 1; + margin-block: -24px 0; + margin-inline: var(--neg-padding); + padding-block: 24px; + padding-inline: var(--padding); + overflow: hidden auto; + position: relative; +} + +.entry-type-override-settings-footer { + position: relative; + display: flex; + flex-direction: row; + margin-block: 0 -24px; + margin-inline: var(--neg-padding); + padding-block: 5px; + padding-inline: var(--padding); + @include mixins.pane; + background-color: var(--gray-050); + z-index: 3; + + & > .ee-site-select { + flex: 1; + } + + & > .btn { + margin-inline-start: 5px; + } + + & > .spinner { + margin-inline: 0 var(--neg-padding); + margin-block: 0; + } +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_global-sidebar.scss b/packages/craftcms-legacy/cp/src/css.bkup/_global-sidebar.scss new file mode 100644 index 00000000000..a7545f91774 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_global-sidebar.scss @@ -0,0 +1,436 @@ +@use '@craftcms/sass/mixins'; +@use 'cp'; + +.global-sidebar { + --is-always-visible: true; + position: sticky; + inset-block-start: 0; + display: grid; + grid-template-columns: var(--cp-sidebar-width); + grid-template-rows: calc(var(--cp-header-height) + 1px) minmax(0, 1fr) auto; + grid-auto-flow: row; + height: 100vh; + padding: 0; + -webkit-overflow-scrolling: touch; + background-color: var(--gray-150); + border-inline-end: 1px solid var(--border-hairline); + width: var(--cp-sidebar-width); + isolation: isolate; + z-index: 1; + + a { + text-decoration: none; + } + + & > a, + *:not(.has-subnav) > a { + &:not([href]) { + cursor: default; + background-color: transparent; + } + } + + @media only screen and (max-width: cp.$minFullUiWidth - calc(1rem/16)) { + --is-always-visible: false; + } +} + +.global-sidebar__nav { + padding-block: var(--s); + padding-inline: 0; + overflow: hidden auto; + -webkit-overflow-scrolling: touch; + scrollbar-width: none; + overscroll-behavior: contain; +} + +.global-sidebar__footer { + margin-block-start: auto; + border-block-start: 1px solid var(--border-hairline); +} + +.global-nav > ul { + display: flex; + flex-direction: column; +} + +.global-nav > ul > li { + position: relative; +} + +.nav-icon { + display: inline-flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 1.25rem; + height: 1rem; + line-height: 0; + + --thumb-size: 1rem; + + > svg { + @include mixins.svg-mask(currentColor); + width: 100%; + height: 100%; + } +} + +.nav-item { + display: grid; + grid-template-columns: var(--nav-item-gutter-width) minmax(0, 1fr) var( + --nav-item-gutter-width + ); + grid-template-areas: '. action .' 'subnav subnav subnav'; + align-items: center; + width: 100%; + padding-block: var(--xs); + + > .sidebar-action { + grid-area: action; + } +} + +.nav-item--sub { + padding-block: 0; + grid-template-columns: + calc(var(--nav-item-gutter-width) * 3) minmax(0, 1fr) + var(--nav-item-gutter-width); +} + +.nav-item__trigger { + --icon-size: 10px; + width: var(--nav-item-trigger-size); + height: var(--nav-item-trigger-size); + display: inline-block; + z-index: 1; + + .menubtn.btn.hairline { + padding: 0; + flex-direction: column; + justify-content: center; + align-items: center; + width: var(--nav-item-trigger-size); + height: var(--nav-item-trigger-size); + min-height: 0; + border-color: transparent; + + &:hover:not(:has(.sel)) { + background-color: var(--nav-item-bg-hover); + } + + &[aria-expanded='true'] { + background-color: transparent; + } + + &[aria-expanded='true']::after { + @include mixins.angle(up); + } + + &::after { + margin-inline-start: 0 !important; + } + } +} + +.nav-item__subnav { + --nav-item-prefix-ratio: 4/3; + display: none; + grid-area: subnav; + gap: 1px; + margin-block: 1px; + flex-direction: column; + + &[data-state='expanded'] { + display: flex; + } + + [data-sidebar='expanded'] & { + .sidebar-action { + position: relative; + } + + .sidebar-action::before { + content: ''; + display: inline-block; + position: absolute; + inset-inline-start: calc(-6rem / 16); + inset-block-start: -1px; // Account for gap + height: calc(100% + 1px); + width: 1px; + background-color: color-mix(in srgb, currentcolor, transparent 75%); + border-radius: 0; + } + + .sidebar-action.sel::before { + background-color: currentcolor; + width: 3px; + border-radius: 0 2px 2px 0; + } + } +} + +.badge { + display: inline-flex; + justify-content: center; + text-align: center; + font-size: calc(10rem / 16); + line-height: 1rem; + min-width: 1.1rem; + height: 1rem; + padding-block: 0; + padding-inline: var(--xs); + border-radius: var(--s); + background-color: var(--nav-item-badge-bg); + color: var(--nav-item-badge-fg); +} + +.sidebar-actions { + display: none; + + @media only screen and (min-width: cp.$minFullUiWidth) { + display: block; + padding-block: 10px; + padding-inline: var(--nav-item-gutter-width); // match padding of #system-info + + #sidebar-trigger { + display: flex; + } + } +} + +// Active indicator +.nav-indicator { + width: var(--nav-item-indicator-size); + border-radius: var(--radius-sm); + aspect-ratio: 1; + background-color: currentcolor; +} + +.sidebar-action { + --thumb-size: 0.75rem; + display: grid; + grid-template-columns: var(--nav-item-prefix-width) minmax(0, 1fr) auto; + width: 100%; + align-items: center; + position: relative; + text-align: start; + border-radius: var(--radius-md); + color: currentcolor; + cursor: pointer; + min-height: 30px; + font-weight: 500; + + &::before { + content: ''; + position: absolute; + width: 4px; + inset-block-start: 0; + inset-inline-start: calc(var(--nav-item-gutter-width) / -2 - 3px); + height: 100%; + border-radius: var(--radius-md); + background-color: transparent; + z-index: -1; + } + + &:focus-visible, + &:hover:not(:has(.btn:hover)) { + color: var(--nav-item-fg-hover); + background-color: var(--nav-item-bg-hover); + } + + &[aria-current='page'], + &[aria-current='true'] { + &::before { + background-color: var(--nav-item-fg-active); + } + } +} + +.sidebar-action--sub { + font-size: 0.9em; + min-height: 26px; + + &::before { + display: none; + } + + .sidebar-action__prefix { + position: relative; + } + + &[aria-current='page'], + &[aria-current='true'] { + --nav-item-indicator-size: 6px; + } +} + +.sidebar-action--job { + align-items: start; + + .sidebar-action__label { + flex-wrap: wrap; + padding-block: calc((30px - var(--lh)) / 2); + gap: var(--2xs); + } + + .label { + white-space: normal; + } + + .progress-label { + width: 100%; + display: block; + color: var(--gray-300); + font-size: 11px; + line-height: 1.5; + } + + .nav-icon { + display: block; + position: relative; + width: 16px; + height: 16px; + + & > canvas { + display: block; + position: absolute; + width: 16px; + height: 16px; + } + } + + #job-icon-hover { + opacity: 0; + } + + &:hover { + #job-icon-hover { + opacity: 1; + } + + #job-icon-static { + opacity: 0; + } + } +} + +.sidebar-action__prefix { + display: flex; + align-items: center; + justify-content: center; + width: var(--nav-item-prefix-width); + aspect-ratio: var(--nav-item-prefix-ratio); + line-height: 0; +} + +.sidebar-action__suffix { + display: flex; + gap: var(--s); + align-items: center; + padding-block: 0; + padding-inline: var(--xs); + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + margin-inline-start: 7px; // magic number to align with system name + + [data-icon='external'] { + display: inline-flex; + } +} + +.sidebar-action__badge { + flex: 0 1 auto; + display: flex; + flex-direction: column; + justify-content: center; + padding-block: 0; + padding-inline: var(--xs); + margin-inline-start: auto; +} + +/** +States + */ +@media only screen and (min-width: cp.$minFullUiWidth) { + [data-sidebar='collapsed'] { + .global-sidebar { + --cp-sidebar-width: calc(50rem / 16); + } + + .nav-item { + grid-template-areas: '. action .' '. trigger .' 'subnav subnav subnav'; + grid-template-columns: + var(--nav-item-gutter-width) var(--nav-item-prefix-width) + var(--nav-item-gutter-width); + justify-items: center; + } + + .nav-item__indicator { + inset-inline-end: -1px; + } + + .sidebar-action { + width: var(--nav-item-prefix-width); + min-height: var(--nav-item-prefix-width); + grid-template-columns: none; + } + + .nav-item__trigger { + .menubtn { + width: 100%; + height: var(--touch-target-size); + padding-block: 2px var(--xs); + } + } + + .sidebar-action__label { + display: none; + } + + .sidebar-action__suffix { + display: flex; + justify-content: center; + margin-inline: 0; + padding-inline: 0; + } + + .sidebar-action__badge { + z-index: 100; + position: absolute; + inset-inline-end: calc(var(--xs) * -1); + inset-block-end: var(--xs); + transform: translateY(25%); + padding: 0; + } + + .sidebar-action--sub { + min-height: 26px; + } + + .global-nav > ul > li + li { + --separator-width: calc(28rem / 16); + + &::before { + position: absolute; + inset-block-start: 0; + inset-inline-start: calc( + (var(--cp-sidebar-width) - var(--separator-width)) / 2 + ); + content: ''; + width: var(--separator-width); + height: 1px; + margin-block: 0; + margin-inline: auto; + background-color: var(--border-hairline); + } + } + } + + [data-sidebar='expanded'] { + #sidebar-toggle-icon { + transform: rotate(180deg); + } + } +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_grouped-entry-type-select.scss b/packages/craftcms-legacy/cp/src/css.bkup/_grouped-entry-type-select.scss new file mode 100644 index 00000000000..4e99301b9d8 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_grouped-entry-type-select.scss @@ -0,0 +1,66 @@ +@charset "UTF-8"; + +.entry-type-groups { + display: flex; + align-items: start; + flex-wrap: wrap; + gap: var(--s); +} + +.entry-type-group { + display: flex; + flex-direction: column; + border-radius: var(--pane-border-radius); + border: var(--input-border); + margin: 0; + padding: var(--s); + background-color: var(--white); + + .entry-type-group--titlebar { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--m); + margin-block: calc(var(--s) * -1) var(--s) !important; + margin-inline: calc(var(--s) * -1) !important; + padding: var(--s); + border-block-end: 1px solid var(--hairline-color); + font-weight: bold; + + .entry-type-group--actions { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--s); + + .icon { + margin-block: -4px 0; + } + } + + span { + flex: 1; + } + } + + .componentselect { + flex: 1; + display: flex; + flex-direction: column; + + .components { + flex: 1; + + // match the height of a single entry type chip being included + min-height: calc( + var(--xs) * 2 + var(--lh) + var(--xs) + 1.2 * 0.8em + var(--xs) + ); + + .entry-type-group--caboose { + content: ''; + flex: 1; + width: 100%; + } + } + } +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_image_editor.scss b/packages/craftcms-legacy/cp/src/css.bkup/_image_editor.scss new file mode 100755 index 00000000000..72988c3625f --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_image_editor.scss @@ -0,0 +1,368 @@ +@charset "UTF-8"; +@use 'sass:color'; +@use '@craftcms/sass/mixins'; + +/* No Scroll */ +html.noscroll, +html.noscroll body { + overflow: hidden; + height: 100%; +} + +/* Image Editor */ + +.modal.imageeditor { + --focus-ring: var(--focus-ring-light); + background-color: var(--gray-900); + color: var(--white); + @include mixins.light-on-dark-text; + opacity: 0; + user-select: none; + + [data-cropper-edit] { + @include mixins.visually-hidden; + } +} + +.modal.imageeditor.modal { + border-radius: 0; +} + +.modal.imageeditor.modal .body::after { + display: none; +} + +.modal.imageeditor .btn:not(.submit, .noborder) { + background-color: var(--gray-600); + color: var(--white); +} + +.modal.imageeditor .btn:not(.submit, .noborder):hover { + background-color: var(--gray-700); +} + +.modal.imageeditor .btn:not(.submit, .noborder).active { + background-color: var(--gray-800); +} + +.modal.imageeditor .icon::before { + width: 24px; + height: 24px; + margin-inline-start: -3px; + display: inline-block; + content: ''; +} + +.modal.imageeditor .icon.rotate-left::before { + background-image: url('../images/image-editor/rotate-left.svg'); +} + +.modal.imageeditor .icon.rotate-right::before { + background-image: url('../images/image-editor/rotate-right.svg'); +} + +.modal.imageeditor .icon.flip-vertical::before { + background-image: url('../images/image-editor/flip-vertical.svg'); +} + +.modal.imageeditor .icon.flip-horizontal::before { + background-image: url('../images/image-editor/flip-horizontal.svg'); +} + +.modal.imageeditor .icon.constraint::before { + background-image: url('../images/image-editor/unconstrained.svg'); +} + +.modal.imageeditor .icon.focal-point::before { + background-image: url('../images/image-editor/focal-point.svg'); +} + +.modal.imageeditor .body { + display: flex; + padding: 0; +} + +.modal.imageeditor input { + color: var(--text-color); +} + +.modal.imageeditor .body .tabs { + border-inline-end: 1px solid var(--gray-1000); +} + +.modal.imageeditor .body .tabs ul { + width: 100px; + flex-direction: column; + align-items: stretch; +} + +.modal.imageeditor .body .tabs ul li { + position: relative; + padding: 14px; + text-align: center; + border-block-end: 1px solid var(--gray-1000); + cursor: pointer; + + &::before { + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; + content: ''; + width: 0; + height: 100%; + background-color: currentcolor; + } + + &.selected { + background-color: color.adjust(mixins.$grey900, $lightness: -5%); + + &::before { + width: 2px; + } + } +} + +.modal.imageeditor .body .tabs ul li i { + background-repeat: no-repeat; + background-position: top center; + display: block; + height: 24px; +} + +.modal.imageeditor .body .tabs ul li[data-view='rotate'] i { + background-image: url('../images/image-editor/rotate-left.svg'); +} + +.modal.imageeditor .body .tabs ul li[data-view='crop'] i { + background-image: url('../images/image-editor/crop.svg'); +} + +.modal.imageeditor .body .tabs ul li[data-view='filters'] i { + background-image: url('../images/image-editor/filters.svg'); +} + +.modal.imageeditor .body .tabs ul li:hover { + background-color: color.adjust(mixins.$grey900, $lightness: -2%); +} + +.modal.imageeditor .body .tabs ul li:hover { + cursor: pointer; +} + +.modal.imageeditor .body .views { + padding: 24px; + overflow: auto; +} + +.modal.imageeditor .body .views .btngroup { + margin-block-end: 24px; +} + +.modal.imageeditor .body .views .filters ul { + width: 100px; +} + +.modal.imageeditor .body .views .filters ul li { + text-align: center; + margin-inline-end: 14px; + margin-block-end: 14px; +} + +.modal.imageeditor .body .views .filters ul li:last-child { + margin-inline-end: 0; +} + +.modal.imageeditor .body .views .filters ul li img { + border: 3px solid transparent; + border-radius: 4px; +} + +.modal.imageeditor .body .views .filters ul li span { + display: block; +} + +.modal.imageeditor .body .views .filters ul li:hover { + cursor: pointer; +} + +.modal.imageeditor .body .views .filters ul li.selected img { + border-color: var(--white); +} + +.modal.imageeditor .body .image-container { + flex-grow: 1; + display: flex; + flex-direction: column; + position: relative; + overflow: hidden; +} + +.modal.imageeditor .body .image-container .image { + text-align: center; + flex-grow: 1; + position: relative; + margin: 14px; +} + +.modal.imageeditor .body .image-container .image canvas { + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; +} + +.modal.imageeditor .body .image-container .image-tools { + text-align: center; +} + +.modal.imageeditor .body .image-container .image-tools .straightening { + max-width: 400px; + min-height: calc(60 / 16 * 1rem); + display: block; + margin-block: 0; + margin-inline: auto; + overflow: hidden; +} + +.modal.imageeditor .footer { + position: absolute; + background-color: transparent; + inset-block-end: 0; + inset-inline-start: 0; + width: 100%; + border-block-start: 1px solid #000; + + body.has-debug-toolbar & { + padding-block-end: calc(8px + 42px); + } +} + +.modal.imageeditor .body .views .crop { + fieldset .heading { + display: none; + } + + .custom-constraint-spacer { + padding-block: 0; + padding-inline: var(--xs); + } + + .constraint-group { + display: grid; + grid-gap: var(--xs); + } + + .custom { + padding-inline-start: calc(1rem + 5px); + } +} + +.modal.imageeditor.vertical .body .views .crop { + & > .btngroup:first-child { + justify-content: center; + } +} + +.modal.imageeditor:not(.vertical) .body .views .crop { + .constraint.custom { + margin-block-start: var(--xs); + } +} + +/* Vertical */ + +.vertical.imageeditor .body { + flex-direction: column; + + .image-container { + flex-basis: 30vh; + flex-shrink: 0; + } + + .constraint-group { + grid-template-columns: 1fr 1fr; + } +} + +.vertical.imageeditor .body .tabs ul { + display: flex; + flex-direction: row; + width: 100%; + border-block-start: 1px solid #000; + border-block-end: 1px solid #000; +} + +.vertical.imageeditor .body .tabs ul li { + flex-grow: 1; + border: 0; + border-inline-end: 1px solid #000; + padding-block: 10px; + padding-inline: 7px; + + &::before { + inset-block-start: unset; + inset-block-start: 0; + width: 100%; + height: 0; + } + + &.selected::before { + width: 100%; + height: 2px; + } +} + +.vertical.imageeditor .body .views { + width: auto; +} + +.vertical.imageeditor .body .views .rotate { + display: flex; + justify-content: center; + flex-wrap: wrap; + margin-block-end: -14px; +} + +.vertical.imageeditor .body .views .rotate .btngroup { + margin-block: 0 14px; + margin-inline: 7px; +} + +.vertical.imageeditor .body .views .filters ul { + width: auto; + height: 109px; + overflow: auto; + white-space: nowrap; + margin-block: 0; + margin-inline: -24px; + margin-block-end: -24px; + padding: 24px; + text-align: center; +} + +.vertical.imageeditor .body .views .filters ul li { + display: inline-block; + margin-block-end: 0; +} + +/* Misc */ + +.menu.dark { + background-color: var(--gray-600); + @include mixins.light-on-dark-text; + + ul { + li { + a { + color: var(--white) !important; + + &:not(.sel, .disabled):hover { + background-color: var(--gray-700); + } + } + } + } +} + +#cropping-canvas { + --focus-ring: none; +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_login.scss b/packages/craftcms-legacy/cp/src/css.bkup/_login.scss new file mode 100644 index 00000000000..1c49ad24a4a --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_login.scss @@ -0,0 +1,199 @@ +@charset "UTF-8"; +@use '@craftcms/sass/mixins'; + +.login-alt-menu { + z-index: 1001; +} + +body.login { + display: flex; + flex-direction: column; + align-items: stretch; + + header { + flex: 0 0 calc(var(--header-height) + 1px); + display: flex; + align-items: center; + padding: var(--header-padding); + border-block-end: var(--header-border); + background: var(--header-bg); + + #system-info { + padding-inline: 0; + + &:hover, + &:focus { + background: transparent; + } + } + } + + main { + min-height: 100vh; + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: var(--m); + padding: var(--padding); + + h1 { + width: 100%; + } + + img#login-logo { + margin-inline: auto; + width: auto; + max-width: calc(15rem + var(--pane-padding) * 2); + } + + #poweredby { + display: block; + margin-block-start: calc(70rem / 16 - var(--m)); + text-align: center; + opacity: 0.8; + + &:hover, + &:focus, + &:active { + opacity: 1; + } + + > svg { + display: inline-block; + } + } + } +} + +.modal.email-sent { + width: 300px; + + .body { + padding-inline-start: 68px; + + &::before { + @include mixins.icon; + display: block; + position: absolute; + inset-block-start: 24px; + inset-inline-start: 24px; + content: 'mail'; + font-size: 30px; + color: var(--link-color); + } + } +} + +.login-modal { + width: calc(600px + var(--l) * 2); + max-width: calc(100% - 20px); + background: var(--login-modal-bg, var(--modal-bg)); + border-radius: var(--radius-lg); + + .body { + display: flex; + flex-direction: row; + padding: var(--l); + + .login-modal-intro, + .login-modal-form { + width: 300px; + max-width: 100%; + } + + .login-modal-intro { + padding: var(--m); + } + } + + @media screen and (width <= 656px) { + border-radius: var(--radius-lg); + + .body { + padding: var(--m); + flex-direction: column; + gap: var(--m); + overflow: auto; + + .login-modal-intro { + padding-block: var(--xs); + padding-inline: var(--xl); + } + + .login-modal-form { + border-radius: 0; + } + } + } +} + +.login-container { + position: relative; + width: calc(15rem + var(--pane-padding) * 2); + max-width: 100%; + + form { + display: flex; + flex-direction: column; + gap: var(--l); + + input[readonly] { + cursor: not-allowed; + } + + .field { + margin-block: 0; + } + + hr { + margin-block: calc(var(--pane-padding) - var(--l)); + } + + .btn { + display: flex; + } + } + + .alternative-login-methods { + margin-block-start: var(--m); + + .btn { + width: 100%; + } + } + + .login-forgot-password, + .login-alt-container button { + font-size: 11px; + color: var(--light-text-color); + } + + .login-alt-container { + margin-block: calc(var(--s) - var(--pane-padding)); + margin-inline: 0; + + button { + display: inline-flex; + width: auto; + } + } + + .login-forgot-password:hover, + .login-forgot-password:focus, + .login-alt-container button:hover, + .login-alt-container button:focus { + color: var(--link-color); + } + + .login-errors { + text-align: center; + color: var(--fg-error); + margin-block-start: 1em; + } + + .login-reset-password .login-errors { + margin-block-start: 0; + } +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_main.scss b/packages/craftcms-legacy/cp/src/css.bkup/_main.scss new file mode 100644 index 00000000000..3884d80371b --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_main.scss @@ -0,0 +1,8064 @@ +@charset "UTF-8"; +@use 'sass:color'; +@use 'variables'; +@use '@craftcms/sass/mixins'; + +@mixin striped-bg($size, $color: mixins.$grey100) { + // h/t https://css-tricks.com/stripes-css/ + $halfSize: $size * 0.5; + + body.ltr & { + background: repeating-linear-gradient( + 135deg, + var(--white), + var(--white) $halfSize, + $color $halfSize, + $color $size + ); + } + + body.rtl & { + background: repeating-linear-gradient( + 45deg, + var(--white), + var(--white) $halfSize, + $color $halfSize, + $color $size + ); + } +} + +@font-face { + font-family: Craft; + src: + url('../fonts/Craft.woff2') format('woff2'), + url('../fonts/Craft.woff') format('woff'), + url('../fonts/Craft.ttf') format('truetype'), + url('../fonts/Craft.svg#Craft') format('svg'); + font-weight: normal; + font-style: normal; + font-display: block; +} + +/* ---------------------------------------- +/* Basic stuff +/* ---------------------------------------- */ + +body, +html { + background: var(--body-bg); +} + +html.noscroll, +html.noscroll body, +body:has(.menu.visible) { + overflow: hidden; +} + +body { + width: 100vw; + overflow-x: hidden; + font-size: var(--font-size); + line-height: var(--lh); + color: var(--text-color); + -webkit-font-smoothing: subpixel-antialiased; +} + +body.rtl { + direction: rtl; +} + +body, +input, +select, +textarea { + @include mixins.sans-serif-font; +} + +.center-absolute { + position: absolute; + inset-block-start: 50%; + inset-inline-start: 50%; + transform: translate(-50%, -50%); +} + +.pointer { + cursor: pointer !important; +} + +.no-scroll { + overflow: hidden !important; +} + +.draghelper { + box-sizing: border-box; + list-style-type: none; +} + +.offset-drag-helper { + transition: + margin linear 200ms, + padding linear 200ms; +} + +body.dragging .offset-drag-helper { + margin-block: -50px 0; + margin-inline: -50px 0; + padding-block: 60px 0; + padding-inline: 60px 0; +} + +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +img { + max-width: 100%; +} + +.text, +table.editable textarea { + body.rtl .ltr & { + direction: ltr !important; + } + + body.ltr .rtl & { + direction: rtl !important; + } +} + +/* icons */ +.icon::before, +.menu ul.padded li a.sel::before, +.menu ul.padded li .menu-item.sel::before, +.menu ul.padded li .menu-option.sel::before, +.menu .flex.padded.sel::before, +.texticon::before, +#help::before, +.secure::before, +.insecure::before, +.go::after, +.required::after, +.preview-btn::before, +.view-btn::before, +.action-btn::before, +[data-icon]::before, +[data-icon-after]::after { + @include mixins.icon; +} + +.badge-icon { + position: relative; + inset-block-start: -1px; + display: inline-flex; + align-items: center; + justify-content: center; + width: 1rem; + height: 1rem; + box-sizing: border-box; + border: 1px solid var(--border-warning-emphasis); + border-radius: var(--radius-sm); + color: var(--fg-warning); + font-size: 9px; +} + +.secure::before, +.insecure::before { + margin-block-start: -3px; + font-size: 14px; +} + +[data-icon]::before { + content: attr(data-icon) / ''; +} + +[data-icon-after]::after { + content: attr(data-icon-after); +} + +[data-icon-size='large'] { + &[data-icon]::before, + &[data-icon-after]::after { + font-size: 20px; + } +} + +[data-icon-size='small'] { + &[data-icon]::before, + &[data-icon-after]::after { + font-size: 14px; + } +} + +[data-icon-size='puny'] { + &[data-icon]::before, + &[data-icon-after]::after { + font-size: 12px; + } +} + +body.rtl [data-icon='list']::before, +body.rtl [data-icon-after='list']::after { + content: 'listrtl'; +} + +body.rtl [data-icon='structure']::before, +body.rtl [data-icon-after='structure']::after { + content: 'structurertl'; +} + +.icon.secure::before { + content: 'secure'; +} + +.icon.insecure::before { + content: 'insecure'; +} + +.icon.add::before { + content: 'plus' / ''; +} + +.icon.edit::before { + content: 'edit'; +} + +.icon.settings::before { + content: 'settings'; +} + +.icon.search::before { + content: 'search'; +} + +.icon.expand::before { + content: 'expand'; +} + +.icon.collapse::before { + content: 'collapse'; +} + +.help::before { + content: 'help'; + color: var(--pink-400); +} + +.preview-btn, +.view-btn { + &::before { + margin-inline-end: var(--xs); + } +} + +.preview-btn::before { + content: 'view' / ''; +} + +.view-btn::before { + body.ltr & { + content: 'share'; + } + + body.rtl & { + content: 'shareleft'; + } +} + +.action-btn::before { + content: 'ellipsis' / ''; +} + +/* paragraphs */ +p { + margin-block: 1em; + margin-inline: 0; +} + +h5 + p { + margin-block-start: 0; +} + +sup { + vertical-align: super; + font-size: smaller; +} + +sub { + vertical-align: sub; + font-size: smaller; +} + +.indent { + margin-inline-start: 14px; +} + +/* lists */ +.bullets { + padding-inline-start: 40px; + list-style-type: square; +} + +ol { + padding-inline-start: 40px; + list-style-type: decimal; +} + +/* code */ +code, +.code { + @include mixins.fixed-width-font; + + &.smalltext { + font-size: 0.8em !important; + } + + p & { + background-color: var(--gray-100); + padding-block: 0.0625em; + padding-inline: 0.25em; + border-radius: var(--radius-sm); + border: 1px solid var(--border-hairline); + } + + .warning & { + background-color: var(--bg-warning); + border-color: var(--border-warning); + } + + .tip & { + background-color: var(--bg-notice); + border-color: var(--border-notice); + } +} + +.code { + input, + textarea { + @include mixins.fixed-width-font; + font-size: 1em !important; + } +} + +pre code { + display: block; + overflow-x: auto; +} + +/* links */ +a { + color: var(--link-color); + cursor: pointer; + + &[aria-current] { + cursor: default; + } + + body.underline-links &, + &:hover { + text-decoration: underline; + } + + .cp-icon svg { + @include mixins.svg-mask(var(--icon-color, var(--link-color))); + } +} + +a:not([href]) { + color: inherit; + cursor: inherit; + + body.underline-links &, + &:hover { + text-decoration: none; + } +} + +a.sel, +li.sel > a { + cursor: default !important; + text-decoration: none; +} + +.go::after { + font-size: 11px; + margin-block-start: -1px; + padding-inline-start: 4px; + + body.ltr & { + content: 'circlerarr' / ''; + } + + body.rtl & { + content: 'circlelarr' / ''; + } +} + +button { + cursor: pointer; +} + +/* status icons */ +.checkmark-icon, +.alert-icon { + padding: 5px; + margin-block-end: 0 !important; + line-height: 10px; + border-radius: 20px; + cursor: pointer; + + &::before { + @include mixins.icon; + } +} + +.checkmark-icon { + p & { + display: inline-block; + } + + background-color: var(--gray-200); + + &::before { + content: 'check'; + color: var(--fg-success); + } +} + +.alert-icon { + background-color: var(--gray-200); + + &::before { + content: 'alert'; + color: var(--fg-error); + } +} + +.revision-status-hud { + max-width: 400px; + + .http-error { + border-radius: var(--radius-md); + border: 1px solid var(--border-hairline); + color: var(--light-text-color); + background-color: var(--gray-050); + padding-block: 7px; + padding-inline: 14px; + } +} + +.draft-notice { + display: flex; + align-items: center; + place-content: stretch center; + gap: var(--s); + color: var(--blue-800); + + #content-notice & { + display: inline-flex; + justify-content: flex-start; + } + + .so-notice > & { + margin-inline: calc(var(--xl) * -1) 0; + margin-block: -5px; + padding-inline: var(--xl) 0; + padding-block: 5px; + border-end-start-radius: var(--radius-lg); + + body.ltr & { + background-image: linear-gradient( + to bottom right, + color.adjust(mixins.$blue600, $alpha: -0.8), + color.adjust(mixins.$blue600, $alpha: -1) 50% + ); + } + + body.rtl & { + background-image: linear-gradient( + to left, + color.adjust(mixins.$blue600, $alpha: -0.8), + color.adjust(mixins.$blue600, $alpha: -1) + ); + } + } + + p { + flex: 1; + margin: 0; + } + + .draft-icon { + position: relative; + flex-shrink: 0; + width: 34px; + height: 34px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 100%; + border: 2px solid color.adjust(mixins.$blue800, $alpha: -0.8); + box-sizing: border-box; + box-shadow: 0 1px 1px 1px var(--white); + + &::before { + position: relative; + inset-inline-start: 1px; + color: var(--blue-800) !important; + font-size: 17px; + } + + &::after { + content: ''; + font-size: 0; + position: absolute; + inset: -2px; + border-radius: 100%; + box-shadow: inset 0 2px 0 color.adjust(mixins.$blue900, $alpha: -0.8); + } + } + + .discard-changes-btn { + margin-inline-start: var(--xs); + background-color: transparent !important; + color: var(--blue-800) !important; + border: 2px solid var(--blue-600) !important; + + &:hover, + &:focus { + border-color: color.adjust(mixins.$blue600, $lightness: -5%); + } + + &:active { + border-color: color.adjust(mixins.$blue600, $lightness: -10%); + } + } +} + +.content-notice { + display: flex; + align-items: center; + place-content: stretch center; + gap: var(--s); + color: var(--gray-600); + + #content-notice & { + display: inline-flex; + justify-content: flex-start; + } + + p { + flex: 1; + margin: 0; + } + + .content-notice-icon { + position: relative; + flex-shrink: 0; + width: 34px; + height: 34px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 100%; + border: 2px solid color.adjust(mixins.$grey800, $alpha: -0.8); + box-sizing: border-box; + box-shadow: 0 1px 1px 1px var(--white); + + .cp-icon { + --icon-size: calc(20rem / 16); + } + + &::after { + content: ''; + font-size: 0; + position: absolute; + inset: -2px; + border-radius: 100%; + box-shadow: inset 0 2px 0 color.adjust(mixins.$blue900, $alpha: -0.8); + } + } +} + +/* toggles */ +button.toggle { + appearance: none; + color: inherit; + background: none; + border: none; + padding: 0; +} + +.toggle::before, +button.fieldtoggle:not(.lightswitch)::before, +a.fieldtoggle::before { + @include mixins.angle(right); + transition: transform linear 100ms; +} + +.toggle.expanded::before, +.toggle[aria-expanded='true']::before, +button.fieldtoggle:not(.lightswitch).expanded::before, +a.fieldtoggle.expanded::before, +.sidebar nav li.expanded > .toggle::before, +.structure li:not(.collapsed) > .row > .toggle::before { + transform: rotate(45deg) !important; +} + +button.fieldtoggle:not(.lightswitch), +a.fieldtoggle { + display: block; + position: relative; + margin-block: var(--m); + margin-inline: 0; + padding-inline-start: var(--m); + color: var(--text-color); + text-decoration: none; + cursor: default; +} + +button.fieldtoggle:not(.lightswitch) { + cursor: pointer; +} + +button.fieldtoggle:not(.lightswitch)::before, +a.fieldtoggle::before { + display: block; + position: absolute; + inset-block-start: 7px; + inset-inline-start: -1px; +} + +/* emphasis */ +em, +i { + font-style: italic; +} + +ul.errors em { + font-style: normal; +} + +strong, +b, +i em { + font-weight: bold; +} + +/* readable blocks */ +.readable { + @include mixins.readable; +} + +/* text styles */ +.leftalign { + text-align: start; +} + +.topalign { + vertical-align: top; +} + +.rightalign { + text-align: end; +} + +.centeralign { + text-align: center !important; +} + +.nowrap { + white-space: nowrap; +} + +.break-word { + overflow-wrap: break-word; +} + +.light { + color: var(--fg-subtle) !important; +} + +.extralight { + color: var(--light-text-color) !important; +} + +.smalltext { + font-size: 12px; + line-height: 1.2; +} + +.largetext { + font-size: 16px; + line-height: 1.2; +} + +.zilch { + padding-block: 100px; + padding-inline: 0; + text-align: center; + font-size: 20px; + line-height: 24px; + color: var(--light-text-color); + + &.small { + padding-block: 24px; + padding-inline: 0; + font-size: 16px; + } +} + +.required::after { + content: 'asterisk'; + margin-inline: 5px 0; + margin-block: -2px 0; + font-size: 12px; + color: var(--rose-600); +} + +.scrollpane { + overflow: auto; +} + +.left { + float: inline-start; +} + +.right { + float: inline-end; +} + +th, +td { + text-align: start; + vertical-align: middle; +} + +body table[dir='rtl'] { + th, + td { + text-align: end; + } +} + +body table[dir='ltr'] { + th, + td { + text-align: start; + } +} + +th.right, +td.right { + float: none; + text-align: end; +} + +.clear { + display: block; + clear: both; + height: 0; +} + +.fullwidth { + width: 100%; +} + +.token { + @include mixins.token-styles; +} + +.token[data-name='*'] { + position: relative; + width: 10px; +} + +.token[data-name='*'] span { + opacity: 0; +} + +.token[data-name='*']::before { + @include mixins.icon; + display: block; + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; + width: 100%; + font-size: 9px; + line-height: 17px; + content: 'asterisk'; + text-indent: 0; +} + +.token:focus { + @include mixins.active-token-styles; +} + +// Override .token for Prism +.highlight { + .token { + display: inline; + border: none; + border-radius: 0; + padding: 0; + font-size: inherit; + line-height: inherit; + text-shadow: none; + background: transparent; + box-shadow: none; + } +} + +.pane.highlight { + pre[class*='language-'] { + overflow: visible; + + & > code.diff-highlight .token:not(.prefix) { + margin-block: 0; + margin-inline: -24px; + padding-block: 0; + padding-inline: 24px; + } + } +} + +.success { + color: var(--fg-success) !important; +} + +.notice, +.warning { + &.with-icon, + .icon { + &::before { + margin-inline: 0 2px; + margin-block: -2px 0; + @include mixins.icon; + width: 1em; + } + } + + &.has-icon { + display: flex; + flex-wrap: nowrap; + align-items: flex-start; + + .icon { + flex-shrink: 1; + } + } +} + +.notice { + color: var(--fg-notice) !important; + + a { + text-decoration: underline; + } + + &.with-icon, + .icon { + &::before { + content: 'lightbulb'; + } + } +} + +.warning { + color: var(--fg-warning) !important; + + &.with-icon, + .icon { + &::before { + content: 'alert'; + } + } +} + +.error { + color: var(--fg-error) !important; +} + +.icon.move, +.move-btn { + &:not(.disabled) { + cursor: move !important; + } +} + +.icon.move { + &::before { + content: 'move'; + color: var(--custom-text-color, var(--ui-control-color)); + } + + &:not(.disabled):hover::before { + color: var(--link-color); + } +} + +.icon.delete { + display: inline-block; + line-height: inherit; + + &::before { + content: 'remove'; + color: var(--ui-control-color); + } + + &:not(.disabled) { + cursor: pointer; + + &:hover::before { + color: var(--bg-disabled); + } + + &:active::before { + color: var(--red-800); + } + } +} + +.hidden { + display: none !important; +} + +// Visually hide without hiding from screen readers +.visually-hidden { + @include mixins.visually-hidden; +} + +.invisible { + visibility: hidden; +} + +.clearafter::after { + @include mixins.clearafter; +} + +.info { + vertical-align: bottom; + display: inline-block; + width: 1em; + height: 1.375em; + text-align: center; + cursor: pointer; + overflow: hidden; + + &::before { + @include mixins.icon; + vertical-align: baseline; + width: 100%; + line-height: 1.375; + color: var(--ui-control-color); + } + + &:not(.warning) { + &::before { + content: 'info'; + } + + &:hover::before { + color: var(--link-color); + } + } + + &.warning { + &::before { + content: 'alert'; + } + + &:hover::before { + color: var(--fg-warning); + } + } +} + +.info-hud { + max-width: 550px; + + table { + max-width: 280px; + table-layout: auto; + } + + td { + overflow-wrap: break-word; + width: 100%; + } +} + +@media (width <= 450px) { + .info-hud { + table { + table-layout: fixed; + width: 100%; + } + } +} + +/* ---------------------------------------- +/* Content +/* ---------------------------------------- */ + +.content { + position: relative; +} + +.content::after { + @include mixins.clearafter; +} + +.checkbox-select-item { + display: flex; + gap: var(--xs); + align-items: flex-start; + align-content: stretch; + padding-block: 4px; + + .move { + margin-block-start: -4px; + margin-inline-end: var(--xs); + position: relative; + z-index: 1; + } + + .action-btn { + margin-block: -4px; + } +} + +ul.path { + display: flex; + flex-flow: row wrap; + align-items: stretch; + + li { + display: inline-flex; + align-items: center; + + &:not(:last-child)::after { + margin-inline: 2px 5px; + margin-block: 0; + @include mixins.angle(right, var(--light-text-color), calc(1rem / 16)); + } + } +} + +/* ---------------------------------------- +/* Icon lists +/* ---------------------------------------- */ + +ul.icons { + margin-block-start: 20px; + display: flex; + flex-wrap: wrap; + + li { + margin-block: 0 10px; + margin-inline: 0 4px; + + a { + display: block; + position: relative; + padding-block: 60px 10px; + padding-inline: 5px; + width: 110px; + text-align: center; + color: var(--text-color); + border-radius: 4px; + border: 1px solid var(--white); + + &::before { + display: block; + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; + width: 100%; + font-size: 40px; + line-height: 60px; + } + + .icon { + position: absolute; + inset-block-start: 12px; + inset-inline-start: 0; + width: 100%; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + + img, + svg { + // give Users, Addresses, Categories, and Filesystems icons a little extra breathing room + max-width: 50px; + height: 40px; + } + + &.icon-mask svg { + @include mixins.svg-mask(var(--text-color)); + } + } + + &:hover { + text-decoration: none; + background-color: var(--gray-050); + border-color: var(--gray-100); + + .icon.icon-mask svg { + @include mixins.svg-mask(var(--link-color)); + } + } + } + } +} + +@media only screen and (width <= 380px) { + ul.icons li a { + width: 96px; + } +} + +@media only screen and (width <= 320px) { + ul.icons li a { + width: 75px; + } +} + +/* ---------------------------------------- +/* Buttons +/* ---------------------------------------- */ + +.toolbar { + position: relative; + margin-block-end: var(--s); + min-height: 34px; + + &.flex, + .flex { + align-items: flex-start; + } + + .text { + border-radius: var(--radius-lg) !important; + } +} + +.inline-flex { + display: inline-flex !important; + align-items: center; + align-content: stretch; + gap: var(--s); +} + +.gap-0 { + gap: 0; +} + +.gap-2xs { + gap: var(--2xs); +} + +.gap-xs { + gap: var(--xs); +} + +.gap-s { + gap: var(--s); +} + +.gap-m { + gap: var(--m); +} + +.gap-l { + gap: var(--l); +} + +.gap-xl { + gap: var(--xl); +} + +.spacer { + width: 14px; +} + +.buttons { + display: flex; + gap: 7px; + position: relative; + margin-block: 24px; + margin-inline: 0; + align-items: center; + + .footer > & { + margin: 0; + } +} + +.btn { + isolation: isolate; + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + border: var(--button-border); + border-radius: var(--button-border-radius); + padding-inline: var(--button-padding); + text-align: center; + user-select: none; + box-sizing: border-box; + appearance: none; + color: var(--text-color); + font-size: inherit; + text-wrap: nowrap; + background-color: var(--button-bg); + min-height: calc(34rem / 16); + + &:hover { + border: var(--button-border--hover); + background: var(--button-bg--hover); + } + + &:active, + &.active { + border: var(--button-border--active); + background: var(--button-bg--active); + } + + &:not([aria-current]) { + cursor: pointer; + } + + &[aria-current], + &.active { + cursor: default; + } + + &.chromeless, + &.hairline, + &.hairline-dark, + &.link-btn { + border: none; + background: transparent; + + &:focus-visible { + box-shadow: var(--focus-ring); + } + } + + &.chromeless { + height: auto; + min-height: var(--touch-target-size); + padding-inline: 0; + + &:hover, + &:active, + &.active, + &:focus { + background: transparent; + } + + &:hover, + &:active, + &.active { + color: var(--link-color); + text-decoration: underline; + } + } + + &.hairline, + &.link-btn { + border: 1px solid var(--border-hairline-medium); + + &:active, + &.active, + &[aria-expanded='true'] { + background: var(--ui-control-static-bg-color); + } + } + + &.hairline { + &:hover, + &:active, + &.active, + &[aria-expanded='true'] { + border-color: var(--border-hairline-dark); + } + } + + &.hairline-dark { + border: 1px solid var(--border-hairline-dark); + + &:not(:hover, :active, .active, [aria-expanded='true']) { + background-color: transparent; + } + } + + &.link-btn { + color: var(--link-color); + + &:hover, + &:active, + &.active, + &[aria-expanded='true'] { + border-color: var(--link-color); + } + } + + &.wrap { + height: auto; + min-height: calc(34rem / 16); + white-space: initial; + text-align: start; + } + + &:not(.disabled, .loading, .dashed, [aria-disabled], [aria-current]) { + &:focus, + &.focus, + &:hover { + --ui-control-bg-color: var(--ui-control-hover-bg-color); + } + + &:active, + &.active, + &[aria-expanded='true'] { + --ui-control-bg-color: var(--ui-control-active-bg-color); + } + } + + &[type='color'] { + padding-inline: 6px !important; + width: 36px; + } + + &.loading { + cursor: default; + } + + &:hover:not(.chromeless) { + text-decoration: none; + } + + &:empty, + &.btn-empty { + padding-inline: 12px; + } + + &[data-icon]:not(:empty, .btn-empty)::before, + &.icon:not(:empty, .btn-empty)::before, + &.menubtn:not(.action-btn)[data-icon]:empty::before, + &.menubtn:not(.action-btn)[data-icon].btn-empty::before, + &.menubtn:not(.action-btn).icon:empty::before, + &.menubtn:not(.action-btn).icon.btn-empty::before { + margin-inline-end: 5px; + } + + &:not(.loading) .spinner { + display: none; + } + + &.loading { + &::before, + &::after, + .cp-icon, + .label { + visibility: hidden; + } + } + + &.copyable { + color: var(--fg-subtle); + + [data-icon] { + margin-inline: 0; + } + } + + [data-icon] { + margin-block-start: -3px; + margin-inline-end: 5px; + + &.light::before { + color: var(--gray-300); + } + } + + .cp-icon svg { + @include mixins.svg-mask(currentColor); // Matches color of font icons + } + + &.header-btn { + margin-block: 2px; + margin-inline: 0; + @include mixins.header-btn; + } +} + +.disabled:not(.status, .status-label) { + opacity: 0.5; + user-select: none; + cursor: not-allowed !important; + + .layoutdesigner { + pointer-events: none; + } +} + +.noteditable { + cursor: not-allowed; + + .element, + .lightswitch-container, + & + .colorhex { + cursor: not-allowed; + } +} + +.btn { + height: var(--input-height); + min-height: var(--input-height); +} + +.btn[data-icon-after]:not(:empty, .btn-empty)::after, +.menu-toggle:not(:empty, .btn-empty)::after, +.menubtn:not(.action-btn, :empty, .btn-empty)::after, +.menubtn:not(.action-btn).icon::after { + margin-inline-start: 6px; +} + +.btn[data-icon]::before, +.btn[data-icon-after]::after, +.btn.icon::before { + position: relative; +} + +.btn.small { + --icon-size: calc(12rem / 16); + + &[data-icon]::before, + &[data-icon-after]::after, + &.icon::before { + font-size: 12px; + } +} + +/* button groups */ +.btngroup-container { + margin: -3px; + padding: 3px; + overflow-x: auto; +} + +.btngroup { + position: relative; + z-index: 1; + display: flex; + white-space: nowrap; + align-items: center; + border-radius: var(--radius-lg); + + &.fullwidth .btn { + flex: 1; + } + + &.disabled .btn { + cursor: default; + } + + .btn { + &:focus { + z-index: 1; + } + + &:not(.dashed, :last-child, .btngroup-btn-last) { + margin-inline-end: 1px; + } + + &:not(:first-child, .btngroup-btn-first) { + border-start-start-radius: 0; + border-end-start-radius: 0; + } + + &:not(:last-child, .btngroup-btn-last) { + border-start-end-radius: 0; + border-end-end-radius: 0; + } + } +} + +.btngroup--exclusive { + .btn[aria-pressed='true']:not(.disabled, .loading, .dashed, [aria-disabled]) { + --focus-ring: var(--focus-ring-outset); + background-color: var(--gray-500); + color: var(--white); + } +} + +.copytext { + position: relative; + z-index: 1; + display: flex; + white-space: nowrap; + + .text { + border-start-end-radius: 0; + border-end-end-radius: 0; + min-width: 0; + } + + .btn { + border-start-start-radius: 0; + border-end-start-radius: 0; + } +} + +craft-copy-attribute { + display: inline-block; + @include mixins.fixed-width-font(calc(11rem / 16)); + color: var(--fg-subtle); + height: calc(22rem / 16); + + button { + gap: 5px; + display: inline-flex; + border: 1px solid var(--border-hairline); + border-radius: var(--button-border-radius); + padding-inline: 5px; + flex-wrap: nowrap; + align-items: center; + cursor: pointer; + height: 100%; + + &:hover, + &:focus { + border-color: var(--border-hairline-medium); + color: var(--text-color); + } + + span[data-icon] { + margin-block-start: -3px; + } + } +} + +/* menu buttons */ +.menu-toggle, +.menubtn:not(.action-btn) { + display: inline-flex; + align-items: center; + user-select: none; + + &::after { + @include mixins.angle; + position: relative; + } + + &.btn { + &::after { + inset-block-start: -1px; + } + + &:not(.disabled, .inactive) { + &:active, + &.active { + &::after { + border-color: var(--ui-control-active-color); + } + } + } + + &.submit { + &::after { + border-color: var(--white) !important; + opacity: 0.8; + } + + &:not(.disabled, .inactive) { + &:hover, + &.hover, + &:active, + &.active { + &::after { + opacity: 1; + } + } + } + } + } + + &:not(.btn, .icon) { + height: 17px; + + &::after { + inset-block-start: -2px; + border-color: currentcolor; + } + } + + &:empty, + &.btn-empty { + padding-inline: 8px; + } +} + +@keyframes rotator { + 0% { + transform: rotate(0); + } + + 100% { + transform: rotate(1turn); + } +} + +/* spinner */ +.spinner { + display: inline-flex; + align-items: center; + justify-content: center; + width: var(--size, 24px); + height: var(--size, 34px); + + &::before { + display: block; + content: ''; + font-size: 0; + animation: rotator 0.7s linear infinite; + box-sizing: border-box; + width: var(--size, 20px); + height: var(--size, 20px); + object-fit: scale-down; + border-radius: 50%; + border: 2px solid transparent; + border-inline-end-color: currentcolor; + border-block-end-color: currentcolor; + opacity: 0.8; + } + + &.small { + --size: 12px; + } + + &.big { + --size: 48px; + } + + &.spinner-absolute { + position: absolute; + width: var(--size, 20px); + height: var(--size, 20px); + transform: translateX(-50%) translateY(-50%); + inset-block-start: 50%; + inset-inline-start: 50%; + z-index: 101; + + .rtl & { + transform: translateX(50%) translateY(-50%); + } + } +} + +.btn + .spinner { + margin-inline-start: 7px; +} + +.buttons .btn + .spinner, +.buttons .btngroup + .spinner { + margin-inline-start: 0; +} + +.buttons.right .btn + .spinner { + margin-inline-end: var(--neg-padding); +} + +/* small buttons */ +.btngroup.small .btn, +.btn.small { + padding-block: 0 !important; + padding-inline: var(--s) !important; + font-size: 12px; + line-height: calc(22rem / 16); + min-height: calc(22rem / 16) !important; +} + +.btngroup.small, +.btngroup.small input.btn, +.btn.small, +.btn.small + .spinner { + height: calc(22rem / 16); +} + +/* big buttons */ +.btngroup.big .btn, +.btn.big { + padding-block: 0; + padding-inline: 14px; + font-size: 14px; + line-height: 36px; +} + +.btn.big[data-icon]::before, +.preview-btn::before, +.view-btn::before { + margin-inline-start: -2px; +} + +.btngroup.big, +.btngroup.big input.btn, +.btn.big, +.btn.big + .spinner { + min-height: calc(36rem / 16); +} + +/* huge buttons */ +.btn.huge { + padding-inline: var(--l); + line-height: calc(48rem / 16); + height: calc(48rem / 16); +} + +/* special buttons */ +.btn { + &.submit, + &.secondary { + --ui-control-active-color: var(--white); + --focus-ring: var(--focus-ring-outset); + @include mixins.light-on-dark-text; + } + + &.submit { + border: var(--primary-button-border) !important; + color: var(--primary-button-text-color) !important; + background: var(--primary-button-bg) !important; + + &:not(.disabled, .inactive, .loading) { + &:hover, + &.hover { + border: var(--primary-button-border--hover) !important; + background: var(--primary-button-bg--hover) !important; + } + + &:active, + &.active, + &[aria-expanded='true'] { + border: var(--primary-button-border--active) !important; + background: var(--primary-button-bg--active) !important; + } + } + } + + &.caution { + background-color: var(--red-050) !important; + color: var(--fg-error); + + &:hover, + &.hover, + &:focus { + background-color: color.adjust( + mixins.$red050, + $lightness: -5% + ) !important; + } + + &:active, + &.active, + &[aria-expanded='true'] { + background-color: var(--red-100) !important; + } + } +} + +.secondary-buttons .btn.submit, +.btn.secondary { + border: var(--secondary-button-border) !important; + color: var(--secondary-button-text-color) !important; + background: var(--secondary-button-bg) !important; +} + +.secondary-buttons .btn.submit:not(.disabled, .inactive, .loading):hover, +.secondary-buttons .btn.submit:not(.disabled, .inactive, .loading).hover, +.secondary-buttons .btn.submit:not(.disabled, .inactive, .loading):focus, +.btn.secondary:not(.disabled, .inactive, .loading):hover, +.btn.secondary:not(.disabled, .inactive, .loading).hover, +.btn.secondary:not(.disabled, .inactive, .loading):focus { + border: var(--secondary-button-border--hover) !important; + background: var(--secondary-button-bg--hover) !important; +} + +.secondary-buttons .btn.submit:not(.disabled, .inactive, .loading):active, +.secondary-buttons .btn.submit:not(.disabled, .inactive, .loading).active, +.secondary-buttons + .btn.submit:not(.disabled, .inactive, .loading)[aria-expanded='true'], +.btn.secondary:not(.disabled, .inactive, .loading):active, +.btn.secondary:not(.disabled, .inactive, .loading).active, +.btn.secondary:not(.disabled, .inactive, .loading)[aria-expanded='true'] { + border: var(--secondary-button-border--active) !important; + background: var(--secondary-button-bg--active) !important; +} + +div.btn.submit { + position: relative; + overflow: hidden; +} + +div.btn.submit input { + position: absolute; + inset-inline-start: 100%; +} + +/* dashed buttons */ +.btn.dashed { + border: 1px dashed #{color.adjust(mixins.$inputColor, $alpha: -0.5)}; + background-color: transparent; + + .btngroup &:not(:last-child, .btngroup-btn-last) { + border-inline-end: 1px solid transparent; + margin-inline-end: -1px; + } + + &:focus-visible { + background-color: color.adjust(mixins.$grey200, $alpha: -0.9); + border-color: transparent; + } + + &:not(.disabled) { + &:active, + &.active, + &[aria-expanded='true'] { + background-color: color.adjust(mixins.$grey200, $alpha: -0.75); + } + } +} + +/* chevron buttons */ +.chevron-btns { + display: flex; + justify-content: flex-start; + + .btn { + position: relative; + padding-inline: 0; + border-radius: 0; + background-color: transparent; + height: var(--ui-control-height); + min-height: auto; + + &.current-step, + &.active-drop-target { + color: var(--white); + + --text-color: var(--white); + --ui-control-color: var(--white); + --ui-control-bg-color: var(--gray-500); + --ui-control-hover-bg-color: #{color.adjust( + mixins.$grey500, + $lightness: -5% + )}; + --ui-control-active-bg-color: #{color.adjust( + mixins.$grey500, + $lightness: -10% + )}; + } + + &.current-step { + --focus-ring: var(--focus-ring-light); + @include mixins.light-on-dark-text; + } + + &:focus-visible { + z-index: 1; + box-shadow: none; + + .label { + z-index: 1; + box-shadow: var(--focus-ring); + } + } + + &:not(.has-action-menu) { + padding-inline-end: calc(var(--ui-control-height) / 2); + margin-inline-end: 2.8px; + + &:not(.current-step[data-disclosure-trigger]) .btn-body { + padding-inline-end: 5px; + } + } + + &.current-step[data-disclosure-trigger] .btn-body { + padding-inline-start: 8px; + + .label { + padding: 3px; + + &::after { + @include mixins.angle; + position: relative; + } + } + } + + .btn-body { + display: inline-flex; + align-items: center; + justify-content: center; + height: 100%; + background-color: var(--ui-control-bg-color); + + [data-icon] { + --ui-control-height: calc((13rem / 16)); // 1rem == 16px + text-align: center; + margin-inline-end: 0; + } + } + + .label { + display: inline-flex; + align-items: center; + overflow: hidden; + text-overflow: ellipsis; + } + + &.has-action-menu .btn-body { + padding-inline-end: 1px; + margin-inline-end: 0; + } + + .chevron-right, + .chevron-left { + position: absolute; + inset-block-start: 0; + height: 100%; + width: calc(var(--ui-control-height) / 2); + } + + .chevron-left { + inset-inline-start: 0; + border-block-start: calc(var(--ui-control-height) / 2) solid + var(--ui-control-bg-color); + border-inline-start: calc(var(--ui-control-height) / 2) solid transparent; + + &::after { + display: block; + content: ''; + font-size: 0; + position: absolute; + inset-block-end: 0; + inset-inline-end: 0; + border-block-end: calc(var(--ui-control-height) / 2) solid + var(--ui-control-bg-color); + border-inline-start: calc(var(--ui-control-height) / 2) solid + transparent; + } + } + + .chevron-right { + inset-inline-end: 0; + border-block-start: calc(var(--ui-control-height) / 2) solid transparent; + border-block-end: calc(var(--ui-control-height) / 2) solid transparent; + border-inline-start: calc(var(--ui-control-height) / 2) solid + var(--ui-control-bg-color); + } + } + + ol { + position: relative; + padding-inline-start: 0; + list-style-type: none; + display: flex; + + li { + &.first-step .btn { + .btn-body { + padding-inline-start: 14px; + border-start-start-radius: var(--ui-control-border-radius); + border-start-end-radius: 0; + border-end-end-radius: 0; + border-end-start-radius: var(--ui-control-border-radius); + } + + .chevron-left { + display: none; + } + } + + &:not(.first-step) .btn { + margin-inline-start: calc(-1 * (var(--ui-control-height) / 2)); + padding-inline-start: calc(var(--ui-control-height) / 2); + + .btn-body { + padding-inline-start: 7px; + } + } + } + } +} + +/* color inputs */ +.color-input-container { + position: relative; + + .color-hex-indicator { + position: absolute; + inset-block-start: 0; + inset-inline-start: 7px; + width: 1em; + line-height: 34px; + text-align: center; + user-select: none; + } +} + +.color-input { + @include mixins.fixed-width-font; + padding-inline: calc(7px + 1em) 9px; +} + +.color { + display: inline-block; + position: relative; + vertical-align: middle; + width: 34px; + height: 34px; + border-radius: 17px; + padding: 0; + + &:not(.static, .noteditable) { + cursor: pointer; + } + + &:not(.small) { + @include mixins.checkered-bg(17px); + } + + &.small { + width: 16px; + height: 16px; + @include mixins.checkered-bg(8px); + } + + .color-preview { + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; + width: 100%; + height: 100%; + border-radius: 17px; + box-shadow: inset 0 0 0 1px color.adjust(mixins.$black, $alpha: -0.85); + + &:focus-within { + @include mixins.input-focused-styles; + } + + & > .color-preview-input { + position: absolute; + inset-inline-start: 0; + width: 100%; + height: 100%; + margin: 0; + padding: 0; + border: none; + opacity: 0; + } + } +} + +.colorhex { + display: inline-block; + margin-inline-start: 5px; + vertical-align: middle; + color: var(--fg-subtle); +} + +/* lightswitch */ +.lightswitch-outer-container { + display: flex; + + .lightswitch-inner-container { + border: 1px solid var(--border-hairline); + border-radius: var(--radius-sm); + display: flex; + align-items: center; + max-width: 100%; + padding-inline: 7px; + + span { + flex-grow: 1; + padding-block: 7px; + padding-inline: 0; + color: var(--fg-subtle); + cursor: default; + overflow: auto; + overflow-wrap: break-word; + hyphens: auto; + + &[data-toggle='on'] { + margin-inline-start: 7px; + } + + &[data-toggle='off'] { + margin-inline-end: 7px; + text-align: end; + } + } + } +} + +.lightswitch { + // Ensures contrast with pane background is over 3:1 + --_lightswitch-border-color: var( + --lightswitch-border-color, + hsl(from var(--input-border-color) h s l / 80%) + ); + display: block; + position: relative; + border: none !important; + overflow: hidden; + cursor: pointer; + user-select: none; + background-image: linear-gradient(to right, var(--gray-200), var(--gray-200)); + transition: background-image linear 100ms; + box-shadow: inset 0 0 0 1px var(--_lightswitch-border-color); + + &[disabled] { + --_lightswitch-border-color: var( + --lightswitch-border-color-disabled, + hsl(from var(--input-border-color) h s l / 30%) + ); + } + + &.on { + --_lightswitch-border-color: oklch( + from var(--bg-enabled) calc(l - 0.1) c h + ); + background-image: linear-gradient( + to right, + var(--bg-enabled), + var(--bg-enabled) + ); + + .lightswitch-container .handle::before { + background-color: var(--enabled-color); + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3E%3C!--! Font Awesome Pro 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2024 Fonticons, Inc. --%3E%3Cpath d='M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z'/%3E%3C/svg%3E%0A"); + mask-repeat: no-repeat; + } + + // Makes small icon a little darker to compensate for the size + &.small .lightswitch-container .handle::before { + background-color: hsl(from var(--enabled-color) h s calc(l - 20)); + } + } + + &.indeterminate { + background-image: linear-gradient( + to right, + var(--bg-enabled) 40%, + var(--gray-200) 60% + ); + } + + .lightswitch-container { + position: relative; + height: 100%; + + .handle { + position: absolute; + inset-block-start: 2px; + background-color: var(--white); + box-shadow: inset 0 0 0 1px var(--_lightswitch-border-color); + } + + .handle::before { + content: ''; + position: absolute; + inset-block-start: 50%; + inset-inline-start: 54%; + transform: translateX(-50%) translateY(-50%); + width: 12px; + height: 12px; + } + } + + &:not(.small) { + border-radius: 11px; + min-width: 34px; + width: 34px; + height: 22px; + + .lightswitch-container { + margin-inline-start: -12px; + width: 46px; + + .handle { + border-radius: 9px; + width: 18px; + height: 18px; + inset-inline-start: calc(50% - 9px); + } + } + } + + &.small { + border-radius: 9px; + width: 28px; + height: 18px; + + .lightswitch-container { + margin-inline-start: -10px; + width: 38px; + + .handle { + border-radius: 8px; + width: 14px; + height: 14px; + inset-inline-start: calc(50% - 7px); + } + + .handle::before { + width: 8px; + height: 8px; + } + } + } + + table & { + display: inline-block; + margin-block-end: -5px; + } + + &.on { + .lightswitch-container { + margin-inline-start: 0; + } + } + + &.indeterminate { + &:not(.small) { + .lightswitch-container { + margin-inline-start: 0.5 * -12px; + } + } + + &.small { + .lightswitch-container { + margin-inline-start: 0.5 * -10px; + } + } + } +} + +/* pagination */ +.pagination { + table.data + & { + margin-block-start: 24px; + } + + .page-link { + width: calc(30rem / 16); + height: calc(30rem / 16); + display: flex; + align-items: center; + justify-content: center; + border-radius: var(--radius-md); + + &::after { + position: relative; + transition: border-color linear 100ms; + } + + &.prev-page::after { + @include mixins.angle(left, var(--light-text-color)); + inset-inline-end: -1px; + } + + &.next-page::after { + @include mixins.angle(right, var(--light-text-color)); + inset-inline-start: -1px; + } + + &:not(.disabled) { + transition: box-shadow linear 100ms; + box-shadow: inset 0 0 0 1px var(--border-hairline); + cursor: pointer; + + &:hover { + text-decoration: none; + box-shadow: inset 0 0 0 1px var(--link-color); + + &::after { + border-color: var(--link-color); + } + } + + &:focus-visible { + box-shadow: + inset 0 0 0 1px var(--border-hairline), + var(--focus-ring); + } + } + + &.disabled { + opacity: 1; + + &::after { + border-color: var(--border-hairline); + } + } + } +} + +/* action buttons */ +.actions { + float: inline-end; +} + +.actions > li { + float: inline-start; +} + +.actions > li + li { + margin-inline-start: 10px; +} + +h1 + .actions { + margin-block-start: -100px; +} + +h2 + .actions { + margin-block-start: -54px; +} + +/* ---------------------------------------- +/* Tables +/* ---------------------------------------- */ + +.tablepane { + --pane-y-padding-default: calc(var(--xl) - 2px); + --pane-x-padding-default: calc(var(--padding) - 2px); + + #content & { + --pane-padding: var(--pane-x-padding-default); + } + + margin-block: calc(var(--pane-padding, var(--pane-y-padding-default)) * -1) + calc( + var(--pane-padding, var(--padding)) * -1 + var(--pane-padding, var(--m)) + ); + margin-inline: calc(var(--pane-padding, var(--pane-x-padding-default)) * -1); + padding: 0 !important; + overflow-x: auto; + + table.data { + th, + td { + &:first-child:not(.checkbox-cell, .vuetable-th-slot-checkbox) { + padding-inline-start: var( + --pane-padding, + var(--pane-x-padding-default) + ); + } + + &:last-child { + padding-inline-end: var(--pane-padding, var(--pane-x-padding-default)); + } + } + } +} + +table:not(.cp-table) { + &.fixed-layout { + table-layout: fixed; + } + + th.thin, + td.thin { + width: 0.01% !important; + white-space: nowrap; + } + + thead { + th { + font-weight: bold; + text-align: start; + vertical-align: top; + } + } + + // plain tables + &:not(.data) { + th, + td { + padding-block: 7px; + + &:not(:first-child) { + padding-inline-start: 12px; + } + + &:not(:last-child) { + padding-inline-end: 12px; + } + } + } + + // data tables + &.data { + th, + td { + position: relative; + padding-inline: 12px; + box-sizing: border-box; + + &.checkbox-cell, + &.vuetable-th-slot-checkbox { + width: var(--checkbox-size) !important; + min-width: var(--checkbox-size); + box-sizing: content-box; + position: relative; + + input.checkbox + label, + div.checkbox { + position: absolute; + inset-block-start: calc(50% - 8rem / 16); + } + } + } + + th { + font-weight: bold; + } + + thead:first-child, + tbody:first-child, + tfoot:first-child, + caption + thead, + caption + tbody, + caption + tfoot { + tr:first-child { + th, + td { + &:first-child { + border-start-start-radius: var(--border-radius, var(--radius-sm)); + border-end-start-radius: var(--border-radius, var(--radius-sm)); + } + + &:last-child { + border-start-end-radius: var(--border-radius, var(--radius-sm)); + border-end-end-radius: var(--border-radius, var(--radius-sm)); + } + } + } + } + + thead { + th, + td { + width: auto; + background-color: var(--gray-050); + cursor: default; + } + + th:not(.orderable), + td { + padding-block: var(--s); + } + + th { + white-space: nowrap; + vertical-align: middle; + + &.orderable { + position: relative; + padding: 0 !important; + + body:not(.dragging) &:not(.ordered):hover { + background-color: var(--gray-100); + } + + &.ordered { + background-color: var(--bg-selection-light); + + &:not(.loading) { + button::after { + @include mixins.angle(up); + position: absolute; + inset-inline-end: var(--m); + inset-block-start: calc(50% - 3px); + } + + &.desc button::after { + transform: rotate(45deg); + } + } + } + + button { + position: relative; + font: inherit; + width: 100%; + padding-block: var(--m); + padding-inline: var(--m) 35px; + text-align: start; + + &:focus { + z-index: 1; + } + } + } + + &:not(.loading) { + .spinner { + display: none; + } + } + + .spinner { + position: absolute; + inset-block-start: calc(50% - 6px); + inset-inline-end: 8px; + + --size: 12px; + } + } + } + + tbody { + tr { + --hover-bg-color: var(--gray-050); + --selected-bg-color: var(--bg-selection-dark); + + &:not(.disabled) { + &:hover { + th, + td { + background-color: var(--hover-bg-color); + } + } + + &:focus { + position: relative; + z-index: 1; + } + + &.sel, + &.active-drop-target { + --text-color: var(--white); + --fg-subtle: var(--white); + --light-text-color: var(--white); + --link-color: var(--white); + --ui-control-color: var(--white); + --focus-ring: var(--focus-ring-light); + + .status-label .status-label-text { + --status-label-text-color: var(--white) !important; + } + + th, + td { + color: var(--white); + background-color: var(--selected-bg-color); + + .chip { + color: var(--white); + + &:not(.chromeless) { + background-color: var( + --custom-sel-bg-color, + var(--gray-600) + ) !important; + } + } + } + + .icon, + .cp-icon, + [data-icon], + [data-icon-after] { + --icon-color: var(--white) !important; + } + } + } + } + + th, + td { + padding-block: 7px; + max-width: 33vw; + } + + td { + &.timestamp { + text-align: end; + vertical-align: bottom; + white-space: nowrap; + color: var(--light-text-color); + } + } + } + + thead + tbody tr, + tr + tr { + th, + td { + border-block-start: 1px solid transparent; + } + } + + tr.sel:not(.draggee) + tr.sel:not(.draggee) { + th, + td { + border-block-start-color: var(--gray-300); + } + } + + &.vuetable { + th.sortable { + &:hover { + color: var(--text-color); + background-color: var(--gray-100); + } + + &.ordered { + background-color: var(--bg-selection-light); + + .sort-icon { + @include mixins.angle(up); + inset-inline-end: var(--m); + inset-block-start: calc(7rem / 16); + } + + &.desc .sort-icon { + transform: rotate(45deg); + inset-block-start: calc((7rem / 16) - (2rem / 16)); + } + } + } + } + } + + // collapsable data tables for small screens + // based on Aaron Gustafson's technique: http://blog.easy-designs.net/archives/2013/02/02/responsive-tables/ + &.collapsed { + width: auto; + + &, + tbody, + tbody tr, + tbody th, + tbody td { + display: block; + border: none; + padding: 0; + text-align: start; + width: auto !important; + white-space: normal; + } + + thead { + display: none; + } + + tbody { + tr { + padding-block: 6px; + padding-inline: 0; + border-block-end: 1px dotted var(--border-hairline); + + &::after { + @include mixins.clearafter; + } + } + + th, + td { + padding-block: 2px !important; + padding-inline: 0 !important; + } + + td { + &:empty { + display: none; + } + } + + [data-title] { + margin-inline-end: 0; + + &::before { + margin-inline-end: 5px; + content: attr(data-title) ':'; + font-weight: bold; + } + + form { + display: inline-block; + } + } + } + } +} + +.datatablesorthelper, +.editabletablesorthelper { + background-color: var(--white); + @include mixins.shadow; +} + +.datatablesorthelper, +.datatablesorthelper .chip, +.datatablesorthelper a { + cursor: move !important; +} + +.datatablesorthelper tr:first-child th, +.datatablesorthelper tr:first-child td { + border-block-start: none !important; +} + +.datatablesorthelper tr:last-child th, +.datatablesorthelper tr:last-child td { + border-block-end: none !important; +} + +.datatablesorthelper th .toggle { + display: none !important; +} + +.chip, +.card, +.matrixblock { + position: relative; + + &:not(.chromeless) { + border-radius: var(--radius-lg); + color: var(--custom-text-color, var(--text-color)); + } + + --custom-border-color: initial; + --custom-titlebar-bg-color: initial; + --custom-bg-color: initial; + --custom-text-color: initial; + --custom-sel-titlebar-bg-color: initial; + --custom-sel-bg-color: initial; + + &:not(.chromeless, .hairline) { + background-color: var(--custom-bg-color, var(--gray-050)); + box-shadow: 0 2px 6px -1px rgb(0 0 0 / 5%); + } + + &:not(.chromeless)::before { + position: absolute; + content: ''; + inset: 0; + border-radius: var(--radius-lg); + box-shadow: inset 0 0 0 1px var(--custom-border-color, var(--gray-200)); + pointer-events: none; + z-index: 1; + } +} + +.chip, +.card { + overflow: clip; // needed for status indicators + + &.sel, + tr.sel &, + li.sel &, + li.active-drop-target &, + .card.sel & { + --text-color: var(--white); + --custom-text-color: var(--white) !important; + --fg-subtle: var(--white); + --light-text-color: var(--white); + --link-color: var(--white); + --ui-control-color: var(--white); + --custom-border-color: rgb(0 0 0 / 10%) !important; + --focus-ring: var(--focus-ring-light); + color: var(--white); + + &:not(.chromeless) { + background-color: var( + --custom-sel-bg-color, + var(--bg-selection-dark) + ) !important; + } + + .icon, + .cp-icon, + [data-icon], + [data-icon-after] { + --icon-color: var(--white) !important; + } + + .thumb { + filter: brightness(0.85); + opacity: 0.75; + } + } +} + +/* chips */ +.chip { + position: relative; + display: inline-flex; + align-items: center; + cursor: default; + user-select: none; + font-weight: normal; + padding-block: 0; + max-width: 100%; + gap: var(--xs); + + &:not(.chromeless) { + padding-inline: var(--s); + } + + &.small { + flex-direction: row; + + --thumb-size: calc(30rem / 16); + + & > .thumb { + margin-inline-end: 2px; + margin-block: 0; + + &.cp-icon { + --thumb-size: 1rem; // 16px + } + } + + &:not(.chromeless) { + min-height: calc(26rem / 16 + 8px); + + & > .thumb { + margin-inline-start: -2px; + } + } + } + + &.large { + flex-direction: column; + + --thumb-size: 120px; + min-width: calc(var(--s) * 2 + var(--thumb-size)); + width: 100%; + + .chip-content { + width: 100%; + } + + &:not(.chromeless) { + padding-block: var(--xs); + } + } + + .chip-content { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--s); + width: 100%; + + .infoicon-container { + margin-inline-start: var(--xs); + } + + .status, + .icon { + margin-inline-end: 0; + } + + .icon { + margin-block: -4px 0; + margin-inline: -1px; + } + + .label { + flex: 1; + } + + .chip-label { + padding-block: var(--xs); + padding-inline: 0; + display: flex; + flex-direction: column; + gap: var(--xs); + + .indicators { + display: flex; + gap: var(--xs); + padding-block: var(--2xs); + } + } + + .chip-actions { + margin-inline-start: auto; + } + } + + &:not(.large) .chip-content .chip-actions { + margin-inline-end: 4px; + } + + &:has(.thumb):not(.large) .chip-content { + min-width: calc(100% - var(--thumb-size) - var(--s)); + } + + .offset-drag-helper & { + background-color: var(--gray-050); + @include mixins.shadow; + } + + & > .thumb { + flex: 0 0 auto; + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: var(--thumb-size); + height: var(--thumb-size); + + &.rounded { + img, + svg { + border: var(--xs) solid transparent; + border-radius: 50%; + } + } + + &.checkered img { + @include mixins.checkered-bg(8px); + } + + img, + svg { + display: block; + flex-shrink: 0; + max-width: 100%; + max-height: 100%; + } + + &:not(.cp-icon) { + img, + svg { + border-radius: var(--radius-sm); + } + } + + svg { + width: 100%; + } + } +} + +.chips, +.cards { + display: flex; + + &:not(.inline-chips) { + flex-direction: column; + } + + li { + max-width: 100%; + } +} + +.cards { + gap: var(--s); +} + +.chips { + align-items: flex-start; + gap: var(--xs); +} + +.inline-chips { + display: flex; + flex-flow: row wrap; + align-items: center; + gap: var(--xs); + + .chip { + margin: 0 !important; + } +} + +.elements.inline-chips.chips-large { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); +} + +/** cards */ +.card { + display: flex; + flex-direction: column; + container-type: inline-size; + + &::after { + border-radius: var(--radius-lg); + } + + & > .card-titlebar { + display: flex; + flex-direction: column; + justify-content: space-between; + padding-inline: var(--m); + background-color: var(--custom-titlebar-bg-color, var(--gray-100)); + border-start-start-radius: var(--radius-lg); + border-start-end-radius: var(--radius-lg); + user-select: none; + + @container (min-width: 200px) { + flex-direction: row; + align-items: center; + min-height: calc(var(--lh) + 10px); + } + + .card-titlebar-label { + font-size: 0.8em !important; + } + + & > .card-actions-container { + display: flex; + align-items: flex-start !important; + position: relative; + } + } + + & > .card-main { + display: grid; + position: relative; + padding-block: var(--s); + padding-inline: var(--m); + gap: var(--s); + border-end-start-radius: var(--radius-lg); + border-end-end-radius: var(--radius-lg); + width: 100%; + overflow: hidden; + + @container (min-width: 200px) { + grid-template-areas: 'content thumb'; + grid-template-columns: 1fr auto; + } + + & > .thumb { + grid-area: thumb; + display: flex; + justify-content: center; + flex: 0 0 120px; + width: 120px; + max-height: 120px; + overflow: hidden; + align-self: start; + + img, + svg { + max-width: 120px; + max-height: 120px; + border-radius: var(--radius-sm); + } + } + + & > .card-content { + grid-area: content; + } + } + + &.thumb-start > .card-main { + grid-template-areas: 'thumb content'; + grid-template-columns: auto 1fr; + } + + .ck-content & { + ul { + padding-inline: 0 !important; + list-style-type: none; + } + } + + .card-content, + .card-content .card-body { + display: flex; + flex-direction: column; + gap: var(--xs); + flex: 1; + } + + .card-content { + flex: 1 0 0 !important; + overflow: hidden; + position: relative; + + --focus-ring: var(--focus-ring-inner); + + .card-heading { + display: flex; + flex-direction: row; + align-items: center; + gap: 5px; + min-height: calc(22rem / 16); + + .label { + font-weight: 600; + } + } + + .card-body { + &:empty { + display: none; + } + + & > .card-attribute-preview:not(:has(> .no-truncate)) { + --max-lines: 2; + margin: 0; + max-height: calc(var(--lh) * var(--max-lines)); + overflow: hidden; + text-wrap: pretty; + } + } + } + + &.sel, + li.sel & { + --text-color: var(--white); + --custom-text-color: var(--white) !important; + --fg-subtle: var(--white); + --light-text-color: var(--white); + --link-color: var(--white); + --ui-control-color: var(--white); + --focus-ring: var(--focus-ring-light); + color: var(--white); + background-color: var( + --custom-sel-bg-color, + var(--bg-selection-dark) + ) !important; + + & > .card-titlebar { + background-color: var(--custom-sel-titlebar-bg-color, var(--gray-600)); + + .icon, + .cp-icon, + [data-icon], + [data-icon-after] { + --icon-color: var(--white) !important; + } + } + + .status-label .status-label-text { + --status-label-text-color: var(--white) !important; + } + } +} + +// Adjust the columns when in live preview +.lp-editor-container .card-grid, +.width-50 .card-grid, +.width-25 .card-grid { + grid-template-columns: minmax(0, 1fr); +} + +.context-label, +.context-menu-container { + display: inline-flex; + align-items: center; + margin-inline-start: var(--xs); + height: var(--touch-target-size); + padding-block: 0; + padding-inline: var(--s); + font-size: 11px; + font-weight: normal; + text-decoration: none !important; + color: var(--fg-subtle); + border-radius: calc(var(--touch-target-size) / 2); + border: 1px solid var(--border-hairline-medium); +} + +.context-menu-container { + padding-inline-end: 0; + + .menubtn:not(.action-btn) { + margin-inline: 0 -1px; + margin-block: 0; + padding-inline-end: 2px !important; + border-inline-start: 1px solid var(--border-hairline-medium); + border-start-start-radius: 0; + border-start-end-radius: calc(var(--touch-target-size) / 2); + border-end-end-radius: calc(var(--touch-target-size) / 2); + border-end-start-radius: 0; + + &:hover { + border-color: var(--border-hairline-dark) !important; + } + } + + > * { + display: inline-block; + padding-inline-end: var(--s); + } +} + +// fix for context menus that are only children +.context-menu-container .menubtn:not(.action-btn):only-child, +.context-menu-container + .visually-hidden:first-child + + .menubtn:not(.action-btn):last-child { + margin-block: 0; + margin-inline: calc(var(--s) * -1); + border-inline-start: none !important; + border-radius: calc(var(--touch-target-size) / 2) !important; +} + +.chip > .chip-content > .chip-actions, +.card > .card-titlebar > .card-actions-container > .card-actions, +.matrixblock > .actions { + display: flex; + flex-direction: row; + align-items: center; + gap: var(--s); + min-height: calc(22rem / 16); + + &:empty { + display: none; + } + + & > .status { + margin: 0; + } + + & > .btn.chromeless, + & > .action-btn { + padding-inline: 0 !important; + height: var(--touch-target-size); + width: var(--touch-target-size); + margin-block: 0; + margin-inline: -4px; + + &::before { + color: var(--custom-text-color, var(--ui-control-color)); + } + } + + .action-btn { + background-color: transparent; + + &::before { + margin-inline-end: 0 !important; + } + + &:hover, + &:active, + &[aria-expanded='true'] { + backdrop-filter: brightness(90%); + } + } +} + +.chip, +.card { + // prevent double focus ring (chip/card already gets it) + .checkbox::before { + box-shadow: none !important; + } + + .label { + --focus-ring: var(--focus-ring-inner); + display: flex; + align-items: center; + gap: var(--xs); + overflow: hidden; + + .label-link { + flex: 1 1 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + .sel & { + --focus-ring: var(--focus-ring-inner-light); + } + } + + // label links inside cards and chip should be coloured as regular a tags despite not having href attribute + a.label-link { + color: var(--link-color); + } + + .segment::after { + display: inline-flex !important; + position: relative; + inset-block-start: -2px; + margin-inline: 2px 5px; + margin-block: 0; + @include mixins.angle(right, var(--light-text-color), calc(1rem / 16)); + + .sel & { + @include mixins.angle(right, var(--white), calc(1rem / 16)); + } + } + } + + &.error .label .label-link { + color: var(--fg-error); + } +} + +.element-index { + .source-path { + // see https://github.com/craftcms/cms/issues/18876 + position: relative; + z-index: 1; + + background-color: var(--gray-050); + border-radius: 3px; + + --ui-control-bg-color: var(--bg-selection-light); + --ui-control-hover-bg-color: #{color.adjust( + mixins.$lightSelColor, + $lightness: -5% + )}; + --ui-control-active-bg-color: #{color.adjust( + mixins.$lightSelColor, + $lightness: -10% + )}; + + .chevron-btns { + display: inline-flex; + position: relative; + background: mixins.$white; + + --ui-control-height: calc((30rem / 16)); // 1rem == 16px + + &::before { + display: block; + content: ''; + font-size: 0; + position: absolute; + inset-block-start: 0; + width: 0; + height: 0; + inset-inline-end: 0; + border-block-start: calc(var(--ui-control-height) / 2) solid + mixins.$grey050; + border-inline-start: calc(var(--ui-control-height) / 2) solid + transparent; + } + + &::after { + display: block; + content: ''; + font-size: 0; + position: absolute; + inset-block-start: calc(var(--ui-control-height) / 2); + inset-inline-end: 0; + border-block-end: calc(var(--ui-control-height) / 2) solid + mixins.$grey050; + border-inline-start: calc(var(--ui-control-height) / 2) solid + transparent; + } + + .btn { + --ui-control-border-radius: 3px; + } + } + + .btn.settings { + box-shadow: 0 0 0 2px var(--white); + } + } + + &.main { + .source-path { + margin-block: calc(var(--padding) * -1 + 2px) 24px; + margin-inline: calc(var(--padding) * -1 + 2px); + + & + .elements > .tablepane { + margin-block-start: calc(var(--xl) * -1 + 2px); + } + } + + .inline-editing { + textarea, + input[type='email'], + input[type='text'].fullwidth, + input[type='url'], + .link-input { + min-width: 10rem; + } + + .link-input .flex-nowrap, + .icon-picker { + flex-wrap: wrap; + } + + .money-container input[type='text'].fullwidth, + input[type='text'][inputmode].fullwidth { + min-width: 5rem; + width: 5rem; + } + + .lightswitch-outer-container .lightswitch-inner-container span { + overflow: initial; + } + + .selectize.select:not(.fullwidth) { + width: 10rem; + } + + .flex:has(input[type='text'][inputmode].fullwidth) { + flex-wrap: nowrap; + } + } + } + + .elementselectormodal & { + .source-path { + margin-block-end: 2px; + } + } + + &.pane { + overflow: auto; + + .toolbar { + position: relative; + z-index: 2; + margin-block: calc(var(--pane-padding) * -1) var(--pane-padding) !important; + margin-inline: calc(var(--pane-padding) * -1) !important; + border-radius: calc(var(--radius-lg) - 1px) calc(var(--radius-lg) - 1px) 0 + 0; + padding: var(--pane-padding); + box-shadow: 0 1px 0 var(--border-hairline); + background-color: var(--gray-050); + } + + .header { + padding-block: var(--pane-padding); + background-color: transparent; + border-block-end: 1px solid var(--border-hairline); + } + + .elements { + --border-radius: 0; + + .tableview table.data thead { + th, + td { + border-block-end: 1px solid var(--border-hairline); + + &:not(.ordered) { + background-color: transparent; + } + } + } + } + + .footer { + border-radius: 0 0 calc(var(--radius-lg) - 1px) + calc(var(--radius-lg) - 1px) !important; + box-shadow: none; + border-block-start: 1px solid var(--border-hairline); + background: transparent; + } + } + + craft-proxy-scrollbar { + position: sticky; + width: calc(100% + var(--xl) * 2); + margin-inline: calc(var(--xl) * -1); + } +} + +.elements { + position: relative; + + .update-spinner { + inset-block-start: 50%; + } + + &:not(.busy) { + .update-spinner { + display: none; + } + } + + &.busy { + min-height: 72px; + + &::after { + display: block; + content: ''; + font-size: 0; + position: absolute; + z-index: 100; + inset-block-start: 0; + inset-inline-start: calc(var(--pane-padding, 24px) * -1); + width: calc(100% + var(--pane-padding, 24px) + var(--pane-padding, 24px)); + height: 100%; + background: color.adjust(mixins.$white, $alpha: -0.25); + border-radius: var(--radius-lg); + } + } + + .header { + margin-block: calc(var(--xl) * -1 + 2px) var(--xl); + margin-inline: calc(var(--padding) * -1 + 2px); + padding: var(--s); + background-color: var(--gray-050); + box-shadow: none; + border-radius: var(--border-radius, var(--radius-sm)); + + // adjust the margin-block + @media only screen and (width <= 767px) { + margin-block: calc(var(--s) * -1 + 2px) var(--s); + } + + &::after { + content: ''; + } + + .selectallcontainer { + display: flex; + align-items: center; + gap: 5px; + cursor: default; + } + } + + .tableview tr.draggee th, + .tableview tr.draggee td, + .thumbsview li.draggee { + opacity: 0.25; + } + + // table views + + &:not(.datatablesorthelper) .tableview { + margin-block: calc(var(--pane-padding, var(--pane-y-padding-default)) * -1) + calc( + var(--pane-padding, var(--padding)) * -1 + var(--pane-padding, var(--m)) + ); + margin-inline: calc( + var(--pane-padding, var(--pane-x-padding-default)) * -1 + ); + overflow-x: auto; + + .elementselectormodal & { + margin-block: 0; + margin-inline: 0; + } + + th, + td { + height: 34px; + } + + th { + .move, + .toggle { + display: flex; + position: absolute; + justify-content: center; + align-items: center; + inset-block-start: 50%; + transform: translateY(-50%); + margin-inline-start: calc(var(--touch-target-size) * -1); + width: var(--touch-target-size); + height: var(--touch-target-size); + } + + .move { + font-size: 11px; + text-decoration: none; + } + + .toggle { + text-align: center; + padding: 4px; + border-radius: 50%; + } + + .move + .toggle { + margin-inline-start: calc(var(--touch-target-size) * -2); + } + + .enabled-label { + margin-inline-start: var(--xs); + } + } + + tr.disabled { + opacity: 1; + + & > th > div > *, + & > td { + opacity: 0.25; + } + + & > th > div > button.toggle { + opacity: 1; + pointer-events: all; + } + } + } + + // thumbs views + .thumbsview { + display: grid; + gap: var(--s); + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + + li { + position: relative; + margin-inline: 0 1px; + margin-block: 0 1px; + max-width: 226px; + border-radius: var(--radius-lg); + + &:hover { + .chip { + background-color: var(--gray-050); + } + } + + &.sel { + a { + cursor: pointer !important; + + &:hover { + text-decoration: underline; + } + } + } + } + + .chip.large { + width: 100%; + } + + .chip-content { + max-width: 100%; + } + } +} + +.export-form { + position: relative; + + .spinner { + position: absolute; + inset-block-end: 0; + inset-inline-end: -24px; + } +} + +/* structures */ +.structure { + position: relative; + z-index: 1; + + li { + padding-inline-start: 8px; + + &.collapsed > ul { + display: none; + } + + .row:hover > .icon, + &.draghelper > .row .move, + .add.active { + opacity: 1; + } + + &.draghelper { + & > .row { + .add { + opacity: 0; + } + + .move::before { + color: var(--link-color); + } + } + } + + &.draginsertion { + position: relative; + margin-inline: 8px 0; + margin-block: -1px; + padding-inline-start: 0; + height: 2px; + background-color: var(--link-color) !important; + border-inline-start: none; + border-radius: 1px; + } + + .toggle { + position: relative; + z-index: 1; + float: inline-start; + margin-inline: -12px -8px; + margin-block: 10px 0; + padding: 4px; + } + + .row::after { + @include mixins.clearafter; + } + + .move, + .add { + margin-inline: 0 5px; + margin-block: 5px 0; + opacity: 0; + transition: opacity linear 100ms; + } + + .add { + padding-block: 0; + padding-inline: 5px; + + &::before { + content: 'downangle'; + color: var(--border-hairline-dark); + } + + &:not(.disabled):hover::before, + &.active::before { + color: var(--link-color); + } + } + + .checkbox { + float: inline-start; + margin-inline: 7px 0; + margin-block: 7px 0; + } + } + + ul { + margin-inline-start: -3px; + + li { + padding-inline-start: 38px; + background-repeat: no-repeat; + + --background-position-x: 0; + --background-position-y: -6px; + background-position: var(--background-position-x) + var(--background-position-y); + + body.ltr & { + background-image: url('../images/branch.png'); + } + + body.rtl & { + --background-position-x: 100%; + background-image: url('../images/branch_rtl.png'); + } + + &:not(:last-child, .last) { + padding-inline-start: 37px; + border-inline-start: 1px solid var(--gray-200); + + body.ltr & { + --background-position-x: -1px; + } + + body.rtl & { + --background-position-x: calc(100% + 1px); + } + } + + &.draginsertion { + margin-inline-start: 38px; + } + } + } + + .row { + &.draghover { + .chip { + z-index: 2; + border-radius: 15px; + box-shadow: inset 0 0 0 2px var(--link-color); + } + } + + &.droptarget { + border-radius: 5px; + box-shadow: inset 0 0 0 2px var(--link-color); + } + } +} + +.elementselect .elements:not(:empty), +.componentselect .components:not(:empty) { + & + .flex { + margin-block-start: var(--s); + } +} + +// Each chip's `` box is `inline-flex`, so in a block list item it +// lays out in a line box and picks up baseline leading — and the flex baseline +// shifts with the prefix, so a chip with no icon/status renders ~11px taller +// than one with. Making the `li` a flex container blockifies the chip (no line +// box, no baseline), keeping every chip the same height. +.componentselect .chips > li { + display: flex; +} + +/* element select fields */ +.elementselect { + display: block; + position: relative; + min-height: 34px; + + .flex, + .btn { + clear: both; + } + + .structure { + .chip { + margin-block-start: var(--xs); + } + + & > li { + padding-inline-start: 0; + } + + ul { + margin-inline-start: 14px; + + li { + --background-position-y: 0; + } + } + } +} + +.elementselect__search-input-wrapper, +.tagselect__input-wrapper { + position: relative; + z-index: 1; + width: 12em; + + .text { + padding-inline-end: 30px !important; + } + + .spinner { + position: absolute; + inset-block-start: 0; + inset-inline-end: 5px; + } + + &.icon.add::before { + content: none; + } + + svg { + width: calc(14rem / 16); + height: calc(14rem / 16); + fill: var(--ui-control-color); + } +} + +/* nested element cards */ +.nested-element-cards { + display: flex; + flex-direction: column; + gap: var(--s); + + & > .pane { + margin: 0; + } +} + +/* editable tables */ +table.editable { + border-radius: var(--radius-lg); + border: var(--input-border); + color: var(--text-color); + + th, + td.heading, + td.action { + color: var(--fg-subtle); + font-weight: normal; + + button:not(.lightswitch), + a { + display: inline-flex; + width: var(--touch-target-size); + height: var(--touch-target-size); + align-items: center; + justify-content: center; + } + + .flex { + gap: 0; + } + } + + td.action { + padding-inline: var(--xs) !important; + vertical-align: middle; + + &:has(+ td.action) { + padding-inline-end: 0 !important; + } + + & + td.action { + padding-inline-start: 0 !important; + } + } + + thead, + tbody { + tr { + th { + padding-block: 6px; + padding-inline: 10px; + } + } + } + + thead:first-child, + tbody:first-child, + colgroup + thead, + colgroup + tbody { + tr:first-child { + th, + td { + &:first-child { + border-start-start-radius: var(--radius-lg); + + textarea, + input.text { + border-start-start-radius: calc(var(--radius-lg) - 1px); + } + } + + &:last-child { + border-start-end-radius: var(--radius-lg); + + textarea, + input.text { + border-start-end-radius: calc(var(--radius-lg) - 1px); + } + } + } + } + } + + thead, + tbody { + &:last-child tr:last-child { + th, + td { + &:first-child { + border-end-start-radius: var(--radius-lg); + + textarea, + input.text { + border-end-start-radius: calc(var(--radius-lg) - 1px); + } + } + + &:last-child { + border-end-end-radius: var(--radius-lg); + + textarea, + input.text { + border-end-end-radius: calc(var(--radius-lg) - 1px); + } + } + } + } + } + + thead { + tr { + th { + border-block-end: 1px solid var(--border-hairline); + font-family: inherit; // for .code + font-size: 0.8em !important; // ! for .code + font-weight: 500; + line-height: 1.4; + + &.has-info { + padding-inline-end: calc(15px + 1em); + } + + span.info { + position: absolute; + margin-inline-start: 5px; + } + } + } + } + + tbody { + tr { + &:not(:first-child) { + th, + td { + border-block-start: 1px solid var(--border-hairline); + } + } + + td:not(:first-child), + th ~ td:not(.hidden) ~ td { + border-inline-start: 1px solid var(--border-hairline); + } + + th { + font-weight: 500; + + // Set a dark border-left for the first that follows a , if there is one. + // This is a ridiculous CSS hack since there's no operator/pseudo-class that mimics jQuery's next(selector) function. + // If there was it could have been as simple as: th ??? td:not(.hidden) { dark left border } + // kudos to Mark Huot for coming up with it! + & ~ td:not(:first-child) { + border-inline-start: 1px solid #dbdddf; + } + } + + td { + vertical-align: top; + background-color: var(--input-bg); + padding-block: 4px; + padding-inline: 10px; + + &.focus { + position: relative; + box-shadow: inset 0 0 0 1px var(--border-hairline); + } + + &.textual { + padding: 0; + + .editable-table-preview { + text-align: start; + white-space: pre-wrap; + + & + textarea { + opacity: 0; + height: 0; + min-height: 0; + padding-block: 0; + } + } + + textarea { + resize: none; + } + + pre { + text-align: start; + white-space: pre-wrap; + } + } + + &.lightswitch-cell { + padding-block: 9px; + + .lightswitch { + display: block; + margin-block: 0; + margin-inline: auto; + } + } + + &.checkbox-cell { + padding-block: 10px; + + .checkbox-wrapper { + display: block; + margin-block: -2px 0; + margin-inline: auto; + width: 16px; + height: 16px; + } + } + + &.icon-cell { + padding-block: 6px; + } + + &.error { + box-shadow: inset 0 0 0 1px var(--fg-error); + } + + &.disabled { + position: relative; + opacity: 1; + + &::after { + content: ''; + font-size: 0; + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; + width: 100%; + height: 100%; + background-color: color.adjust(mixins.$grey050, $alpha: -0.25); + user-select: none; + } + } + + &.action { + padding-block: 4px; + padding-inline: 7px; + + & + td.action { + border-inline-start: none; + padding-inline-start: 0; + } + } + + .flex > * { + margin-block-end: 0; + } + } + } + + textarea, + textarea.text, + input.text, + pre, + .editable-table-preview { + display: block; + width: 100%; + border: none; + box-shadow: none; + border-radius: 0; + padding-block: 7px; + padding-inline: 10px; + line-height: 20px; + background-color: transparent; + overflow: hidden; + transition: none; + box-sizing: border-box; + } + + .color-container { + display: block; + position: relative; + + & > .color, + .color-input { + margin-block-end: 0; + } + + & > .color { + position: absolute; + inset-block-start: 10px; + inset-inline-start: 10px; + z-index: 1; + } + + .color-hex-indicator { + inset-inline-start: 32px; + } + + .color-input { + padding-inline-start: calc(32px + 1em); + } + } + + .datewrapper, + .timewrapper { + display: block; + width: calc(100% - 29px); + + .text + div[data-icon] { + inset-block-start: 6px; + inset-inline-start: 10px; + } + } + } + + &:not(.static) { + td.textual { + cursor: text; + } + } + + & + .btn.add { + display: block; + width: 100%; + } + + &:not(.hidden) + .btn.add { + border-block-start-width: 0; + border-radius: 0 0 var(--radius-md) var(--radius-md); + } +} + +.border-box, +.shadow-box { + & + .buttons { + margin-block-start: 7px; + } +} + +/* ---------------------------------------- +/* Nav +/* ---------------------------------------- */ + +ul.tree, +.tree ul { + margin-inline-start: 20px; +} + +.tree li .toggle { + margin-inline: -15px 0; + margin-block: 7px 0; +} + +/* status indicators */ +.status { + flex: 0 0 auto; + display: inline-block; + position: relative; + width: calc(12rem / 16); + height: calc(12rem / 16); + border-radius: 100%; + box-sizing: border-box; + background-clip: border-box; + + body.use-shapes & { + &.all { + rotate: 45deg; + background-image: linear-gradient(30deg, #184cef, #e5422b); + } + + &.pending { + background-color: transparent; + border-style: solid; + border-width: 0 5px 10px; + border-color: transparent transparent var(--bg-pending) transparent; + border-radius: 1px; + } + + &.all, + &.off, + &.suspended, + &.expired { + border-radius: 2px; + transform: scale(90%); + } + } +} + +.status:not(.on, .live, .active, .enabled, .all) { + &:not(.pending, .warning, .off, .suspended, .expired) { + &:not(.light, .gray, .red, .orange, .amber, .yellow) { + &:not(.lime, .green, .emerald, .teal, .cyan, .sky) { + &:not(.blue, .indigo, .violet, .purple, .fuchsia) { + &:not(.pink, .rose, .grey, .black, .disabled) { + &:not(.inactive) { + border-color: var(--ui-control-color); + } + } + } + } + } + } +} + +.status.all { + background-image: linear-gradient(60deg, #184cef, #e5422b); + background-origin: border-box; +} + +.status.on, +.status.live, +.status.active, +.status.enabled { + background-color: var(--bg-enabled); +} + +.status.red, +.bg-red, +.status.off, +.status.suspended, +.status.expired { + background-color: var(--bg-disabled); +} + +.status.warning { + background-color: var(--fg-warning); +} + +.status.orange, +.bg-orange, +.status.pending { + background-color: var(--bg-pending); +} + +.status.amber, +.bg-amber { + background-color: var(--amber-500); +} + +.status.yellow, +.bg-yellow { + background-color: var(--yellow-500); +} + +.status.lime, +.bg-lime { + background-color: var(--lime-500); +} + +.status.green, +.bg-green { + background-color: var(--green-600); +} + +.status.emerald, +.bg-emerald { + background-color: var(--emerald-500); +} + +.status.teal, +.bg-teal, +.status.turquoise, +.bg-turquoise { + background-color: var(--bg-enabled); +} + +.status.cyan, +.bg-cyan { + background-color: var(--cyan-500); +} + +.status.sky, +.bg-sky { + background-color: var(--sky-500); +} + +.status.blue, +.bg-blue { + background-color: var(--blue-600); +} + +.status.indigo, +.bg-indigo { + background-color: var(--indigo-500); +} + +.status.violet, +.bg-violet { + background-color: var(--violet-500); +} + +.status.purple, +.bg-purple { + background-color: var(--purple-500); +} + +.status.fuchsia, +.bg-fuchsia { + background-color: var(--fuchsia-500); +} + +.status.pink, +.bg-pink { + background-color: var(--pink-500); +} + +.status.rose, +.bg-rose { + background-color: var(--rose-500); +} + +.status.light { + background-color: var(--gray-100); +} + +.status.white, +.bg-white { + background-color: var(--white); +} + +.status.black, +.bg-black { + background-color: var(--gray-800); +} + +.status.gray, +.bg-gray, +.status.grey, +.bg-grey { + background-color: var(--gray-300); +} + +.status.disabled, +.status.inactive { + --outline-color: var(--gray-500); + box-shadow: inset 0 0 0 2px var(--outline-color); + + .sel & { + --outline-color: var(--gray-200); + } +} + +.status.white { + opacity: 1; +} + +$statusLabelColorShade: '900'; +$statusLabelBgShade: '500'; + +/* status labels */ +.status-label { + position: relative; + display: inline-flex; + align-items: start; + justify-content: center; + gap: var(--xs); + padding-block: var(--xs); + padding-inline: var(--xs) var(--s); + line-height: 1.1; + font-size: calc(11rem / 16); + background-color: rgb(from var(--status-label-bg-color) r g b / 15%); + border-radius: calc(11rem / 16); + font-weight: 500; + text-transform: uppercase; + + .status, + .cp-icon { + position: relative; + margin: 0; + } + + .status-label-text { + color: var(--status-label-text-color); + } + + &.red { + --status-label-text-color: var(--red-#{$statusLabelColorShade}); + --status-label-bg-color: var(--bg-disabled); + } + + &.amber { + --status-label-text-color: var(--amber-#{$statusLabelColorShade}); + --status-label-bg-color: var(--amber-#{$statusLabelBgShade}); + } + + &.orange { + --status-label-text-color: var(--orange-#{$statusLabelColorShade}); + --status-label-bg-color: var(--bg-pending); + } + + &.yellow { + --status-label-text-color: var(--yellow-#{$statusLabelColorShade}); + --status-label-bg-color: var(--yellow-#{$statusLabelBgShade}); + } + + &.lime { + --status-label-text-color: var(--lime-#{$statusLabelColorShade}); + --status-label-bg-color: var(--lime-#{$statusLabelBgShade}); + } + + &.green { + --status-label-text-color: var(--green-#{$statusLabelColorShade}); + --status-label-bg-color: var(--green-#{$statusLabelBgShade}); + } + + &.emerald { + --status-label-text-color: var(--emerald-#{$statusLabelColorShade}); + --status-label-bg-color: var(--emerald-#{$statusLabelBgShade}); + } + + &.teal, + &.turquoise { + --status-label-text-color: var(--teal-#{$statusLabelColorShade}); + --status-label-bg-color: var(--bg-enabled); + } + + &.cyan { + --status-label-text-color: var(--cyan-#{$statusLabelColorShade}); + --status-label-bg-color: var(--cyan-#{$statusLabelBgShade}); + } + + &.sky { + --status-label-text-color: var(--sky-#{$statusLabelColorShade}); + --status-label-bg-color: var(--sky-#{$statusLabelBgShade}); + } + + &.blue { + --status-label-text-color: var(--blue-#{$statusLabelColorShade}); + --status-label-bg-color: var(--blue-#{$statusLabelBgShade}); + } + + &.indigo { + --status-label-text-color: var(--indigo-#{$statusLabelColorShade}); + --status-label-bg-color: var(--indigo-#{$statusLabelBgShade}); + } + + &.violet { + --status-label-text-color: var(--violet-#{$statusLabelColorShade}); + --status-label-bg-color: var(--violet-#{$statusLabelBgShade}); + } + + &.purple { + --status-label-text-color: var(--purple-#{$statusLabelColorShade}); + --status-label-bg-color: var(--purple-#{$statusLabelBgShade}); + } + + &.fuchsia { + --status-label-text-color: var(--fuchsia-#{$statusLabelColorShade}); + --status-label-bg-color: var(--fuchsia-#{$statusLabelBgShade}); + } + + &.pink { + --status-label-text-color: var(--pink-#{$statusLabelColorShade}); + --status-label-bg-color: var(--pink-#{$statusLabelBgShade}); + } + + &.rose { + --status-label-text-color: var(--rose-#{$statusLabelColorShade}); + --status-label-bg-color: var(--rose-#{$statusLabelBgShade}); + } + + &.light { + --status-label-text-color: var(--gray-#{$statusLabelColorShade}); + --status-label-bg-color: var(--gray-#{$statusLabelBgShade}); + } + + &.gray, + &.grey { + --status-label-text-color: var(--gray-#{$statusLabelColorShade}); + --status-label-bg-color: var(--gray-#{$statusLabelBgShade}); + } + + &.black { + --status-label-text-color: var(--black); + --status-label-bg-color: var(--gray-1000); + } +} + +.card.sel, +li.sel .card, +table.data tbody tr:not(.disabled).sel, +table.data tbody tr:not(.disabled).active-drop-target { + .status-label.gray { + --status-label-bg-color: var(--white); + + &::before { + opacity: 0.075; + } + } +} + +/* colors */ +.icon, +.cp-icon, +[data-icon], +[data-icon-after] { + &.warning { + --icon-color: var(--fg-warning); + } + + &.red { + --icon-color: var(--bg-disabled); + } + + &.orange { + --icon-color: var(--bg-pending); + } + + &.amber { + --icon-color: var(--amber-500); + } + + &.yellow { + --icon-color: var(--yellow-500); + } + + &.lime { + --icon-color: var(--lime-500); + } + + &.green { + --icon-color: var(--green-500); + } + + &.emerald { + --icon-color: var(--emerald-500); + } + + &.teal { + --icon-color: var(--bg-enabled); + } + + &.cyan { + --icon-color: var(--cyan-500); + } + + &.sky { + --icon-color: var(--sky-500); + } + + &.blue { + --icon-color: var(--blue-600); + } + + &.indigo { + --icon-color: var(--indigo-500); + } + + &.violet { + --icon-color: var(--violet-500); + } + + &.purple { + --icon-color: var(--purple-500); + } + + &.fuchsia { + --icon-color: var(--fuchsia-500); + } + + &.pink { + --icon-color: var(--pink-500); + } + + &.rose { + --icon-color: var(--rose-500); + } + + &.white { + --icon-color: var(--white); + } + + &.black { + --icon-color: var(--gray-800); + } + + &.gray { + --icon-color: var(--gray-300); + } +} + +.warning, +.red, +.orange, +.amber, +.yellow, +.lime, +.green, +.emerald, +.teal, +.cyan, +.sky, +.blue, +.indigo, +.violet, +.purple, +.fuchsia, +.pink, +.rose, +.white, +.black, +.gray { + &[data-icon]::before, + &[data-icon-after]::after { + color: var(--icon-color) !important; + } +} + +/* ---------------------------------------- +/* Progress bar +/* ---------------------------------------- */ + +.progressbar { + border-radius: 6px; + border: 2px solid var(--gray-700); + padding: 2px; + position: absolute; + inset-inline-start: 20%; + width: 60%; + z-index: 1000; +} + +.progressbar-inner { + border-radius: 2px; + height: 4px; + background-color: var(--gray-700); +} + +.progressbar:not(.pending) .progressbar-inner { + width: 0; + transition: width linear 100ms; +} + +.progressbar.pending .progressbar-inner { + @include striped-bg(17.6777px, var(--gray-700)); // sqrt(25^2 / 2); + body.ltr & { + animation-name: pendingprogress-ltr; + } + + body.rtl & { + animation-name: pendingprogress-rtl; + } + + animation-timing-function: linear; + animation-duration: 250ms; + animation-iteration-count: infinite; +} + +@keyframes pendingprogress-ltr { + from { + background-position: 0; + } + + to { + background-position: 25px; + } +} + +@keyframes pendingprogress-rtl { + from { + background-position: 0; + } + + to { + background-position: -25px; + } +} + +.elementselect .progress-shade { + background-color: color.adjust(mixins.$white, $alpha: -0.2); + width: 100%; + height: 100%; + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; + display: none; +} + +.elementselect.uploading { + position: relative; +} + +.elementselect.uploading .progress-shade { + display: block; + z-index: 2; +} + +/* ---------------------------------------- +/* Panes, Modals and HUDs +/* ---------------------------------------- */ + +.pane { + @include mixins.pane; + position: relative; + margin-block: 14px; + margin-inline: 0; + padding: var(--pane-padding); + border: var(--pane-border); + border-radius: var(--pane-border-radius); + overflow-wrap: break-word; + box-sizing: border-box; + + &.secondary { + border: var(--secondary-pane-border); + border-radius: var(--secondary-pane-border-radius); + background: var(--secondary-pane-bg); + box-shadow: var(--secondary-pane-shadow); + } + + .pane &, + .slideout &, + #content &, + .lp-content & { + border: 1px solid var(--border-hairline); + background: var(--secondary-pane-bg); + box-shadow: none; + } + + &.dashed { + background-color: transparent !important; + box-shadow: none; + border: 1px dashed var(--border-hairline-medium) !important; + } + + &.hairline, + &:is(fieldset) { + background-color: transparent !important; + box-shadow: none; + border: 1px solid #{color.adjust(mixins.$inputColor, $alpha: -0.75)} !important; + } + + &.no-border, + &.chromeless { + border: none !important; + } + + &.chromeless { + background-color: transparent !important; + box-shadow: none; + } + + &.tip, + &.warning { + padding-inline-start: 50px; + + &::before { + @include mixins.icon; + opacity: 1; + position: absolute; + inset-block-start: var(--pane-padding); + inset-inline-start: 18px; + font-size: 18px; + width: 24px; + } + + &.dismissible { + padding-inline-end: 48px; + } + + .tip-dismiss-btn { + position: absolute; + inset-block-start: 23px; + inset-inline-end: 18px; + + & + p { + margin-block-start: 0; + } + } + } + + &.tip { + border-color: var(--sky-600) !important; + background-color: var(--sky-050) !important; + color: var(--fg-notice); + + &::before { + content: 'lightbulb'; + color: var(--fg-notice); + } + } + + &.warning { + border-color: var(--amber-600) !important; + background-color: var(--amber-050) !important; + color: var(--fg-warning); + + &::before { + content: 'alert'; + color: var(--fg-warning); + } + } + + &.padding-xs { + --pane-padding: var(--xs); + } + + &.padding-s { + --pane-padding: var(--s); + } + + &.padding-m { + --pane-padding: var(--m); + } + + &.padding-l { + --pane-padding: var(--l); + } + + &.loading { + min-height: 200px; + + &::after { + display: block; + content: ''; + font-size: 0; + position: absolute; + inset-block-start: 0; + inset-inline-start: -24px; + width: calc(100% + #{24 + 24}px); + height: 100%; + } + } + + &:is(fieldset) > legend { + font-weight: 600; + color: var(--light-text-color); + } + + hr { + margin-block: var(--pane-padding); + margin-inline: calc(var(--pane-padding) * -1); + } +} + +.pane-header { + margin-block: var(--neg-padding) var(--padding); + margin-inline: var(--neg-padding); + padding-block: 5px 6px; + padding-inline: var(--padding); + min-height: 45px; + box-sizing: border-box; + box-shadow: inset 0 -1px 0 0 color.adjust(mixins.$grey300, $alpha: -0.75); + border-radius: var(--radius-lg) var(--radius-lg) 0 0; + background-color: var(--gray-050); + + .spinner { + margin: 0 !important; + } +} + +.pane-tabs { + display: flex; + flex-direction: row; + align-items: center; + margin-block: -5px -6px; + margin-inline: calc(var(--padding) * -1); + + &:first-child { + border-radius: var(--radius-lg) var(--radius-lg) 0 0; + overflow: hidden; + } + + [role='tablist'] { + flex: 1; + display: flex; + flex-direction: row; + overflow-x: auto; + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } + + &.scrollable { + body.ltr & { + mask-image: linear-gradient( + to left, + rgb(0 0 0 / 0%), + rgb(0 0 0 / 100%) 24px + ); + } + + body.rtl & { + mask-image: linear-gradient( + to right, + rgb(0 0 0 / 0%), + rgb(0 0 0 / 100%) 24px + ); + } + } + + [role='tab'] { + --tab-label-color: var(--light-text-color); + + &.error { + --highlight-color: var(--fg-error) !important; + --tab-label-color: var(--fg-error) !important; + } + + &, + .tab-label { + border-radius: 2px 2px 0 0; + } + + .tab-label { + display: flex; + flex-direction: row; + align-items: center; + position: relative; + padding-block: 0; + padding-inline: var(--padding); + white-space: nowrap; + height: 45px; + } + + &:hover { + text-decoration: none; + } + + &:focus-visible { + .tab-label { + box-shadow: var(--focus-ring-inner); + } + } + + &:not(.sel) { + color: var(--custom-text-color, var(--tab-label-color)); + + &:hover { + backdrop-filter: brightness(95%); + } + } + + &.sel { + --highlight-color: var(--gray-500); + --tab-label-color: var(--text-color); + position: relative; + z-index: 1; + cursor: default; + box-shadow: + inset 0 2px 0 var(--custom-text-color, var(--highlight-color)), + 0 0 0 1px mixins.$hairlineColor, + 0 2px 12px var(--custom-sel-tab-shadow-color, var(--gray-200)); + color: var(--tab-label-color); + background-color: var(--white) !important; + } + + span[data-icon] { + margin-inline-start: 4px; + } + } + } + + &#tabs:first-child { + [role='tablist'] { + [role='tab'] { + &:first-child { + &, + .tab-label { + border-start-start-radius: var(--radius-lg); + } + } + } + } + } + + .menubtn { + margin-block: 0; + margin-inline: var(--xl); + + &.error { + span[data-icon] { + margin-inline-end: 2px; + } + } + } +} + +/* detail sidebars */ +.details { + --spacing: var(--l); + padding-block: 0 var(--spacing); + padding-inline: var(--padding); + + .meta, + .field, + hr { + margin-inline: var(--neg-padding); + } + + .meta { + margin-block-end: var(--spacing); + + &:not(.read-only) { + background-color: var(--gray-050) !important; + } + + &.read-only { + color: var(--fg-subtle); + + & > .data { + min-height: auto; + + & > .heading, + & > .value { + padding-block: 6px; + } + + &:first-child { + & > .heading, + & > .value { + padding-block-start: 0; + } + } + + &:last-child { + & > .heading, + & > .value { + padding-block-end: 0; + } + } + } + } + + &.warning { + padding-block: var(--m); + color: var(--text-color) !important; + background-color: var(--yellow-050) !important; + box-shadow: + 0 0 0 1px var(--yellow-300), + 0 2px 12px color.adjust(mixins.$grey200, $alpha: -0.5); + + p { + margin-block-end: 5px; + } + + .btn { + background-color: var(--yellow-300); + + &:hover, + &:focus { + background-color: color.adjust(mixins.$yellow300, $lightness: -10%); + } + + &:active, + &[aria-expanded='true'] { + background-color: color.adjust(mixins.$yellow300, $lightness: -15%); + } + } + } + + & > .field, + & > .data { + margin-block: 0 !important; + margin-inline: var(--neg-padding) !important; + + & > .heading > label, + & > .heading { + color: var(--gray-600); + } + } + + & > .field > .status-badge { + inset-inline-start: 0; + } + + .text::placeholder, + .datewrapper .text + div[data-icon], + .timewrapper .text + div[data-icon] { + color: var(--gray-500); + } + + .ui-datepicker { + margin-inline: -8px 0; + margin-block: 0; + } + } + + hr { + margin-block: var(--spacing); + margin-inline: 0; + border-block-start-color: var(--border-hairline); + } + + @include mixins.placeholder-styles(var(--gray-500)); + + .text { + background-color: transparent !important; + resize: none; + } + + .data { + overflow-wrap: break-word; + } + + & > .field .heading, + & > fieldset > legend { + margin-block: 0 var(--s); + margin-inline: 0; + } + + & > .field > .heading > label, + & > fieldset > legend { + font-weight: normal; + color: var(--gray-600); + } + + & > .field > .heading > label { + margin: 0; + } + + & > .field { + margin-block: 0 var(--spacing); + margin-inline: 0; + + & > .heading { + margin-block-start: 0; + } + + & > .input > .text.fullwidth { + margin-block: 0; + margin-inline: var(--neg-padding); + padding-inline: var(--m); + border: none; + background-color: var(--gray-050) !important; + width: calc(100% + var(--padding) + var(--padding)); + } + } + + /* + When there's no .meta container (which can occur when editing a matrix block) + make sure the sidebar aligns with the top of the content area. + */ + & > fieldset:not(:first-child) { + margin-block: var(--spacing) !important; + margin-inline: 0 !important; + } + + & > .text { + border-radius: var(--radius-lg); + margin-block-end: var(--spacing); + + &:not(:focus) { + border-color: color.adjust(mixins.$inputColor, $alpha: -0.6); + } + } +} + +/* meta panes */ +$min2ColWidth: 400px; + +.meta { + padding-block: 0; + padding-inline: var(--padding); + overflow: visible; + + --heading-width: 150px; + + #details & { + --heading-width: 132px; + } + + &, + & > .flex-fields { + & > .field, + & > .data { + display: flex; + min-height: 44px; + box-sizing: border-box; + flex-wrap: wrap; // for error lists + justify-content: space-between; + align-items: stretch; + margin-block: 0 !important; + margin-inline: var(--neg-padding) !important; + padding-block: 0; + transition: + padding-inline-start linear 100ms, + padding-inline-end linear 100ms; + + &.nested { + padding-inline-start: 38px; + + & > .heading { + padding-inline-start: 10px; + } + } + + &.add { + &::before { + position: absolute; + inset-block-start: var(--m); + inset-inline-start: 0; + width: 48px; + text-align: end; + @include mixins.icon; + content: 'plus' / ''; + color: var(--light-text-color); + } + + .input { + width: 100%; + } + } + + & > .heading { + margin: 0; + + @media screen and (min-width: $min2ColWidth) { + flex: 0 0 var(--heading-width); + line-height: 18px; + } + } + + #details &, + .so-sidebar.details & { + &.lightswitch-field > .heading { + flex: 1; + border-inline-end: none; + } + } + + & > .input { + display: flex; + align-items: center; + + .flex { + flex-wrap: nowrap; + + & > * { + margin-block-end: 0; + } + } + } + } + + & > .field > .heading { + @media screen and (width < $min2ColWidth) { + padding-block-start: var(--xs); + padding-inline: 10px; + } + + @media screen and (min-width: $min2ColWidth) { + padding-block: 12px; + padding-inline: var(--m) var(--s); + border-inline-end: 1px solid var(--border-hairline); + } + + & > .copytextbtn { + display: none; + } + } + + & > .data > .heading { + padding-block: var(--s); + padding-inline: var(--m) 0; + } + + & > .field > .heading > label, + & > .data > .heading { + color: var(--fg-subtle); + } + + & > .field > .input, + & > .data > .value { + padding-block: var(--s); + width: 100%; + + @media screen and (width < $min2ColWidth) { + padding-inline: 10px; + } + + @media screen and (min-width: $min2ColWidth) { + width: calc(100% - var(--heading-width)); + padding-inline: var(--s) var(--m); + } + + // Fixes https://github.com/craftcms/cms/issues/16473 + // h/t https://stackoverflow.com/a/66689926/1688568 + > * { + min-width: 0; + } + } + + & > .data > .value { + display: flex; + align-items: center; + width: calc(100% - (var(--heading-width) + 6px)); + + & > [data-icon='draft'] { + margin-block-start: -2px; + margin-inline-end: 8px; + } + } + + & > .field.lightswitch-field > .input { + padding-inline: 10px; + + #details &, + .so-sidebar.details & { + flex: 0; + width: auto; + } + } + + & > .field { + &.has-errors { + border: 1px solid var(--fg-error) !important; + + &:first-child { + border-start-start-radius: var(--radius-lg); + border-start-end-radius: var(--radius-lg); + } + + &:last-child { + border-end-start-radius: var(--radius-lg); + border-end-end-radius: var(--radius-lg); + } + + & + .field { + border-block-start: none !important; + } + } + + & > .heading { + & > label, + & > legend { + font-weight: normal; + } + } + + & > .input { + &, + & > .flex, + & > .flex > .textwrapper, + & > .datewrapper, + & > .timewrapper, + & > .datetimewrapper > .datewrapper, + & > .datetimewrapper > .timewrapper { + & > .text { + display: block; + margin-block: calc(var(--s) * -1); + padding-block: 12px; + border-radius: 0; + background-color: transparent; + border: none !important; + + @media screen and (width < $min2ColWidth) { + margin-inline: -10px; + padding-inline: 10px; + } + + @media screen and (min-width: $min2ColWidth) { + margin-inline: calc(var(--s) * -1) 0; + padding-inline-start: var(--s); + } + + &:placeholder-shown + div[data-icon] { + inset-inline-start: 1px; + } + } + } + + & > .datetimewrapper { + width: calc(100% - 3px); + } + + & > .datewrapper, + & > .timewrapper, + & > .datetimewrapper > .datewrapper, + & > .datetimewrapper > .timewrapper { + background-color: transparent; + } + + & > .datetimewrapper { + gap: 0; + + & > .datewrapper { + width: 55%; + } + + & > .timewrapper { + width: 45%; + } + } + + & > .datewrapper, + & > .timewrapper { + display: block; + width: 100%; + } + } + + & > ul.errors { + margin: 0; + padding-block: 0 6px; + padding-inline: 10px; + width: 100%; + list-style-type: none; + + @media screen and (min-width: $min2ColWidth) { + padding-inline: var(--m); + } + } + + & > .clear-btn { + margin-inline-end: var(--neg-padding); + } + } + } + + & > .field:not(:first-child, .first-child), + & > .flex-fields + .field:not(.first-child) { + border-block-start: 1px solid var(--border-hairline); + } + + & > .flex-fields { + h2, + blockquote.note { + margin-block: 0 !important; + margin-inline: -24px !important; + padding-block: 14px; + padding-inline: 24px; + background-color: color.adjust(mixins.$grey050, $lightness: -2%); + } + + blockquote.note { + border-radius: 0; + border: none; + } + + hr { + margin-block: 0; + margin-inline: -24px; + } + } +} + +.meta > .field > .input > .select { + display: block; + margin-block: calc(var(--s) * -1); + margin-inline: 0; + width: 100%; + border-radius: 0; + box-shadow: none; + background-color: transparent; + + & + .spinner { + position: absolute; + inset-block-start: calc(50% - 17px); + inset-inline-end: -24px; + } + + select { + padding-inline: 0 12px; + padding-block: var(--s); + width: 100%; + background-color: transparent; + } +} + +.meta > .field > .input > .custom-select { + display: block; + margin-block: calc(var(--s) * -1); + margin-inline: 0; + width: 100%; + border-radius: 0; + box-shadow: none; + background-color: transparent; + + .menubtn:not(.action-btn) { + justify-content: flex-start; + width: 100%; + background-color: transparent; + overflow: hidden; + + // button padding + icon size + inset-inline-end + padding-inline-end: calc(var(--button-padding) + calc(7rem / 16) + 11px); + + &::after { + position: absolute; + inset-block-start: calc(50% - 5px); + inset-inline-end: 11px; + } + + .inline-flex { + overflow: hidden; + } + } + + .label { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + } +} + +.body { + position: relative; +} + +/* inline asset previews */ + +.preview-thumb-container { + position: relative; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + height: 190px; + background-color: var(--gray-900); + margin-block: 0 var(--spacing); + margin-inline: var(--neg-padding); + + &.checkered img { + background-color: var(--white); + @include mixins.checkered-bg(17px); + } + + &.editable { + cursor: pointer; + } + + &.loading { + &::after { + content: ''; + font-size: 0; + display: block; + position: absolute; + width: 100%; + height: 100%; + inset-inline-start: 0; + inset-block-start: 0; + background-color: color.adjust(mixins.$grey900, $alpha: -0.2); + } + + .spinner { + color: var(--white); + z-index: 1; + } + } + + #details & { + border-radius: var(--radius-lg); + overflow: hidden; + } + + .preview-thumb { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + + img { + display: block; + max-width: 100%; + max-height: 190px; + } + } +} + +.image-actions { + &.is-mobile { + margin-block: calc((var(--spacing) / 2) * -1) var(--spacing); + margin-inline: var(--neg-padding); + display: grid; + grid-template-columns: 1fr 1fr; + } +} + +.button-fade { + .buttons { + opacity: 0; + position: absolute; + inset-block-start: 10px; + inset-inline-end: 10px; + margin: 0; + transition: opacity linear 100ms; + + .btn { + --ui-control-color: var(--white); + --ui-control-hover-color: var(--white); + --ui-control-active-color: var(--white); + --interaction-background-color: var(--gray-700); + background-color: var(--gray-600); + color: var(--white); + @include mixins.light-on-dark-text; + @include mixins.two-color-focus-ring($light-button: false); + + &:hover { + background-color: var(--interaction-background-color) !important; + } + + &:not(.disabled, .loading, .dashed) { + &:focus, + &.focus, + &:hover { + background-color: var(--interaction-background-color); + } + } + } + } + + &:hover, + &:focus-within { + .buttons { + opacity: 1; + } + } +} + +/* element selector modals */ +.elementselectormodal { + --content-padding: 24px; + padding-block-end: 44px; + user-select: none; + + & > .header { + padding-block: 14px; + text-align: center; + + & + .body { + height: calc(100% - 48px) !important; + } + } + + .body { + position: relative; + height: 100%; + + .spinner.big { + position: absolute; + inset-block-start: 50%; + inset-inline-start: 50%; + margin-block: -24px 0; + margin-inline: -24px 0; + } + + .content { + height: calc(100% + 48px); + + .sidebar { + position: absolute; + inset-block-start: 0; + margin-inline-start: calc(-249rem / 16); + height: 100%; + overflow: auto; + padding-block: var(--content-padding); + padding-inline: 0; + } + + .main { + margin: -24px; + padding: var(--content-padding); + height: 100%; + box-sizing: border-box; + overflow: auto; + position: relative; + + .elements { + &.busy { + min-height: calc(100% - 48px); + + .update-spinner { + z-index: 101; + } + } + + .header { + margin-block: 0 var(--m); + margin-inline: 0; + } + + .tableview table { + tr { + th, + td { + cursor: default; + } + + // prevent double focus ring (the row already gets it) + .checkbox::before { + box-shadow: none !important; + } + } + } + + .structure .row { + margin-block-start: 1px; + } + } + } + } + } + + .footer { + position: absolute; + inset-block-end: 0; + inset-inline-start: 0; + width: 100%; + margin: 0; + box-sizing: border-box; + + .spinner { + float: inline-end; + margin-inline-end: -24px; + } + } +} + +/* element selector modals (the matching .cs-modal rules live in _customize-sources.scss) */ +.elementselectormodal { + .main-header { + display: flex; + align-items: center; + margin-block-end: var(--s); + } + + .main-heading { + margin-block-end: 0; + } + + .nav-toggle { + margin-inline-start: 4px; + @include mixins.touch-target; + color: var(--ui-control-color); + + &:hover { + color: var(--gray-500); + } + } + + .sidebar-header { + display: flex; + justify-content: flex-end; + padding-block: 0; + padding-inline: var(--s); + margin-block-end: var(--s); + } + + .nav-close { + @include mixins.touch-target; + } +} + +/* element editing HUD */ +.element-hud-form { + .buttons { + position: relative; + + .spinner { + position: absolute; + inset-block-start: 0; + inset-inline-end: -24px; + } + } +} + +/* recent activity container */ +.activity-container { + margin-inline: var(--s); + + ul { + display: flex; + flex-flow: row wrap; + gap: var(--xs); + + li { + .activity-btn { + width: 30px; + height: 30px; + border-radius: 50%; + display: block; + + .elementthumb { + position: relative; + width: 100%; + height: 100%; + border-radius: 50px; + background: var(--gray-050); + overflow: hidden; + border: 2px solid var(--white); + box-shadow: 0 1px 2px 1px color.adjust(mixins.$grey900, $alpha: -0.9); + + img, + svg { + display: block; + width: 100%; + height: 100%; + } + } + } + + &:not(:last-child) { + margin-inline-end: -10px; + } + } + } +} + +/* element index view menu */ +.element-index-view-menu { + width: 400px; + max-width: calc(100% - 20px); + padding: 0 !important; + + .meta { + padding-block: var(--s); + } + + .table-columns-field .heading { + align-items: flex-start; + } + + .menu-footer { + margin: 0 !important; + padding-block: var(--s) !important; + padding-inline: var(--xl) !important; + background-color: var(--gray-050); + } +} + +.element-index-view-menu-table-column { + display: flex; + align-items: flex-start; + align-content: stretch; + margin-block-end: 4px; + + .icon.move { + margin-inline-end: 10px; + position: relative; + z-index: 1; + } +} + +/* sort fields */ +.sort-field { + .input { + .flex { + .btngroup { + .btn { + width: 42px; + } + } + + .flex-grow { + max-width: calc(100% - 85px - var(--s)); + } + + @media screen and (width <= 350px) { + flex-direction: column; + + & > * { + width: 100%; + } + + .flex-grow { + max-width: none; + } + } + } + } +} + +/* element filter HUD */ +.element-filter-hud { + &.loading .body { + padding: 44px; + display: flex; + align-items: center; + justify-content: center; + } + + .body, + .main { + overflow: visible; + } +} + +/* Address Cards */ +.address-cards { + display: grid; + gap: var(--m) var(--m); + grid-template-columns: repeat(1, minmax(0, 1fr)); + grid-auto-rows: minmax(0, 1fr); + + .so-content & { + grid-template-columns: repeat(1, minmax(0, 1fr)) !important; + } +} + +.address-cards__add-btn { + padding: 1rem; + min-height: 8rem; + height: auto; + width: 100%; +} + +.address-card.error { + border: 1px solid #cf1124; +} + +.address-card.error:hover { + border-color: #cf1124; +} + +@media (width >= 1024px) { + .address-cards { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (width >= 1280px) { + .address-cards { + grid-template-columns: repeat(3, minmax(0, 1fr)); + + .so-content & { + grid-template-columns: repeat(2, minmax(0, 1fr)) !important; + } + } +} + +@media (width >= 1536px) { + .address-cards { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } +} + +.address-card { + border: 1px solid #eee; + border-radius: 0.375rem; + padding: 1rem; + min-height: 4rem; +} + +.address-card:hover { + border-color: #ddd; + background-color: #fafafa; + cursor: pointer; +} + +.address-card .address-card-header { + display: flex; + flex-wrap: nowrap; + justify-content: space-between; +} + +.address-card .address-card-header-actions { + display: flex; + justify-content: flex-end; +} + +.address-card .address-card-label { + background: #e6f1fe; + color: #2563eb; + padding-block: 0.125rem; + padding-inline: 0.5rem; + border-radius: 0.25rem; + font-size: 0.75rem; + text-transform: uppercase; + font-weight: 500; + margin-block-end: 0.75rem; + margin-inline-end: 0.5rem; +} + +/* logout warning/login/elevated session modals */ +.logoutwarningmodalshade, +.login-modal-shade, +#logoutwarningmodal, +.login-modal, +#elevatedsessionmodal, +.prompt { + z-index: 1001; +} + +#logoutwarningmodal, +#elevatedsessionmodal, +.prompt { + width: 500px; +} + +.prompt { + height: auto; + min-height: auto; +} + +.cpmodal { + & > .cpmodal-body { + padding: var(--padding); + } + + & > .cpmodal-footer { + position: relative; + display: flex; + gap: 8px; + justify-content: space-between; + flex-wrap: wrap; + @include mixins.pane; + padding-block: var(--s); + padding-inline: var(--padding); + background-color: var(--gray-050); + } +} + +/* element deletion modal */ +.element-deletion-modal { + width: 500px; + display: flex; + flex-direction: column; + + .body { + flex: 1; + height: calc(100% - 44px); + overflow: auto; + + .edm-blockers { + margin-inline: calc(var(--pane-padding) * -1); + border-block-start: var(--hr-border); + + .edm-blocker { + padding: var(--pane-padding); + + &:nth-child(odd) { + background-color: var(--secondary-pane-bg); + } + } + + .edm-details { + .element-index { + border-color: var(--border-hairline-dark) !important; + background-color: var(--white) !important; + max-height: 272px; + } + } + + .edm-blocker-resolved-message { + margin-block-start: var(--s); + } + } + } +} + +/* delete user modal */ +.deleteusermodal { + .content-summary { + margin-block: -24px 24px; + margin-inline: -24px; + padding: 24px; + background-color: var(--gray-050); + } + + .options { + label { + display: inline-block; + line-height: 30px; + } + } + + .elementselect { + margin-inline-start: 10px; + display: inline-block; + vertical-align: middle; + } + + .buttons { + .spinner { + margin-inline-end: -20px; + } + } + + div.elements { + list-style: none; + } +} + +.dropdownsettingsmodal { + width: auto; + height: auto; + min-width: 0; + min-height: 0; + max-width: 400px; + + .body { + max-height: 100%; + overflow-y: auto; + } +} + +.previewmodal { + &.zilch { + padding-block: 100px; + padding-inline: 0; + display: flex; + align-items: center; + justify-content: center; + } +} + +/* ---------------------------------------- +/* Alternative Text +/* ---------------------------------------- */ +.video-transcript { + background-color: var(--gray-050); + overflow-y: scroll; + font-size: 1rem; + position: relative; + + &:focus-visible { + box-shadow: none; + color: var(--white); + background-color: var(--gray-800); + } +} + +.video-transcript__inner { + margin-inline: auto; + max-width: 550px; + padding: var(--xl); +} + +/* tag select fields */ +.tagselect { + .elements { + li { + display: inline; + } + } + + .chip.small { + clear: none; + margin-inline-end: 7px; + } + + .tagselect__input-wrapper { + margin-inline: 0 7px; + margin-block: 7px 0; + display: inline-block; + } +} + +.tagmenu { + ul { + li { + a { + padding-inline-start: 26px; + + &::before { + float: inline-start; + margin-inline: -18px 0; + margin-block: 3px 0; + } + } + } + } +} + +/* selectize */ +.selectize-control.single .selectize-input:not(.no-arrow)::after { + display: none; +} + +/* ---------------------------------------- +/* Fields +/* ---------------------------------------- */ + +.shadow-box { + border-radius: var(--radius-lg); + border: 1px solid var(--gray-200); + @include mixins.shadow; +} + +table.shadow-box, +table.editable { + border-collapse: separate; + border-spacing: 0; + + thead, + tbody:first-child, + caption + tbody { + tr:first-child { + th:first-child, + td:first-child { + &, + &.disabled::after { + border-start-start-radius: var(--radius-md); + } + } + + th:last-child, + td:last-child { + &, + &.disabled::after { + border-start-end-radius: var(--radius-md); + } + } + } + } + + thead:last-child, + tbody:last-child { + tr:last-child { + th:first-child, + td:first-child { + &, + &.disabled::after { + border-end-start-radius: calc(var(--radius-lg) - 1px); + } + } + + th:last-child, + td:last-child { + &, + &.disabled::after { + border-end-end-radius: calc(var(--radius-lg) - 1px); + } + } + } + } +} + +.selectize.multiselect .selectize-input { + line-height: 18px; +} + +.multitext .multitextrow { + &::after { + @include mixins.clearafter; + } + + &:first-child .text { + &:first-child { + border-start-start-radius: var(--radius-md); + } + + &:last-child { + border-start-end-radius: var(--radius-md); + } + } + + &:last-child .text { + &:first-child { + border-end-start-radius: var(--radius-md); + } + + &:last-child { + border-end-end-radius: var(--radius-md); + } + } + + &:not(:first-child) .text { + margin-block-start: -1px; + } + + .text { + border-radius: 0; + float: inline-start; + box-sizing: border-box; + + &:not(:first-child) { + margin-inline-start: -1px; + } + + &:first-child { + &:nth-last-child(1) { + width: 100%; + } + + &:nth-last-child(2) { + width: 50%; + } + + &:nth-last-child(2) ~ .text { + width: calc(50% + 1px); + } + } + + &.error { + position: relative; + z-index: 1; + } + } + + .text:focus, + .selectize.multiselect .selectize-input.focus { + position: relative; + z-index: 2; + } +} + +.CodeMirror { + height: auto !important; + min-height: 70px; + + &.CodeMirror-focused { + @include mixins.input-focused-styles; + } + + &.cm-s-readonly { + &, + * { + cursor: not-allowed; + } + } +} + +.json-field .CodeMirror-scroll { + max-height: 550px; +} + +.link-input { + container-type: inline-size; + + & > .flex { + & > .flex-grow { + overflow: hidden; + } + + & > div { + &.text-link { + border: var(--input-border); + border-radius: var(--radius-lg); + background-color: var(--input-bg); + cursor: text; + + &:has(.text:focus) { + box-shadow: var(--focus-ring); + } + + & > .text, + & > .chip { + margin-block: -1px; + background-color: transparent; + } + + & > .text { + border: none; + margin-inline: -1px; + + &:focus { + position: relative; + } + + &:focus { + box-shadow: none !important; + } + } + + .chip { + min-height: calc(34rem / 16); + padding-inline: var(--s); + } + } + } + + @container (max-width: calc(399rem/16)) { + /* stylelint-disable block-no-redundant-nested-style-rules */ + & { + flex-direction: column; + align-items: stretch; + + & > .select, + & > .select select, + & > div[data-link-type] .text, + & > div[data-link-type] .chip { + display: flex; + width: 100%; + } + + & > div[data-link-type] ul.elements { + align-items: stretch; + } + } + /* stylelint-enable */ + } + } +} + +.chars-left { + position: relative; + float: inline-end; + margin-inline: 7px; + margin-block: calc(-27rem / 16) 0; + color: var(--light-text-color); + + .input.ltr > & { + float: inline-end; + } + + .input.rtl > & { + float: inline-start; + } + + &.negative-chars-left { + color: var(--fg-error); + } +} + +.status-badge { + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; + width: 2px; + height: 100%; + content: ''; + cursor: help; + z-index: 1; + + &.modified { + background-color: var(--blue-600); + box-shadow: 0 0 5px hsl(221deg 83% 53% / 15%); + } + + &.outdated { + background-color: var(--bg-pending); + box-shadow: 0 0 5px hsl(27deg 96% 61% / 15%); + } +} + +.field { + min-inline-size: initial; + + & > .status-badge { + border-radius: 1px; + } + + & > .heading { + display: flex; + flex-wrap: wrap; + gap: 5px; + align-items: center; + position: relative; + margin-block: -5px 5px; + min-height: calc(22rem / 16); + + & > label, + & > legend { + display: flex; + flex-wrap: wrap; + gap: 5px; + align-items: center; + font-weight: bold; + + code { + font-size: 1em !important; + } + + .info { + margin-inline-start: 5px; + } + } + + .required::after { + margin-inline-start: 0; + } + + .t9n-indicator { + position: relative; + inset-block-start: calc(-1rem / 16); + margin-inline: 2px; + color: var(--light-text-color); + + &.copyable { + cursor: pointer; + } + } + + & + .instructions { + margin-block-start: -3px; + } + + // BC + & > .instructions { + width: 100%; + } + } + + & > .instructions { + margin-block-end: 5px; + } + + & > .input { + position: relative; + + & + .instructions { + margin-block: 5px 0; + margin-inline: 0; + } + + input:disabled, + textarea:disabled, + select:disabled, + button:disabled { + cursor: not-allowed; + } + } + + & > .notice, + & > .warning { + margin-block: 5px 0; + margin-inline: 0; + } + + /* radio and checkbox */ + .custom-option-wrapper { + display: inline-block; + } + + .custom-option-input { + margin-inline-start: var(--xs); + } +} + +.read-only-badge { + font-size: calc(11rem / 16); + background-color: var(--gray-100); + color: var(--gray-700); + border: 1px solid var(--border-hairline); + border-radius: var(--radius-sm); + padding-block: 0; + padding-inline: 0.25em; + line-height: 1.45; +} + +.field > .instructions, +.markdown, +.warning.pane, +.tip.pane, + // BC +.field > .heading > .instructions, +.checkboxfield .instructions { + img, + video, + embed, + iframe { + max-width: 100% !important; + } + + ul, + ol { + margin-block: 1em; + margin-inline: 0; + padding-inline-start: 2em; + } + + ul li { + list-style-type: disc; + } + + li + li { + margin-block-start: 0.25em; + } +} + +.field > .instructions, + // BC +.field > .heading > .instructions, +.checkboxfield .instructions { + color: var(--custom-text-color, var(--fg-subtle)); +} + +// Special adjustments for content formatted via Markdown +.markdown { + color: var(--custom-text-color, var(--text-color)); + + h1, + h2, + h3, + h4, + h5, + h6 { + margin-block-end: 0.3em; + } + + p { + margin-block: 0.25em; + } +} + +.cross-site-copy-modal { + max-width: 380px; +} + +.expand-status-btn { + margin-inline-start: 5px; + width: calc(30rem / 16); + height: calc(17rem / 16); + min-height: auto; + padding: 0; + line-height: 16px; + border-radius: var(--radius-sm); + color: var(--text-color); + + &::before { + margin: 0; + } +} + +/* toggles and nested fields */ +.nested-fields { + margin: -24px; + padding-block: 24px 0; + padding-inline: 24px; + + &.hidden { + display: block; + height: 0; + } + + & > .field:last-child { + padding-block-end: 24px; + } +} + +/* checkbox */ +.checkbox-group { + display: flex; + flex-direction: column; + gap: calc(5rem / 16); + + .btn.add { + max-width: calc(200rem / 16); + } +} + +.checkbox-icon { + display: inline-flex; + padding: 3px; + background-color: var(--bg-enabled); + color: var(--white); + border-radius: var(--radius-sm); + + &::before { + --checkbox-size: 14px; + @include mixins.icon; + content: 'check'; + line-height: var(--checkbox-size); + font-size: var(--checkbox-size); + } +} + +.checkbox-preview-label { + display: none; +} + +.monaco-mouse-cursor-text { + &:focus-visible { + box-shadow: none !important; + } +} + +fieldset { + .checkboxfield { + margin-block: 5px; + margin-inline: 0; + } +} + +.checkboxfield { + .instructions, + .notice, + .warning { + margin-block-start: 2px; + padding-inline-start: calc(1rem + 5px); + } +} + +.checkboxfield__custom-wrapper { + display: inline-block; +} + +/* radio */ +.radio-group { + display: flex; + flex-direction: column; + gap: calc(5rem / 16); +} + +input.radio { + opacity: 0; + position: absolute; + width: var(--radio-size); + height: var(--radio-size); +} + +input.radio + label, +div.radio { + display: inline-block; + clear: none; + position: relative; + padding-inline-start: calc(var(--radio-size) + 0.35rem); + line-height: max(1rem, var(--radio-size)); + min-height: max(1rem, var(--radio-size)); + cursor: pointer; +} + +input.radio:disabled + label, +.disabled div.radio { + cursor: not-allowed; +} + +input.radio + label:empty, +div.radio:empty { + padding-inline-start: var(--radio-size); +} + +/* fixes a RTL bug */ +input.radio + label::before, +input.radio + label::after, +div.radio::before, +div.radio::after { + display: block; + position: absolute; + content: ''; + box-sizing: border-box; + background-clip: padding-box; + border-radius: 100%; +} + +input.radio + label::before, +div.radio::before { + inset-block-start: 50%; + inset-inline-start: 0; + transform: translateY(-50%); + width: var(--radio-size); + height: var(--radio-size); + background-color: hsl(212deg 50% 99%); + border: var(--input-border); +} + +input.radio + label::after, +div.radio::after { + inset-block-start: calc(50%); + inset-inline-start: 4px; + transform: translateY(-50%); + width: calc(var(--radio-size) - 8px); + height: calc(var(--radio-size) - 8px); +} + +input.radio:checked + label::after, +div.radio.checked::after, +.sel div.radio::after { + background: var(--gray-900); +} + +input.radio:focus-visible + label::before, +:focus-visible div.radio::before { + @include mixins.input-focused-styles; +} + +/* multiselect */ +.multiselect > select { + color: var(--text-color); + font-size: 14px; + appearance: none; + + &:focus-visible { + @include mixins.input-focused-styles; + } + + option { + padding-block: 1px; + padding-inline: 8px; + } +} + +.text, +.selectize.multiselect .selectize-input { + padding-block: 6px; +} + +.text:not(.color-input), +.selectize.multiselect .selectize-input { + padding-inline: 9px; +} + +.text { + &:not(.small) { + box-sizing: border-box; + min-height: var(--input-height); + } + + &.small { + padding: 3px; + } + + &.readable { + padding-block: 16px; + padding-inline: 18px; + font-size: 16px; + line-height: 22px; + + & + .chars-left { + margin-block-start: -23px; + } + } + + &.clearable { + padding-inline-end: var(--touch-target-size); + } + + input { + margin: 0; + padding: 0; + border: none; + background-color: transparent; + } +} + +td.errors .text, +.input.errors > .text, +.input.errors > .border-box, +.input.errors > .passwordwrapper, +.input.errors > .autosuggest-container .text, +.input.errors > .datetimewrapper .text, +.text.error { + border: 1px solid var(--fg-error) !important; +} + +.elementselect__search-input-wrapper, +.tagselect__input-wrapper, +.texticon { + position: relative; + cursor: text; + min-width: 130px; + + &.icon { + &::before { + color: var(--ui-control-color); + } + + svg, + &::before { + position: absolute; + inset-block-start: calc(50% - 7rem / 16); + inset-inline-start: 9px; + } + } + + .texticon-icon { + position: absolute; + inset-block-start: calc((34rem / 16) / 2); + transform: translateY(-50%); + display: flex; + justify-content: center; + align-items: center; + inset-inline-start: 9px; + } + + .text { + padding-inline-start: calc(26rem / 16); + } + + .clear-btn, + .filter-btn { + width: var(--touch-target-size); + height: var(--touch-target-size); + } + + .clear-btn { + position: absolute; + inset-block-start: calc( + (var(--touch-target-size) - 34px) / -2 + ); /* Responds to min-height of text input */ + inset-inline-end: 0; + } + + &.has-filter-btn { + .text { + padding-inline-end: 26px; + } + + .filter-btn { + position: absolute; + inset-block-start: calc((34rem / 16) / 2); + transform: translateY(-50%); + inset-inline-end: 4px; + padding-block: 0 4px; + font-size: 14px; + line-height: 22px; + cursor: pointer; + border-radius: 13px; + + &::before { + @include mixins.icon; + content: 'filter'; + color: var(--fg-subtle); + } + + &:hover { + background-color: var(--gray-100); + } + + &:active, + &.active, + &[aria-expanded='true'] { + background-color: var(--gray-350); + + &::before { + color: var(--white); + } + } + } + + .text { + &.clearable { + padding-inline-end: calc(30px + var(--touch-target-size)); + } + } + + .clear-btn { + inset-inline-end: 30px; + } + } +} + +.texthint-container { + position: relative; + height: 0; +} + +.texthint { + position: absolute; + inset-block-start: -1px; + width: 100%; + color: var(--light-text-color); + cursor: text; +} + +.passwordwrapper { + position: relative; + + .password { + border: none; + background: transparent; + padding-inline-end: 4rem; + box-shadow: none !important; + } + + .password-toggle { + color: var(--link-color); + position: absolute; + inset-block: 0; + inset-inline-end: 9px; + cursor: pointer; + + &:hover { + text-decoration: underline; + } + } +} + +.datetimewrapper { + display: flex; + flex-flow: row nowrap; + align-items: center; + gap: 5px; +} + +.clear-btn { + display: flex; + justify-content: center; + align-items: center; + width: 24px; + cursor: pointer; + color: var(--ui-control-color); + border: none; + padding: 0; + background: transparent; + + &::before { + @include mixins.icon; + content: 'remove'; + } + + &:hover { + color: var(--ui-control-hover-color); + } + + &:active { + color: var(--ui-control-active-color); + } +} + +.close-btn { + position: relative; + + &::before, + &::after { + position: absolute; + content: ''; + inset-block-start: 50%; + inset-inline-start: 50%; + height: 15px; + width: 2px; + background-color: var(--ui-control-color); + } + + &::before { + transform: translate(-50%, -50%) rotate(-45deg); + } + + &::after { + transform: translate(-50%, -50%) rotate(45deg); + } + + &:hover { + &::before, + &::after { + background-color: var(--ui-control-hover-color); + } + } + + &:active { + &::before, + &::after { + background-color: var(--ui-control-active-color); + } + } +} + +.datewrapper, +.timewrapper { + display: inline-block; + position: relative; + + .text { + position: relative; + z-index: 1; + width: 100%; + + & + div[data-icon] { + display: none; + } + + &:placeholder-shown, + &.empty-value { + & + div[data-icon] { + display: block; + position: absolute; + inset-block-start: calc(50% - 12px); + inset-inline-start: 14px; + z-index: 0; + color: var(--light-text-color); + + &, + &::before { + user-select: none; + pointer-events: none; + z-index: 1; + } + } + } + } +} + +.datewrapper { + width: 8em; +} + +.timewrapper { + width: 7em; +} + +@include mixins.placeholder-styles(var(--gray-400)); + +/* Kill IE's special text features */ +::-ms-reveal, +::-ms-clear { + display: none; +} + +/* Asset indexing related */ +tr.indexingSession td { + height: 34px; + padding-block: 1px; + padding-inline: 10px; +} + +tr.indexingSession td.progress div.progressContainer { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; +} + +tr.indexingSession td.progress div.progressContainer .progressbar { + width: 70%; + position: relative; + inset-inline-start: 0; + height: 12px; + z-index: 1; +} + +tr.indexingSession td.progress div.progressContainer div.progressInfo { + width: 20%; +} + +// Selects +.select:not(.selectize), +.select:not(.selectize) select { + @include mixins.select-styles; +} + +.select:not(.selectize) { + @include mixins.select-container-styles; +} + +.select:not(.selectize)::after { + @include mixins.select-arrow-styles; +} + +.select:not(.selectize) select { + @include mixins.select-input-styles; + white-space: pre; +} + +.select:not(.selectize).fullwidth select { + @include mixins.select-input-fullwidth-styles; +} + +.select:not(.selectize) select { + &:hover:not(:disabled) { + @include mixins.select-input-hovered-styles; + } + + &:focus-visible { + @include mixins.select-input-focused-styles; + } +} + +.select:not(.selectize).small::after { + inset-block-start: 9px; +} + +.select:not(.selectize).small select { + padding-block: 4px !important; + font-size: 11px; +} + +.selectize-control .selectize-input.disabled, +.custom-select.disabled { + opacity: 1; + cursor: not-allowed !important; + pointer-events: auto !important; + + * { + cursor: not-allowed !important; + pointer-events: auto !important; + } +} + +.selectize .selectize-input { + display: block; + border-color: inherit; + box-shadow: none; + background-color: transparent; + + .item { + max-width: 100%; + + span { + overflow: hidden; + text-overflow: ellipsis; + } + } +} + +.selectize.select .selectize-input::after { + display: none; +} + +body .selectize-dropdown { + border: none; + z-index: 101; +} + +/* single select styles */ +.selectize.select { + @include mixins.placeholder-styles(var(--gray-700)); + height: 34px; + + &:not(.fullwidth) { + width: 25em; + max-width: 100%; + } +} + +.datetimewrapper .selectize.select:not(.fullwidth) { + max-width: calc(100% - 29px); +} + +.selectize.select .selectize-control { + @include mixins.select-container-styles; + + &::after { + @include mixins.select-arrow-styles; + } +} + +.selectize.select .selectize-input { + @include mixins.select-styles; + + &.focus { + box-shadow: var(--focus-ring); + } +} + +.selectize.select .selectize-input { + @include mixins.select-input-styles; +} + +.selectize.select .selectize-control, +.selectize.select .selectize-input { + width: 100%; +} + +/* multi select styles */ +.selectize.multiselect .selectize-input { + min-height: 34px; + padding-block-end: 3px; + + &.focus { + @include mixins.input-focused-styles; + } + + & > .item { + @include mixins.token-styles; + display: inline-flex; + flex-direction: row; + padding-block: 3px !important; + padding-inline: 7px !important; + /* stylelint-disable declaration-property-value-keyword-no-deprecated */ + word-break: break-word; + /* stylelint-enable */ + + &.active { + @include mixins.active-token-styles; + } + + & > .remove { + position: static; + border-inline-start: none; + padding: 0; + font-size: 0; + color: var(--ui-control-color); + + &:hover { + color: var(--ui-control-hover-color); + background-color: transparent; + } + + &::before { + font-size: 14px; + @include mixins.icon; + content: 'remove'; + } + } + } +} + +/* menu styles */ +body { + .selectize-dropdown { + margin-block-start: 1px; + + [data-selectable], + .option, + .optgroup-header { + @include mixins.menu-item-styles; + } + + .optgroup { + &:not(:first-child) { + border-block-start: 1px solid var(--border-hairline); + } + + padding-block-start: 5px; + + .option { + padding-inline-start: 24px; + } + } + + .optgroup-header { + @include mixins.h6-styles; + margin: 0; + padding-block: 4px; + padding-inline: 0; + } + + .active:not(.selected), + .option:hover { + background-color: var(--gray-100); + } + + .selected { + @include mixins.menu-item-active-styles; + cursor: default !important; + + .light { + color: inherit !important; + } + } + } + + .selectize-dropdown-content { + @include mixins.menu-styles; + max-height: 70vh; + + .option { + min-height: 18px; + } + + & > div[data-value='new'] { + &::before { + @include mixins.icon; + content: 'plus'; + margin-inline-end: 5px; + } + + &::after { + content: '…'; + } + } + } + + &.no-scroll .selectize-dropdown-content { + max-height: 200px; // default for selectize + } +} + +/* datepicker */ +.ui-datepicker { + position: fixed; + inset-block-start: -300px; + margin-inline-start: 1px; + z-index: 101 !important; +} + +.ui-datepicker-header { + padding-block: 8px 4px; + padding-inline: 8px; +} + +.ui-datepicker-prev { + float: inline-start; +} + +.ui-datepicker-next { + float: inline-end; +} + +.ui-datepicker-prev span, +.ui-datepicker-next span { + display: none; +} + +.ui-datepicker-prev, +.ui-datepicker-next { + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + + &:hover::after { + border-color: var(--link-color); + } +} + +.ui-datepicker-prev::after { + @include mixins.angle(left); +} + +.ui-datepicker-next::after { + @include mixins.angle(right); +} + +.ui-datepicker-title { + text-align: center; + + select.ui-datepicker-year { + background-color: hsl(212deg 25% 90%); + padding-block: 0; + padding-inline: var(--xs); + border-radius: var(--radius-lg); + height: calc(22rem / 16); + } +} + +.ui-datepicker-calendar th, +.ui-datepicker-calendar td { + padding: 2px !important; +} + +.ui-datepicker-calendar th span, +.ui-datepicker-calendar td a { + display: block; + width: calc(26 / 16 * 1rem); + line-height: 26px; + text-align: center; + color: var(--text-color); +} + +.ui-datepicker-calendar th span { + color: var(--fg-subtle); + font-weight: normal; +} + +.ui-datepicker-calendar td a { + border-radius: 2px; +} + +.ui-datepicker-calendar td a:hover { + background-color: var(--bg-selection-light); + text-decoration: none; +} + +.ui-datepicker-calendar td a.ui-state-active { + background-color: var(--bg-selection-dark); + color: var(--white); + @include mixins.light-on-dark-text; + cursor: default; +} + +.ui-datepicker-calendar td.ui-datepicker-today a { + border-radius: 13px; + box-shadow: inset 0 0 0 2px var(--bg-selection-light); +} + +/* timepicker */ +.ui-timepicker-wrapper { + z-index: 101; + overflow-y: auto; + max-height: 210px; +} + +.ui-timepicker-list { + width: calc(14px + 6em); + z-index: 100; +} + +.ui-timepicker-list li { + padding-inline: 14px 0; + padding-block: 2px; + white-space: nowrap; + cursor: pointer; +} + +.ui-timepicker-list li:hover { + background-color: var(--bg-selection-light); +} + +.ui-timepicker-list li.ui-timepicker-selected { + background-color: var(--bg-selection-dark); + color: var(--white); + @include mixins.light-on-dark-text; + cursor: default; +} + +/* errors */ +ul.errors { + margin-block-start: 5px; + list-style-type: square; + padding-inline-start: 20px; +} + +ul.errors li { + color: var(--fg-error); +} + +/* message pages */ +.message-container { + display: flex; + justify-content: center; + align-items: center; + position: fixed; + z-index: 100; + inset-block-start: 0; + inset-inline-start: 0; + width: 100%; + height: 100%; + + .modal { + position: relative; + width: calc(15rem + var(--modal-padding) * 2); + min-width: 0; + height: auto; + min-height: 0; + } +} + +/* 2FA setup page */ +body.setup-2fa { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 100%; + + #setup-2fa { + display: flex; + flex-direction: column; + gap: var(--l); + width: 550px; + max-width: 100%; + padding: var(--padding); + + #setup-2fa-intro { + text-align: center; + } + + #setup-2fa-btn { + display: flex; + justify-content: center; + } + } +} + +/* licensing issues page */ +body.licensing-issues { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 100%; + padding: var(--padding); + + #licensing-issues { + display: flex; + flex-direction: row; + max-width: 50em; + + .buttons { + justify-content: space-between; + + [data-icon] { + margin-inline: 0; + } + } + } + + #continue { + margin: 0; + } +} + +/* auto-suggest */ +.autosuggest-container { + position: relative; +} + +.autosuggest__results-container { + position: absolute; + z-index: 2; + width: 100%; + border-radius: var(--radius-lg); + background-color: var(--white); + @include mixins.shadow; + box-sizing: border-box; + padding-block: 0; + padding-inline: 14px; + text-align: start; + @include mixins.sans-serif-font; + font-size: 1em !important; + + .autosuggest__results-before { + @include mixins.h6-styles; + margin-block-start: 14px !important; + } + + .autosuggest__results-item { + @include mixins.menu-item-styles; + overflow: hidden; + text-overflow: ellipsis; + + &:hover, + &.autosuggest__results-item--highlighted { + @include mixins.menu-item-active-styles; + cursor: pointer; + } + } +} + +/* ---------------------------------------- +/* Matrix +/* ---------------------------------------- */ + +/* Matrix fields */ +.matrix { + & > .buttons { + margin-block-start: 10px; + } +} + +.matrixblock { + margin-block-end: var(--s); + padding-block: 0 var(--m); + padding-inline: var(--m); + + &.static { + .titlebar { + padding-inline: 14px 0; + margin-block-end: 14px; + } + } + + & > .titlebar > .matrixblock-tabs .pane-tabs .menubtn:not(.action-btn) { + padding: 0; + width: var(--touch-target-size); + height: var(--touch-target-size); + background-color: transparent; + + &:hover { + backdrop-filter: brightness(90%); + } + + &:active, + &[aria-expanded='true'] { + backdrop-filter: brightness(85%); + } + } + + .flex-fields { + --row-gap: var(--m) !important; + --padding: var(--m); + --neg-padding: calc(var(--m) * -1); + } + + // no margin when a .field comes after a hidden item. + .hidden + .field { + margin-block-start: 0; + } + + & > .titlebar { + display: grid; + grid-template-columns: auto 1fr; + align-items: center; + gap: var(--m); + margin-block: 0; + margin-inline: calc(var(--m) * -1); + box-sizing: border-box; + border-radius: var(--radius-lg) var(--radius-lg) 0 0; + padding-inline: var(--m) calc(var(--m) + 70px); + padding-block: 5px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + overflow-wrap: normal; + cursor: default; + user-select: none; + position: relative; + background-color: var(--custom-titlebar-bg-color, var(--gray-100)); + min-height: calc(var(--lh) + 10px); + + & > .blocktype, + & > .preview { + font-size: 0.8em !important; + } + + & > .blocktype { + font-weight: 500; + } + + & > .preview { + flex-grow: 1; + min-width: 0; + opacity: 0; + transition: opacity linear 100ms; + overflow: hidden; + + &:empty { + display: none; + } + + body.ltr & { + mask-image: linear-gradient( + to left, + rgb(0 0 0 / 0%), + rgb(0 0 0 / 100%) 12px + ); + } + + body.rtl & { + mask-image: linear-gradient( + to right, + rgb(0 0 0 / 0%), + rgb(0 0 0 / 100%) 12px + ); + } + + span { + opacity: 0.5; + } + } + + & > .matrixblock-tabs { + flex: 1; + min-width: 0; + margin-block: -5px; + margin-inline: 0; + + .pane-tabs { + margin: 0; + padding-inline-end: 3px; + + [role='tablist'] { + padding-block: 0; + padding-inline: 12px; + + &.scrollable { + mask-image: linear-gradient( + to right, + rgb(0 0 0 / 0%), + rgb(0 0 0) 12px, + rgb(0 0 0) calc(100% - 12px), + rgb(0 0 0 / 0%) 100% + ); + } + + [role='tab'] { + background-color: transparent; + + &.sel { + background-color: var( + --custom-bg-color, + var(--gray-050) + ) !important; + } + + .tab-label { + height: calc(var(--lh) + 10px); + padding-block: 0; + padding-inline: var(--m); + } + } + } + + .menubtn:not(.action-btn) { + margin-inline: 0; + + &:not(:empty, .btn-empty)::after { + margin-inline-start: 0; + } + } + } + } + + & > .preview:first-child:empty + .matrixblock-tabs { + margin-inline-start: calc((var(--m) + 12px) * -1); + } + } + + &.disabled-entry { + & > .titlebar { + padding-inline-end: 100px; + } + + & > .actions { + & > .status { + &.off { + display: block; + } + } + } + } + + &.collapsed { + & > .titlebar { + border-radius: var(--radius-lg); + + & > .preview { + opacity: 1; + } + } + } + + & > .actions { + display: flex; + align-items: center; + gap: var(--s); + position: absolute; + inset-block-start: 0; + inset-inline-end: var(--m); + cursor: default; + min-height: calc(var(--lh) + 10px); + + & > .status { + &.off { + display: none; + } + } + } + + &:not(.static) { + & > .fields { + padding-block-start: var(--l); + } + } + + & > .fields > .flex-fields > :not(h2, hr, .line-break) { + &::before { + display: none; + } + } + + & > .buttons { + margin-block-start: 0; + height: 30px; + } +} + +/* number field */ +.number-container { + display: inline-flex; + align-items: center; + flex-wrap: nowrap; + gap: 0; + + .number-currency-label { + @include mixins.input-styles; + border-inline-end: none; + border-start-end-radius: 0; + border-end-end-radius: 0; + align-items: center; + box-sizing: border-box; + background: transparent; + display: flex; + min-height: var(--input-height); + padding-block: 6px; + padding-inline: 9px; + white-space: nowrap; + + & + .text { + border-start-start-radius: 0; + border-end-start-radius: 0; + } + } +} + +/* categories */ +.add-category-form { + margin-block-start: 24px; +} + +.add-category-form .texticon { + width: 200px; + float: inline-start; + margin-inline-end: 5px; +} + +.add-category-form .texticon .text { + padding-inline-end: 30px; +} + +.add-category-form .texticon .spinner { + position: absolute; + inset-block-start: 0; + inset-inline-end: 5px; +} + +/* site pickers */ +body.sitepicker { + #main-content { + padding: 30px; + justify-content: center; + align-items: center; + text-align: center; + } + + #content-container { + max-width: 400px; + } +} + +.sitepicker-group { + li { + &:not(:first-child) { + a { + margin-block-start: -1px; + border-start-start-radius: 0; + border-start-end-radius: 0; + + &:not(:hover) { + border-block-start-color: transparent; + } + } + } + + &:not(:last-child) { + a { + border-end-start-radius: 0; + border-end-end-radius: 0; + } + } + + a { + display: block; + position: relative; + text-align: start; + width: 100%; + box-sizing: border-box; + border: 1px solid var(--border-hairline); + border-radius: var(--radius-md); + padding-inline: 15px 42px; + padding-block: 9px; + font-size: 16px; + line-height: 1.4; + + &::after { + font-size: 14px; + position: absolute; + inset-block-start: calc(50% - 7px); + inset-inline-end: 12px; + margin: 0; + padding: 0; + } + + &:hover { + border-color: var(--link-color); + text-decoration: none; + z-index: 1; + } + } + } +} + +.entry-mover-modal { + --width: calc(var(--ui-control-height) * 10 + var(--s) * 9 + var(--xl) * 2); + width: var(--width) !important; + min-width: 0 !important; + max-width: calc(100% - 20px) !important; + + .header { + padding-block: calc(var(--m)); + text-align: center; + } + + .body { + height: 83%; + position: relative; + + .entry-mover-modal--list { + height: calc(100% + 20px); + position: relative; + + fieldset { + box-sizing: border-box; + height: 100%; + overflow: auto; + padding-block-end: 20px; + position: relative; + } + } + } + + .footer { + position: absolute; + inset-block-end: 0; + inset-inline-start: 0; + width: 100%; + margin: 0; + box-sizing: border-box; + } +} + +/* ---------------------------------------- +/* IE hacks +/* ---------------------------------------- */ + +/* Fix layout of modal element selectors for IE8 */ +.elementselectormodal .body .main { + float: left \9; + width: 445px \9; +} + +/* ---------------------------------------- +/* Retina graphics +/* ---------------------------------------- */ + +@media only screen and (resolution >= 1.5dppx) { + .structure ul li { + background-size: 40px; + + body.ltr & { + background-image: url('../images/branch_2x.png'); + } + + body.rtl & { + background-image: url('../images/branch_rtl_2x.png'); + } + } +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_preview.scss b/packages/craftcms-legacy/cp/src/css.bkup/_preview.scss new file mode 100644 index 00000000000..9655d5a92fe --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_preview.scss @@ -0,0 +1,340 @@ +@charset "UTF-8"; +@use 'sass:color'; +@use '@craftcms/sass/mixins'; + +.lp-editor-container, +.lp-preview-container { + position: fixed; + inset-block-start: 0; + height: 100%; + background-color: var(--white); + z-index: 100; + + & > header { + padding-block: 5px; + padding-inline: var(--pane-padding, var(--xl)); + background-color: var(--gray-100); + box-shadow: 0 1px 0 color.adjust(mixins.$grey700, $alpha: -0.8); + box-sizing: border-box; + position: relative; + z-index: 1; + height: 44px; + + @supports (backdrop-filter: blur(10px)) { + /* stylelint-disable block-no-redundant-nested-style-rules */ + & { + position: absolute; + z-index: 2; + inset-block-start: 0; + inset-inline-start: 0; + width: 100%; + background-color: color.adjust(mixins.$grey100, $alpha: -0.25); + backdrop-filter: blur(10px); + + & + .lp-content { + padding-block-start: #{44 + 24}px; + } + } + /* stylelint-enable */ + } + + .btn, + .spinner, + .checkmark-icon { + margin-block-end: 0; + } + + .btn[data-icon='xmark'] { + margin-inline: calc(-12rem / 16) calc(var(--s) * -1); + + &:not(:hover, :active, [aria-expanded='true']) { + background-color: transparent; + } + } + + .lp-toolbar { + min-width: 0; + + .pane-tabs { + margin-inline: 0 !important; + + [role='tablist'] { + padding-block: 0; + padding-inline: 12px; + + &.scrollable { + mask-image: linear-gradient( + to right, + rgb(0 0 0 / 0%), + rgb(0 0 0) 12px, + rgb(0 0 0) calc(100% - 12px), + rgb(0 0 0 / 0%) 100% + ); + } + + [role='tab'] { + background-color: transparent; + } + } + + .menubtn:not(.action-btn) { + --focus-ring: var(--focus-ring-inner); + margin-inline: 0; + + &:not(:empty, .btn-empty)::after { + margin-inline-start: 0; + } + } + } + } + } +} + +.lp-editor-container { + display: flex; + flex-direction: column; + + .lp-editor-header { + display: flex; + align-items: center; + align-content: stretch; + gap: var(--xs); + + &:not(:has(.lp-close-btn)) { + padding-inline-start: 0; + + .pane-tabs [role='tablist'] { + padding-inline-start: 0; + } + } + } + + .lp-content { + flex: 1; + padding: var(--pane-padding, var(--xl)); + overflow: auto; + box-sizing: border-box; + position: relative; + + &:not(.loading) > .spinner { + display: none; + } + + &.loading > .spinner { + position: absolute; + inset-block-start: calc(50% - 17px); + inset-inline-start: calc(50% - 12px); + color: var(--ui-control-color); + } + } + + & > footer { + padding-block: 5px; + padding-inline: var(--pane-padding, var(--xl)); + box-shadow: inset 0 1px 0 var(--border-hairline); + background-color: var(--gray-100); + justify-content: end; + height: 44px; + } +} + +.lp-draghandle { + inset-block-start: 0; + position: fixed; + z-index: 101; + width: 4px; + height: 100%; + cursor: col-resize; +} + +.lp-preview-container { + display: flex; + flex-direction: column; + box-shadow: -1px 0 0 color.adjust(mixins.$grey700, $alpha: -0.8); + + &.dragging::after { + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; + width: 100%; + height: 100%; + content: ''; + font-size: 0; + } + + .lp-preview-header { + display: flex; + + @supports (not (backdrop-filter: blur(10px))) { + background-color: color.adjust(mixins.$grey100, $alpha: -0.25); + } + + .buttons { + margin: 0; + + .btn + .btn { + margin-inline-start: 7px; + } + } + + & + .lp-iframe-container { + padding-block-start: 0; + + @supports (backdrop-filter: blur(10px)) { + padding-block-start: 44px; + } + } + + .lp-device-type { + .btn { + &::before { + width: 27px; + height: 22px; + display: block; + content: ''; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + transition-duration: 0.3s; + } + + // SVGs + &.lp-device-type-btn--phone::before { + background-image: url('../images/preview/icon-phone.svg'); + } + + &.lp-device-type-btn--tablet::before { + background-image: url('../images/preview/icon-tablet.svg'); + } + + &.lp-device-type-btn--desktop::before { + background-image: url('../images/preview/icon-desktop.svg'); + } + } + } + } + + .lp-device-type__label { + &::before { + width: 27px; + height: 22px; + display: block; + content: ''; + background-size: contain; + background-repeat: no-repeat; + background-position: center; + transition-duration: 0.3s; + } + + // SVGs + &.lp-device-type__label--phone::before { + background-image: url('../images/preview/icon-phone.svg'); + } + + &.lp-device-type__label--tablet::before { + background-image: url('../images/preview/icon-tablet.svg'); + } + + &.lp-device-type__label--desktop::before { + background-image: url('../images/preview/icon-desktop.svg'); + } + } + + .lp-preview-container__bumper-link { + inset-block: unset 0; + } + + .lp-device-mask { + display: none; + } + + .lp-iframe-container { + flex: 1; + overflow: auto; + + .lp-preview { + display: block; + width: 100%; + min-height: 100%; + } + + &:not(.lp-iframe-container--has-device-preview) { + // Preview container + .lp-device-preview-container { + width: auto !important; + height: 100% !important; + transform: none !important; + margin: 0 !important; + } + } + + &--has-device-preview { + flex: none; + padding-block-start: 0 !important; + position: relative; + inset-block-start: 0; + height: calc(100% - 44px); + width: 100%; + background-color: var(--gray-100); + + @supports (backdrop-filter: blur(10px)) { + inset-block-start: 44px; + } + + // Preview container + .lp-device-preview-container { + position: absolute; + inset-block-start: 50%; + inset-inline-start: 50%; + z-index: 2; + overflow: auto; + opacity: 1; + transition: opacity 0.3s; + } + + // Device mask + .lp-device-mask { + display: block; + position: absolute; + inset-block-start: 50%; + inset-inline-start: 50%; + z-index: 1; + background-image: + url('../images/preview/chrome-phone-top.svg'), + url('../images/preview/chrome-phone-bottom.svg'); + background-position: + top center, + bottom center; + background-repeat: no-repeat; + background-size: contain; + background-color: #fff; + box-shadow: 0 0 58px rgb(6 67 117 / 30%); + border-radius: 18px; + } + + // Tablet + &.lp-iframe-container--tablet { + .lp-device-mask { + background-image: + url('../images/preview/chrome-tablet-top.svg'), + url('../images/preview/chrome-tablet-bottom.svg'); + } + } + } + + // Animate rotations + @media screen and (prefers-reduced-motion: no-preference) { + &--rotating { + .lp-device-mask { + transition-duration: 0.3s; + transition-property: transform; + } + + .lp-device-preview-container { + opacity: 0; + transition: opacity 0s; + } + } + } + } +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_range.scss b/packages/craftcms-legacy/cp/src/css.bkup/_range.scss new file mode 100644 index 00000000000..06c525203b3 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_range.scss @@ -0,0 +1,108 @@ +@charset "utf-8"; + +/* range inputs */ + +/* h/t https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/ */ + +/* h/t https://stackoverflow.com/a/38163892/1688568 */ + +$trackColor: var(--white); +$trackHeight: 6px; +$trackBorderRadius: 3px; +$trackShadow: inset 0 0 0 1px var(--ui-control-color); +$thumbColor: var(--ui-control-color); +$thumbSize: var(--m); +$thumbShadow: 0 0 0 1px var(--white); +$thumbBorderRadius: calc(var(--touch-target-size) / 2); + +.range-wrapper { + max-width: 200px; +} + +input.range { + display: block; + appearance: none; + width: 100%; // for FF +} + +input.range:focus { + outline: none; +} + +// Thumb styles +input.range::-webkit-slider-thumb { + border: none; + height: $thumbSize; + width: $thumbSize; + border-radius: $thumbBorderRadius; + background: $thumbColor; + box-shadow: $thumbShadow; + cursor: pointer; + appearance: none; + margin-block-start: calc((#{$thumbSize} / 2) * -1 + (#{$trackHeight} / 2)); +} + +input.range::-moz-range-thumb { + border: none; + height: $thumbSize; + width: $thumbSize; + border-radius: $thumbBorderRadius; + background: $thumbColor; + box-shadow: $thumbShadow; + cursor: pointer; +} + +input.range::-ms-thumb { + border: none; + height: $thumbSize; + width: $thumbSize; + border-radius: $thumbBorderRadius; + background: $thumbColor; + box-shadow: $thumbShadow; + cursor: pointer; +} + +// Track styles +input.range::-webkit-slider-runnable-track { + width: 100%; + height: $trackHeight; + cursor: pointer; + background: $trackColor; + border-radius: $trackBorderRadius; + box-shadow: $trackShadow; +} + +input.range::-moz-range-track { + width: 100%; + height: $trackHeight; + cursor: pointer; + background: $trackColor; + border-radius: $trackBorderRadius; + box-shadow: $trackShadow; +} + +input.range::-ms-track { + width: 100%; + height: $trackHeight; + cursor: pointer; + background: transparent; + border-color: transparent; + border-width: 16px 0; + color: transparent; +} + +input.range::-ms-fill-lower { + background: $trackColor; + border: none; + border-radius: $trackBorderRadius; +} + +input.range::-ms-fill-upper { + background: $trackColor; + border: none; + border-radius: $trackBorderRadius; +} + +input.range:focus::-ms-fill-lower { + background: $trackColor; +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_shame.scss b/packages/craftcms-legacy/cp/src/css.bkup/_shame.scss new file mode 100644 index 00000000000..d44ca30a28f --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_shame.scss @@ -0,0 +1,11 @@ +_:-ms-lang(x), +.elements .tableview td.checkbox-cell input.checkbox + label, +.elements .tableview td.checkbox-cell div.checkbox { + inset-block-start: 16px; +} + +_:-ms-lang(x), +input.checkbox + label:empty, +div:empty.checkbox { + display: block; +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_skip-links.scss b/packages/craftcms-legacy/cp/src/css.bkup/_skip-links.scss new file mode 100644 index 00000000000..e73a71c8b0a --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_skip-links.scss @@ -0,0 +1,26 @@ +@use '@craftcms/sass/mixins'; + +.skip-link { + position: absolute; + margin: 5px; + inset-inline-start: -10000px; + inset-block-start: 0; + width: 1px; + height: 1px; + overflow: hidden; + z-index: $sidebarZIndex + 1; + + &:focus { + inset-inline-start: unset; + inset-inline-start: 0; + width: auto; + height: auto; + background-color: var(--gray-100) !important; + } +} + +.skip-link--global { + @media only screen and (min-width: $minFullUiWidth) { + @include mixins.two-color-focus-ring; + } +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/_variables.scss b/packages/craftcms-legacy/cp/src/css.bkup/_variables.scss new file mode 100644 index 00000000000..bfc804fe0ea --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/_variables.scss @@ -0,0 +1,96 @@ +@use 'sass:color'; +@use '@craftcms/sass/mixins'; + +/** +These variables will be removed in the next major version and area only provided for compatibility. +Use the new values in the `tokens.scss` file instead. +*/ +:root { + --bg-color: var(--body-bg); + --bg-color-hsl: 212deg, 50%, 93%; + + // submit button colors + --primary-color: var(--bg-primary); + --secondary-color: var(--bg-secondary); + --input-color: var(--fg-input); + + // text colors + --medium-dark-text-color: var(--fg-subtle); + --medium-text-color: var(--fg-subtle); + + // font styles + --font-weight-bold: 700; + + // hairline colors + --hairline-color: var(--border-hairline); + --medium-hairline-color: var(--border-hairline-medium); + --dark-hairline-color: var(--border-hairline-dark); + + // focus colors + --light-focus-color: var(--focus-outline-light); + --medium-focus-color: var(--focus-outline-medium); + --dark-focus-color: var(--focus-outline-dark); + + // focus rings + --light-focus-ring: var(--focus-ring-light); + --medium-focus-ring: var(--focus-ring-medium); + --dark-focus-ring: var(--focus-ring-dark); + + // selection colors + --light-sel-color: var(--bg-selection-light); + --dark-sel-color: var(--bg-selection-dark); + + // alert/notice colors + --error-color-rgb: 216 31 35; + --error-color: var(--fg-error); + --warning-color: var(--fg-warning); + --warning-background: var(--bg-warning); + --warning-border-color: var(--border-warning); + --success-color: var(--fg-success); + --notice-color: var(--fg-notice); + --notice-background: var(--bg-notice); + --notice-border-color: var(--border-notice); + + // status colors + --enabled-color: var(--bg-enabled); + --pending-color: var(--bg-pending); + --disabled-color: var(--bg-disabled); + + // misc colors + --indicator-border-color: var(--border-warning-emphasis); + --indicator-icon-color: var(--fg-warning); + + // UI element styles + --small-border-radius: var(--radius-sm); + --medium-border-radius: var(--radius-md); + --large-border-radius: var(--radius-lg); + --menu-border-radius: var(--medium-border-radius); + + // Variables from _main.scss + --ui-control-color: var(--ui-control-fg); + --ui-control-hover-color: var(--ui-control-fg-hover); + --ui-control-active-color: var(--ui-control-fg-active); + --ui-control-static-bg-color: var(--ui-control-bg-static); + --ui-control-bg-color: var(--ui-control-bg); + --ui-control-hover-bg-color: var(--ui-control-bg-hover); + --ui-control-active-bg-color: var(--ui-control-bg-active); + --ui-control-border-radius: var(--ui-control-radius); + --ui-control-height--small: var(--ui-control-height-small); + --light-focus-hsl: 212deg, 96%, 78%; + --dark-focus-hsl: 203deg, 84%, 38%; + --inner-focus-ring: var(--focus-ring-inner); + --touch-target-size: var(--size-touch-target); + --icon-size: var(--size-icon); + --lh: var(--size-line-height); + + // Sidebar + --sidebar-bgColor: var(--sidebar-bg); + + // Nav items (compatibility) + --nav-item-badge-bgColor: var(--nav-item-badge-bg); + --nav-item-badge-fgColor: var(--nav-item-badge-fg); + --nav-item-fgColor-active: var(--nav-item-fg-active); + --nav-item-bgColor-active: var(--nav-item-bg-active); + --nav-item-fgColor-hover: var(--nav-item-fg-hover); + --nav-item-bgColor-hover: var(--nav-item-bg-hover); +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/charts.scss b/packages/craftcms-legacy/cp/src/css.bkup/charts.scss new file mode 100644 index 00000000000..ac1d3e711f5 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/charts.scss @@ -0,0 +1,65 @@ +@charset "UTF-8"; + +@import '@craftcms/sass/mixins'; + +.cp-chart { + margin: 0; + height: 100%; + position: relative; +} + +.cp-chart svg { + width: 100%; + height: 100%; +} + +.cp-chart .axis path, +.cp-chart .axis line { + fill: none; + stroke: var(--border-hairline); + shape-rendering: crispedges; +} + +.cp-chart .ticks-axis path, +.cp-chart .ticks-axis line { + fill: none; + stroke: none; + shape-rendering: crispedges; +} + +.cp-chart .ticks-axis g.tick text { + fill: var(--black); + font-size: 11px; +} + +.cp-chart .axis text { + fill: rgb(0 0 0 / 60%); +} + +.cp-chart .grid-line .tick { + stroke: rgb(0 0 0 / 8%); + stroke-opacity: 0.7; + shape-rendering: crispedges; +} + +.cp-chart .grid-line .tick line { + stroke: rgb(0 0 0 / 8%); + stroke-opacity: 0.7; + shape-rendering: crispedges; +} + +.cp-chart .grid-line path { + stroke-width: 0; +} + +.tooltip { + border-radius: 3px; + padding-block: 7px; + padding-inline: 10px; + background: transparentize($white, 0.1); + position: absolute; + z-index: 1000000; + @include shadow; + user-select: none; + pointer-events: none; +} diff --git a/packages/craftcms-legacy/cp/src/css.bkup/craft.scss b/packages/craftcms-legacy/cp/src/css.bkup/craft.scss new file mode 100644 index 00000000000..1b724bfb146 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css.bkup/craft.scss @@ -0,0 +1,19 @@ +@charset "utf-8"; + +@import 'compat'; +@import 'menu'; +@import 'hud'; +@import 'icon-picker'; +@import 'login'; +@import 'main'; +@import 'cp'; +@import 'range'; +@import 'global-sidebar'; +@import 'craft-spinner'; +@import 'craft-tooltip'; +@import 'preview'; +@import 'entry-type-select'; +@import 'grouped-entry-type-select'; +@import 'image_editor'; +@import 'shame'; +@import 'debug_toolbar'; diff --git a/packages/craftcms-legacy/cp/src/css/_color-palette.scss b/packages/craftcms-legacy/cp/src/css/_color-palette.scss new file mode 100644 index 00000000000..66c47fa4ac9 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css/_color-palette.scss @@ -0,0 +1,224 @@ +@charset "UTF-8"; +@use '@craftcms/sass/mixins'; + +:root { + --white: #fff; + --black: #000; + --gray-050-hsl: 212, 60%, 97%; + --gray-100-hsl: 212, 50%, 93%; + --gray-150-hsl: 212, 40%, 89%; + --gray-200-hsl: 212, 30%, 85%; + --gray-300-hsl: 211, 13%, 65%; + --gray-350-hsl: 211, 11%, 59%; + --gray-400-hsl: 210, 10%, 53%; + --gray-500-hsl: 211, 12%, 43%; + --gray-550-hsl: 210, 13%, 40%; + --gray-600-hsl: 209, 14%, 37%; + --gray-700-hsl: 209, 18%, 30%; + --gray-800-hsl: 209, 20%, 25%; + --gray-900-hsl: 210, 24%, 16%; + --gray-1000-hsl: 210, 24%, 10%; + --gray-050: hsl(var(--gray-050-hsl)); + --gray-100: hsl(var(--gray-100-hsl)); + --gray-150: hsl(var(--gray-150-hsl)); + --gray-200: hsl(var(--gray-200-hsl)); + --gray-300: hsl(var(--gray-300-hsl)); + --gray-350: hsl(var(--gray-350-hsl)); + --gray-400: hsl(var(--gray-400-hsl)); + --gray-500: hsl(var(--gray-500-hsl)); + --gray-550: hsl(var(--gray-550-hsl)); + --gray-600: hsl(var(--gray-600-hsl)); + --gray-700: hsl(var(--gray-700-hsl)); + --gray-800: hsl(var(--gray-800-hsl)); + --gray-900: hsl(var(--gray-900-hsl)); + --gray-1000: hsl(var(--gray-1000-hsl)); + --red-050: #fef2f2; + --red-100: #fee2e2; + --red-200: #fecaca; + --red-300: #fca5a5; + --red-400: #f87171; + --red-500: #ef4444; + --red-600: #dc2626; + --red-700: #b91c1c; + --red-800: #991b1b; + --red-900: #7f1d1d; + --red-950: #450a0a; + --orange-050: #fff7ed; + --orange-100: #ffedd5; + --orange-200: #fed7aa; + --orange-300: #fdba74; + --orange-400: #fb923c; + --orange-500: #f97316; + --orange-600: #ea580c; + --orange-700: #c2410c; + --orange-800: #9a3412; + --orange-900: #7c2d12; + --orange-950: #431407; + --amber-050: #fffbeb; + --amber-100: #fef3c7; + --amber-200: #fde68a; + --amber-300: #fcd34d; + --amber-400: #fbbf24; + --amber-500: #f59e0b; + --amber-600: #d97706; + --amber-700: #b45309; + --amber-800: #92400e; + --amber-900: #78350f; + --amber-950: #451a03; + --yellow-050: #fefce8; + --yellow-100: #fef9c3; + --yellow-200: #fef08a; + --yellow-300: #fde047; + --yellow-400: #facc15; + --yellow-500: #eab308; + --yellow-600: #ca8a04; + --yellow-700: #a16207; + --yellow-750: #93580b; + --yellow-800: #854d0e; + --yellow-900: #713f12; + --yellow-950: #422006; + --lime-050: #f7fee7; + --lime-100: #ecfccb; + --lime-200: #d9f99d; + --lime-300: #bef264; + --lime-400: #a3e635; + --lime-500: #84cc16; + --lime-600: #65a30d; + --lime-700: #4d7c0f; + --lime-800: #3f6212; + --lime-900: #365314; + --lime-950: #1a2e05; + --green-050: #f0fdf4; + --green-100: #dcfce7; + --green-200: #bbf7d0; + --green-300: #86efac; + --green-400: #4ade80; + --green-500: #22c55e; + --green-600: #16a34a; + --green-700: #15803d; + --green-800: #166534; + --green-900: #14532d; + --green-950: #052e16; + --emerald-050: #ecfdf5; + --emerald-100: #d1fae5; + --emerald-200: #a7f3d0; + --emerald-300: #6ee7b7; + --emerald-400: #34d399; + --emerald-500: #10b981; + --emerald-600: #059669; + --emerald-700: #047857; + --emerald-800: #065f46; + --emerald-900: #064e3b; + --emerald-950: #022c22; + --teal-050: #f0fdfa; + --teal-100: #ccfbf1; + --teal-200: #99f6e4; + --teal-300: #5eead4; + --teal-400: #2dd4bf; + --teal-500: #14b8a6; + --teal-550: #11a697; + --teal-600: #0d9488; + --teal-700: #0f766e; + --teal-800: #115e59; + --teal-900: #134e4a; + --teal-950: #042f2e; + --cyan-050: #ecfeff; + --cyan-100: #cffafe; + --cyan-200: #a5f3fc; + --cyan-300: #67e8f9; + --cyan-400: #22d3ee; + --cyan-500: #06b6d4; + --cyan-600: #0891b2; + --cyan-700: #0e7490; + --cyan-800: #155e75; + --cyan-900: #164e63; + --cyan-950: #083344; + --sky-050: #f0f9ff; + --sky-100: #e0f2fe; + --sky-200: #bae6fd; + --sky-300: #7dd3fc; + --sky-400: #38bdf8; + --sky-500: #0ea5e9; + --sky-600: #0284c7; + --sky-700: #0369a1; + --sky-800: #075985; + --sky-900: #0c4a6e; + --sky-950: #082f49; + --blue-050: #eff6ff; + --blue-100: #dbeafe; + --blue-200: #bfdbfe; + --blue-300: #93c5fd; + --blue-400: #60a5fa; + --blue-500: #3b82f6; + --blue-600: #2563eb; + --blue-700: #1d4ed8; + --blue-800: #1e40af; + --blue-900: #1e3a8a; + --blue-950: #172554; + --indigo-050: #eef2ff; + --indigo-100: #e0e7ff; + --indigo-200: #c7d2fe; + --indigo-300: #a5b4fc; + --indigo-400: #818cf8; + --indigo-500: #6366f1; + --indigo-600: #4f46e5; + --indigo-700: #4338ca; + --indigo-800: #3730a3; + --indigo-900: #312e81; + --indigo-950: #1e1b4b; + --violet-050: #f5f3ff; + --violet-100: #ede9fe; + --violet-200: #ddd6fe; + --violet-300: #c4b5fd; + --violet-400: #a78bfa; + --violet-500: #8b5cf6; + --violet-600: #7c3aed; + --violet-700: #6d28d9; + --violet-800: #5b21b6; + --violet-900: #4c1d95; + --violet-950: #2e1065; + --purple-050: #faf5ff; + --purple-100: #f3e8ff; + --purple-200: #e9d5ff; + --purple-300: #d8b4fe; + --purple-400: #c084fc; + --purple-500: #a855f7; + --purple-600: #9333ea; + --purple-700: #7e22ce; + --purple-800: #6b21a8; + --purple-900: #581c87; + --purple-950: #3b0764; + --fuchsia-050: #fdf4ff; + --fuchsia-100: #fae8ff; + --fuchsia-200: #f5d0fe; + --fuchsia-300: #f0abfc; + --fuchsia-400: #e879f9; + --fuchsia-500: #d946ef; + --fuchsia-600: #c026d3; + --fuchsia-700: #a21caf; + --fuchsia-800: #86198f; + --fuchsia-900: #701a75; + --fuchsia-950: #4a044e; + --pink-050: #fdf2f8; + --pink-100: #fce7f3; + --pink-200: #fbcfe8; + --pink-300: #f9a8d4; + --pink-400: #f472b6; + --pink-500: #ec4899; + --pink-600: #db2777; + --pink-700: #be185d; + --pink-800: #9d174d; + --pink-900: #831843; + --pink-950: #500724; + --rose-050: #fff1f2; + --rose-100: #ffe4e6; + --rose-200: #fecdd3; + --rose-300: #fda4af; + --rose-400: #fb7185; + --rose-500: #f43f5e; + --rose-600: #e11d48; + --rose-700: #be123c; + --rose-800: #9f1239; + --rose-900: #881337; + --rose-950: #4c0519; +} diff --git a/packages/craftcms-legacy/cp/src/css/_craft-disclosure.scss b/packages/craftcms-legacy/cp/src/css/_craft-disclosure.scss new file mode 100644 index 00000000000..43cd953bf2b --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css/_craft-disclosure.scss @@ -0,0 +1,17 @@ +craft-disclosure { + --disclosure-icon-transform: rotate(0deg); + --disclosure-icon-transform-active: rotate(-90deg); + display: contents; + + [aria-expanded='true'] .cp-icon { + transform: var(--disclosure-icon-transform); + } +} + +craft-disclosure [aria-expanded='false'] .cp-icon { + transform: var(--disclosure-icon-transform-active); +} + +body.rtl craft-disclosure { + --disclosure-icon-transform-active: rotate(90deg); +} diff --git a/packages/craftcms-legacy/cp/src/css/_fld.scss b/packages/craftcms-legacy/cp/src/css/_fld.scss new file mode 100644 index 00000000000..28b5b699e06 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css/_fld.scss @@ -0,0 +1,469 @@ +@charset "UTF-8"; +@use 'sass:color'; +@use '@craftcms/sass/mixins'; + +$base: 24px; +$tabPadding: 14px; +$tabWidth: $base * 12; +$gridColor: var(--gray-100); + +@mixin workspace-bg { + background-color: var(--gray-050); + background-image: + linear-gradient(to right, $gridColor 1px, transparent 0), + linear-gradient(to bottom, $gridColor 1px, transparent 1px); + background-size: $base $base; +} + +.layoutdesigner { + container-type: inline-size; +} + +.fld-container { + display: flex; + align-items: stretch; + position: relative; + @include mixins.input-styles; + overflow: hidden; + box-shadow: none; + min-height: 500px; + + .errors > .layoutdesigner > & { + border: 1px solid var(--fg-error) !important; + } + + .fld-workspace { + flex: 1; + max-width: 100%; + border-start-start-radius: calc(var(--radius-sm) - 1px); + border-start-end-radius: 0; + border-end-end-radius: 0; + border-end-start-radius: calc(var(--radius-sm) - 1px); + padding-inline: $base 0; + padding-block: $base; + @include workspace-bg; + background-position: -1px -1px; + box-shadow: inset 0 1px 3px -1px + color.adjust(mixins.$grey200, $lightness: -10%); + + .fld-tabs { + display: flex; + align-items: flex-start; + flex-wrap: wrap; + } + } + + .fld-library { + display: none; + } +} + +.fld-library-hud { + width: $tabWidth - 1; + max-width: 100%; + + .main { + height: 100%; + padding: $tabPadding; + } +} + +.fld-new-tab-btn:active { + background-color: var(--gray-050); +} + +.fld-library { + display: flex; + flex-direction: column; + height: 100%; + + .btngroup { + margin-block-end: $tabPadding; + } + + .fld-field-library, + .fld-ui-library { + margin-block: -3px; + margin-inline: #{-$tabPadding}; + padding-block: 3px; + padding-inline: #{$tabPadding}; + flex: 1; + min-height: 0; + max-height: 550px; + overflow: auto; + } + + .fld-field-library { + .fld-field-group { + margin-block-start: $tabPadding; + + & > *:not(:first-child) { + margin-block-start: var(--s); + } + } + + .fld-field-indicators { + display: none; + } + } + + .fld-ui-library > *:not(:first-child) { + margin-block-start: var(--s); + } + + .filtered { + display: none !important; + } +} + +.layoutdesigner .fld-library, +.fld-tab .tabs .tab, +.fld-tab .fld-tabcontent { + background-color: var(--white); + box-shadow: + 0 0 0 1px color.adjust(mixins.$grey900, $alpha: -0.9), + 0 2px 5px -2px color.adjust(mixins.$grey900, $alpha: -0.8); +} + +.fld-new-tab-btn { + background: var(--white) !important; + box-shadow: + 0 0 0 1px #{color.adjust(mixins.$grey900, $alpha: -0.9)}, + 0 2px 5px -2px #{color.adjust(mixins.$grey900, $alpha: -0.8)}; +} + +.fld-tab .settings::before, +.fld-element .settings::before { + margin-block-start: -2px; + font-size: 16px; + opacity: 0.5; +} + +.fld-tab .settings:hover::before, +.fld-tab .settings.active::before, +.fld-element .settings:hover::before, +.fld-element .settings.active::before { + opacity: 1; +} + +.fld-tab { + width: $tabWidth + $base; + max-width: 100%; + padding-inline: 0 $base + 1; + padding-block: 0 $base; + box-sizing: border-box; + + .tabs { + margin-block: -10px 0; + margin-inline: -12px; + padding-block: 10px 0; + padding-inline: 12px; + overflow: hidden; + display: flex; + + .tab { + display: flex; + align-items: center; + gap: var(--xs); + max-width: calc(100% - 10px); + box-sizing: border-box; + padding-block: 8px; + padding-inline: $tabPadding; + border-radius: var(--radius-md) var(--radius-md) 0 0; + + body:not(.dragging) &.draggable { + cursor: move; + cursor: grab; + } + } + } + + .fld-tab__name { + margin-block: 0; + font-weight: var(--font-weight-regular); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .fld-tabcontent { + padding: $tabPadding; + border-start-start-radius: 0; + border-start-end-radius: var(--radius-md); + border-end-end-radius: var(--radius-md); + border-end-start-radius: var(--radius-md); + + & > .fld-element, + & > .fld-add-btn { + &:not(:first-child) { + margin-block-start: var(--s); + } + } + } + + &.fld-insertion { + .tabs .tab, + .fld-tabcontent { + margin: -2px; + border: 2px dashed var(--border-hairline); + box-shadow: none; + @include workspace-bg; + } + + .tabs .tab { + background-position: -1px -1px; + } + + .fld-tabcontent { + background-position: -1px -13px; + } + } +} + +.fld-tab-caboose { + min-height: 24px; +} + +.fld-element { + position: relative; + display: flex; + align-items: center; + padding: var(--s); + gap: var(--s); + box-shadow: inset 0 0 0 1px var(--border-hairline); + border-radius: var(--radius-md); + background-color: var(--white); + + body:not(.dragging) & { + cursor: move; + cursor: grab; + } + + &.fld-insertion { + box-sizing: border-box; + border: 2px dashed var(--border-hairline); + border-radius: var(--radius-md); + background: none; + box-shadow: none; + } + + &.draghelper { + @include mixins.shadow; + } + + &.fld-field { + color: var(--fg-subtle); + background-color: var(--gray-100); + + &:not(.draghelper, :focus) { + box-shadow: none; + } + + .field-name { + display: flex; + flex-direction: column; + gap: var(--xs); + } + } + + .fld-element-icon { + text-align: center; + + &, + svg { + width: 16px; + height: 16px; + } + + svg { + @include mixins.svg-mask(var(--ui-control-color)); + } + } + + .field-name { + flex: 1; + overflow: hidden; + + .fld-element-label, + .fld-attribute { + flex: 1; + display: flex; + align-items: center; + gap: var(--xs); + } + + .fld-element-label h4, + .fld-attribute .smalltext { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .fld-element-label h4 { + font-weight: normal; + color: var(--text-color); + margin: 0; + } + } +} + +.fld-hr, +.fld-br { + position: relative; + flex: 1; + display: flex; + justify-content: center; + + &::before { + position: absolute; + display: block; + inset-block-start: calc(50% - 2px); + inset-inline-start: 0; + width: 100%; + height: 4px; + content: ''; + font-size: 0; + border-radius: 2px; + } + + .smalltext { + position: relative; + display: flex; + justify-content: center; + align-items: center; + background-color: var(--gray-100); + border-radius: var(--radius-lg); + padding-block: 0; + padding-inline: var(--s); + height: var(--touch-target-size); + } +} + +.fld-hr::before { + background-color: var(--gray-100); +} + +.fld-br::before { + background-image: repeating-linear-gradient( + to right, + var(--gray-100), + var(--gray-100) calc(100% / 19), + transparent calc(100% / 19), + transparent calc(100% / 9.5), + var(--gray-100) calc(100% / 9.5) + ); +} + +.fld-element-settings-body { + flex: 1; + margin-block: -24px 0; + margin-inline: var(--neg-padding); + padding-block: 24px; + padding-inline: var(--padding); + overflow: hidden auto; + position: relative; + + hr { + margin-inline: -24px; + } +} + +.fld-element-settings-footer { + position: relative; + display: flex; + flex-direction: row; + margin-block: 0 -24px; + margin-inline: var(--neg-padding); + padding-block: 5px; + padding-inline: var(--padding); + @include mixins.pane; + background-color: var(--gray-050); + z-index: 3; + + & > .ee-site-select { + flex: 1; + } + + & > .btn { + margin-inline-start: 5px; + } + + & > .spinner { + margin-inline: 0 var(--neg-padding); + margin-block: 0; + } +} + +// thumbnail management +.thumb-management { + margin-block: var(--xl); + + .field:first-child { + margin-inline-end: var(--xl); + } +} + +// card view designer +.card-view-designer { + container: cvd / inline-size; +} + +.cvd-container { + display: grid; + position: relative; + overflow: hidden; + box-shadow: none; + gap: var(--xl); +} + +@container cvd (width > 37.5rem) { + .cvd-container { + grid-template-columns: 1fr 2fr; + } +} + +.cvd-library { + .draggable { + display: flex; + } +} + +.cvd-preview-container { + padding: var(--xl); + border: 1px solid #{color.adjust(mixins.$inputColor, $alpha: -0.75)} !important; + border-radius: var(--radius-sm); + display: grid; + height: 100%; + align-items: center; +} + +.cvd-preview { + &:not(.loading) .spinner { + display: none; + } +} + +.cvd-thumbnail { + --icon-size: 2rem; + --icon-color: var(--gray-300); + width: 100%; + aspect-ratio: 4/3; + display: flex; + justify-content: center; + align-items: center; + background-color: var(--gray-150); + border-radius: var(--radius-md); +} + +.card-placeholder { + display: inline-block; + border: 1px dashed mixins.$grey300; + border-radius: var(--radius-sm); + padding-block: 0.1em; + padding-inline: 0.5em; +} + +.field.cvd-field { + margin-block-start: 0.2em !important; + margin-inline-start: 0.5em; +} diff --git a/packages/craftcms-legacy/cp/src/css/_tokens.scss b/packages/craftcms-legacy/cp/src/css/_tokens.scss new file mode 100644 index 00000000000..9aea3d9a8d0 --- /dev/null +++ b/packages/craftcms-legacy/cp/src/css/_tokens.scss @@ -0,0 +1,131 @@ +:root { + /* + Colors + */ + + /* Background */ + --bg-primary: var(--red-600); + --bg-secondary: var(--gray-500); + --bg-selection-light: var(--gray-200); + --bg-selection-dark: var(--gray-500); + --bg-error: var(--red-100); + --bg-warning: var(--amber-100); + --bg-success: var(--teal-100); + --bg-notice: var(--sky-100); + --bg-enabled: var(--teal-550); + --bg-pending: var(--orange-400); + --bg-disabled: var(--red-600); + + /* Foreground */ + --fg-subtle: var(--gray-550); + --fg-error: #d81f23; // Pretty close to --red-600 but not quite + --fg-warning: var(--amber-700); + --fg-success: var(--teal-700); + --fg-notice: var(--sky-700); + --fg-input: hsl(212deg 25% 50%); + + /* Borders */ + --border-primary: var(--red-600); + --border-secondary: var(--gray-500); + --border-hairline: rgb(from var(--gray-800) r g b / 10%); + --border-hairline-medium: #cfd8e3; + --border-hairline-dark: rgb(from hsl(210deg 10% 53%) r g b / 50%); + --border-error: var(--red-300); + --border-warning: var(--amber-300); + --border-warning-emphasis: var(--amber-600); + --border-success: var(--teal-300); + --border-notice: var(--sky-300); + + /* Focus */ + --focus-outline-light: var(--blue-300); + --focus-outline-medium: var(--focus-ring-color, #0284c7); + --focus-outline-dark: #0f74b1; + + /* + Focus Rings + */ + --focus-ring-alpha: 0.85; + --focus-ring-light: + 0 0 0 1px hsl(from var(--focus-outline-light) h s calc(l + 10)), + 0 0 0 3px rgb(from var(--focus-outline-light) r g b / 97%); + --focus-ring-medium: + 0 0 0 1px hsl(from var(--focus-outline-medium) h s calc(l + 10)), + 0 0 0 3px rgb(from var(--focus-outline-medium) r g b / 97%); + --focus-ring-dark: + 0 0 0 1px hsl(from var(--focus-outline-dark) h s calc(l + 20)), + 0 0 0 3px rgb(from var(--focus-outline-dark) r g b / 97%); + --focus-ring: var(--focus-ring-medium); + --focus-ring-outset: + 0 0 0 1px currentcolor, 0 0 0 3px var(--focus-outline-medium), + 0 0 6px 2px + hsl(from var(--focus-outline-medium) h s l / var(--focus-ring-alpha)); + --focus-ring-inner: + inset 0 0 0 1px var(--focus-outline-medium), + inset 0 0 0 3px + hsl(from var(--focus-outline-medium) h s l / var(--focus-ring-alpha)); + --focus-ring-inner-light: + inset 0 0 0 1px var(--focus-outline-light), + inset 0 0 0 3px + hsl(from var(--focus-outline-light) h s l / var(--focus-ring-alpha)); + + /* + Border Radius + */ + --radius-sm: 3px; + --radius-md: 4px; + --radius-lg: 5px; + --radius-full: calc(infinity * 1px); + --radius-circle: 50%; + + /* + Sizing + */ + --size-touch-target: calc(24rem / 16); + --size-icon: 1rem; + --size-line-height: 1.42em; + + /* + Spacing + */ + --2xs: calc(2rem / 16); + --xs: calc(4rem / 16); + --s: calc(8rem / 16); + --m: calc(14rem / 16); + --l: calc(18rem / 16); + --xl: calc(24rem / 16); + --padding: var(--xl); + --neg-padding: calc(var(--xl) * -1); + + /* + Components + */ + + /* UI Controls */ + --ui-control-fg: var(--fg-subtle); + --ui-control-fg-hover: var(--gray-600); + --ui-control-fg-active: var(--gray-700); + --ui-control-bg: rgb(from var(--fg-input) r g b / 25%); + --ui-control-bg-static: var(--ui-control-bg); + --ui-control-bg-hover: rgb(from var(--fg-input) r g b / 30%); + --ui-control-bg-active: rgb(from var(--fg-input) r g b / 50%); + --ui-control-border: var(--ui-control-fg); + --ui-control-radius: var(--radius-lg); + --ui-control-height: calc(34rem / 16); + --ui-control-height-small: calc(30rem / 16); + + /* Sidebars */ + --sidebar-bg: var(--gray-150); + + /* Nav Item */ + --nav-item-indicator-size: var(--xs); + --nav-item-badge-bg: var(--fg-subtle); + --nav-item-badge-fg: var(--white); + --nav-item-fg-active: var(--text-color); + --nav-item-fg-hover: var(--text-color); + --nav-item-bg-active: var(--gray-200); + --nav-item-bg-hover: var(--gray-200); + --nav-item-prefix-width: calc(30rem / 16); + --nav-item-prefix-ratio: 1; + --nav-item-trigger-size: var(--touch-target-size); + --nav-item-gutter-width: calc(10rem / 16); // Left and right padding +} diff --git a/packages/craftcms-legacy/cp/src/js/BaseElementIndex.js b/packages/craftcms-legacy/cp/src/js/BaseElementIndex.js index 18f7f9e0060..d0b9acf8e0a 100644 --- a/packages/craftcms-legacy/cp/src/js/BaseElementIndex.js +++ b/packages/craftcms-legacy/cp/src/js/BaseElementIndex.js @@ -3916,7 +3916,11 @@ Craft.BaseElementIndex = Garnish.Base.extend( }) .appendTo($form); - const $exportSubmit = new Garnish.MultiFunctionBtn($submitBtn); + // Guarded: the modernized Garnish has no MultiFunctionBtn. Without it + // the export button just stays a plain button rather than throwing. + const $exportSubmit = Garnish.MultiFunctionBtn + ? new Garnish.MultiFunctionBtn($submitBtn) + : null; var hud = new Garnish.HUD(this.$exportBtn, $form); @@ -3934,7 +3938,7 @@ Craft.BaseElementIndex = Garnish.Base.extend( } submitting = true; - $exportSubmit.busyEvent(); + $exportSubmit?.busyEvent(); var params = this.getViewParams(); delete params.baseCriteria.offset; @@ -3974,7 +3978,7 @@ Craft.BaseElementIndex = Garnish.Base.extend( }) .finally(() => { submitting = false; - $exportSubmit.successEvent(); + $exportSubmit?.successEvent(); }); }); }, diff --git a/packages/craftcms-legacy/cp/src/js/Craft.js b/packages/craftcms-legacy/cp/src/js/Craft.js index e9f4a70935c..74fe1ae3090 100644 --- a/packages/craftcms-legacy/cp/src/js/Craft.js +++ b/packages/craftcms-legacy/cp/src/js/Craft.js @@ -3032,7 +3032,7 @@ $.extend($.fn, { */ checkboxselect: function () { return this.each(function () { - if (!$.data(this, 'checkboxSelect')) { + if (!$.data(this, 'checkboxSelect') && Garnish.CheckboxSelect) { new Garnish.CheckboxSelect(this, { storageKey: this.getAttribute('data-storage-key'), }); @@ -3053,7 +3053,7 @@ $.extend($.fn, { nicetext: function () { return this.each(function () { - if (!$.data(this, 'nicetext')) { + if (!$.data(this, 'nicetext') && Garnish.NiceText) { new Garnish.NiceText(this); } }); @@ -3268,16 +3268,22 @@ $.extend($.fn, { }, }); -// Override Garnish.NiceText.charsLeftHtml() to be more accessible -Garnish.NiceText.charsLeftHtml = (charsLeft) => { - return Craft.t( - 'app', - 'Characters left: {chars, number}', - { - chars: charsLeft, - } - ); -}; +// Override Garnish.NiceText.charsLeftHtml() to be more accessible. +// Guarded: the modernized Garnish has no NiceText — `craft-input`'s +// `showCharsLeft` covers it — and this runs at module scope, so an +// unguarded assignment aborts the rest of Craft.js on any page where the +// modern namespace owns `window.Garnish`. +if (Garnish.NiceText) { + Garnish.NiceText.charsLeftHtml = (charsLeft) => { + return Craft.t( + 'app', + 'Characters left: {chars, number}', + { + chars: charsLeft, + } + ); + }; +} Garnish.$doc.ready(function () { Craft.initUiElements(); diff --git a/packages/craftcms-legacy/cp/src/js/ElementEditor.js b/packages/craftcms-legacy/cp/src/js/ElementEditor.js index 6778c0d3d6f..e2206c414ed 100644 --- a/packages/craftcms-legacy/cp/src/js/ElementEditor.js +++ b/packages/craftcms-legacy/cp/src/js/ElementEditor.js @@ -97,10 +97,6 @@ Craft.ElementEditor = Garnish.Base.extend( this.$sidebar = this.settings.$sidebar ?? (this.isFullPage ? $('#details .details') : $()); - this.formHost = this.$contentContainer.find( - 'craft-entry-field-layout-form' - )[0]; - this.queue = this._createQueue(); this.previewTokenQueue = this._createQueue(); @@ -1386,7 +1382,7 @@ Craft.ElementEditor = Garnish.Base.extend( console.warn('Couldn’t save draft:', e); reject(e); }); - } else if (this.formHost) { + } else if (this.getFormHost()) { resolve(); } else { this.updateFieldLayout(data) @@ -1911,12 +1907,45 @@ Craft.ElementEditor = Garnish.Base.extend( }); }, + /** + * The `` this editor drives, looked up on + * first use rather than when the editor is constructed. + * + * The host isn't necessarily in the document yet at construction: on a screen + * rendered inside the Vue shell, the legacy ready JS that calls + * `new Craft.ElementEditor()` runs before the content fragment has mounted. + * Capturing it eagerly left it permanently undefined there, so every + * field-layout refresh threw and a nested element — an address, say — could + * never be added. + * + * `$contentContainer` is re-resolved for the same reason while it's still + * empty: it was captured eagerly too, and an empty jQuery set caches just as + * badly as a missing host. + */ + getFormHost() { + if (this.formHost) { + return this.formHost; + } + + if (this.isFullPage && !this.$contentContainer.length) { + this.$contentContainer = this.settings.$contentContainer ?? $('#content'); + } + + this.formHost = this.$contentContainer.find( + 'craft-entry-field-layout-form' + )[0]; + + return this.formHost; + }, + async _afterUpdateFieldLayout(response) { - if (!this.formHost || !response.data.form) { + const formHost = this.getFormHost(); + + if (!formHost || !response.data.form) { throw new Error('Entry Form refresh requires a Form host.'); } - this.formHost.payload = response.data.form; + formHost.payload = response.data.form; const updateTabs = this.settings.updateTabs ?? (this.isFullPage ? (tabs) => Craft.cp.updateTabs(tabs) : null); diff --git a/packages/craftcms-legacy/cp/src/js/UI.js b/packages/craftcms-legacy/cp/src/js/UI.js index 6a48b2bcc70..9c6c039d281 100644 --- a/packages/craftcms-legacy/cp/src/js/UI.js +++ b/packages/craftcms-legacy/cp/src/js/UI.js @@ -125,7 +125,9 @@ Craft.ui = { ) ); - if (config.placeholder || config.showCharsLeft) { + // Guarded: the modernized Garnish has no NiceText, and `craft-input`'s + // own `showCharsLeft` covers it where that namespace is in play. + if ((config.placeholder || config.showCharsLeft) && Garnish.NiceText) { new Garnish.NiceText($input); } @@ -535,7 +537,11 @@ Craft.ui = { if (config.includeSortActions) { new Craft.SortableCheckboxSelect($container); } else { - new Garnish.CheckboxSelect($container); + // Guarded: superseded by the CheckboxSelect component where the + // modernized Garnish owns the namespace. + if (Garnish.CheckboxSelect) { + new Garnish.CheckboxSelect($container); + } if (config.sortable) { const dragSort = new Garnish.DragSort( diff --git a/packages/craftcms-ui/src/components/combobox/combobox-form.browser.test.ts b/packages/craftcms-ui/src/components/combobox/combobox-form.browser.test.ts new file mode 100644 index 00000000000..875b34ecabc --- /dev/null +++ b/packages/craftcms-ui/src/components/combobox/combobox-form.browser.test.ts @@ -0,0 +1,73 @@ +import {beforeEach, expect, it} from 'vite-plus/test'; +import type CraftCombobox from './combobox.js'; +import './combobox.js'; +import '../../styles/cp.css'; + +beforeEach(() => { + document.body.innerHTML = ''; +}); + +/** + * A single-choice combobox in a plain form — the shape a page that posts itself + * uses, rather than going through an Inertia form. + */ +async function fixture( + configure: (control: CraftCombobox) => void = () => {} +): Promise<{control: CraftCombobox; form: HTMLFormElement}> { + const control = document.createElement('craft-combobox') as CraftCombobox; + control.setAttribute('name', 'apiVersion'); + control.options = [ + {label: '2026-01', value: '2026-01'}, + {label: '2026-04', value: '2026-04'}, + ]; + configure(control); + + const form = document.createElement('form'); + form.append(control); + document.body.append(form); + await control.updateComplete; + // Lion adopts a requested `model-value` only once the option naming it has + // registered, so the value lands a tick after the first render. + await new Promise((resolve) => requestAnimationFrame(resolve)); + await control.updateComplete; + + return {control, form}; +} + +const entries = (form: HTMLFormElement) => [...new FormData(form).entries()]; + +it('posts its value under the host name', async () => { + const {control, form} = await fixture((c) => + c.setAttribute('model-value', '2026-01') + ); + + expect(entries(form)).toEqual([['apiVersion', '2026-01']]); + + // Changing the selection changes what the form carries, so a save writes the + // value the field is showing. + control.modelValue = '2026-04'; + await control.updateComplete; + + expect(entries(form)).toEqual([['apiVersion', '2026-04']]); +}); + +it('posts a custom value when it does not match an option', async () => { + const {control, form} = await fixture((c) => { + c.requireOptionMatch = false; + c.setAttribute('model-value', '$SHOPIFY_API_VERSION'); + }); + + expect(entries(form)).toEqual([['apiVersion', '$SHOPIFY_API_VERSION']]); + expect(control.modelValue).toBe('$SHOPIFY_API_VERSION'); +}); + +it('posts nothing while disabled', async () => { + const {control, form} = await fixture((c) => { + c.setAttribute('model-value', '2026-01'); + c.disabled = true; + }); + + await control.updateComplete; + + expect(entries(form)).toEqual([]); +}); diff --git a/packages/craftcms-ui/src/components/combobox/combobox.ts b/packages/craftcms-ui/src/components/combobox/combobox.ts index 569d7266b7d..0fb4e00b07b 100644 --- a/packages/craftcms-ui/src/components/combobox/combobox.ts +++ b/packages/craftcms-ui/src/components/combobox/combobox.ts @@ -271,6 +271,7 @@ export default class CraftCombobox extends HasLabel(LionCombobox) { override updated(changed: Map) { super.updated(changed); + this.#syncFormValue(); // An `aria-labelledby` on the host names a label the consumer renders // itself — a table column heading, say — rather than one in the `label` // slot. Lion rewrites the textbox's own `aria-labelledby` from its (empty) @@ -692,6 +693,39 @@ export default class CraftCombobox extends HasLabel(LionCombobox) { ); } + /** + * Publishes the value for native form submission. + * + * The host carries the `name` and the class declares `formAssociated`, but a + * single-choice combobox never told `ElementInternals` what its value was, so + * it contributed nothing to a native POST — a form read with `FormData`, or a + * page that posts itself rather than going through an Inertia form, saw the + * field as absent and left the old value in place. Multiple choice has its + * own hidden inputs; this is the single-choice equivalent. + */ + #syncFormValue() { + if (this.multipleChoice) { + return; + } + + /** + * `ElementInternals` is the whole mechanism here, so without it there is + * nothing to publish. happy-dom doesn't implement `attachInternals()`, and + * this runs from `updated()` on every render — so an unguarded call made + * rendering a combobox throw outright in any test using that environment. + */ + if (typeof this.attachInternals !== 'function') { + return; + } + + this.internals ??= this.attachInternals(); + + const omit = !this.name || this.disabled || this.fieldsetDisabled; + const value = typeof this.modelValue === 'string' ? this.modelValue : ''; + + this.internals.setFormValue(omit ? null : value); + } + private syncInputs() { if (!this.inputs) { this.inputs = document.createElement('span'); @@ -725,7 +759,11 @@ export default class CraftCombobox extends HasLabel(LionCombobox) { this.modelValue = [...this.initialValues]; this.value = ''; this.syncInputs(); + + return; } + + this.#syncFormValue(); } /** Tracks whether an ancestor `
` has disabled the control. */ diff --git a/packages/craftcms-ui/src/styles/shared/base.css b/packages/craftcms-ui/src/styles/shared/base.css index f6ca749a5c2..0cc8583aabd 100644 --- a/packages/craftcms-ui/src/styles/shared/base.css +++ b/packages/craftcms-ui/src/styles/shared/base.css @@ -204,6 +204,7 @@ Modify with `cp-table--auto` to apply table-layout: auto th, td { + text-align: start; padding-block: var(--_cell-spacing-block); padding-inline: var(--_cell-spacing-inline); position: relative; diff --git a/packages/craftcms-ui/src/utilities/dom.ts b/packages/craftcms-ui/src/utilities/dom.ts index 1df539c333e..6eaec5099ae 100644 --- a/packages/craftcms-ui/src/utilities/dom.ts +++ b/packages/craftcms-ui/src/utilities/dom.ts @@ -22,7 +22,8 @@ export type AppendHtmlDisposer = () => void; export async function appendElementHtml( html: string, parent: HTMLElement, - rejectOnError = false + rejectOnError = false, + before: Node | null = null ): Promise { const appended: Node[] = []; const releases: Array<() => void> = []; @@ -69,7 +70,7 @@ export async function appendElementHtml( ? waitForScript(node, asset.value) : null; - parent.appendChild(node); + parent.insertBefore(node, before); if ( asset && @@ -182,12 +183,22 @@ function releaseAsset(key: string, asset: OwnedAsset): void { /** * Appends HTML to the page ``. * + * Inserts ahead of the `craft-head-anchor` marker where the document carries + * one, so assets injected during a client-side visit land in the same band as + * the ones the root view renders — above the control panel stylesheet, which + * stays authoritative in both cases. Without the marker this appends, as before. + * * Returns a disposer that removes the appended nodes when called. */ export async function appendHeadHtml( html: string ): Promise { - return appendElementHtml(html, document.head); + return appendElementHtml( + html, + document.head, + false, + document.head.querySelector('meta[name="craft-head-anchor"]') + ); } /** diff --git a/resources/css/legacy.css b/resources/css/legacy.css new file mode 100644 index 00000000000..025dbb30511 --- /dev/null +++ b/resources/css/legacy.css @@ -0,0 +1,198 @@ +/** +Legacy compat styles + */ +@scope (.cp-legacy-screen) { + .skip-link { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; + border-width: 0; + } + + .field { + margin-block: var(--c-spacing-lg); + } + + table.data { + width: 100%; + } + + /* Tables — `_elements/revisions.twig` and any other legacy `table.data`. + Ported from the legacy stylesheet onto current tokens, because the vars it + used (`--gray-050`, `--light-text-color`, `--padding`) aren't loaded here. */ + + /* The legacy rule also carried negative margins to bleed the table out of a + pane's padding. There's no such pane in this shell — `CpContainer` owns the + gutters — so only the scroll behavior comes across. */ + .tablepane { + overflow-x: auto; + } + + table.data td, + table.data th { + box-sizing: border-box; + padding-inline: var(--c-spacing-md); + position: relative; + } + + table.data th { + font-weight: 700; + } + + table.data thead td, + table.data thead th { + background-color: var(--c-color-neutral-fill-quiet); + cursor: default; + padding-block: var(--c-spacing-sm); + vertical-align: middle; + white-space: nowrap; + width: auto; + } + + table.data thead:first-child tr:first-child th:first-child { + border-start-start-radius: var(--c-radius-sm); + } + + table.data thead:first-child tr:first-child th:last-child { + border-start-end-radius: var(--c-radius-sm); + } + + table.data tbody td, + table.data tbody th { + max-width: 33vw; + padding-block: var(--c-spacing-sm); + } + + table.data tbody tr:not(.disabled):hover td, + table.data tbody tr:not(.disabled):hover th { + background-color: var(--c-color-neutral-fill-quiet); + } + + /* Revision rows are focusable (`tabindex="0"`), so a focused row has to sit + above its neighbours' borders. */ + table.data tbody tr:not(.disabled):focus { + position: relative; + z-index: 1; + } + + /* Transparent on purpose, as in the legacy sheet: it reserves the row's + border box so selecting a row can colour it without shifting the layout. */ + table.data thead + tbody tr td, + table.data thead + tbody tr th, + table.data tr + tr td, + table.data tr + tr th { + border-block-start: 1px solid transparent; + } + + /* Narrow viewports: legacy JS adds `.collapsed`, and each cell's `data-title` + becomes its inline label. */ + table.collapsed tbody [data-title] { + margin-inline-end: 0; + } + + table.collapsed tbody [data-title]::before { + content: attr(data-title) ": "; + font-weight: 700; + margin-inline-end: 5px; + } + + /* Empty state — "This entry doesn't have revisions." */ + .zilch { + color: var(--c-text-quiet); + font-size: 20px; + line-height: 24px; + padding-block: 100px; + padding-inline: 0; + text-align: center; + } + + .cp-details { + padding: var(--c-spacing-md); + } + + .slideout-screen__details { + padding: var(--c-spacing-md); + } + + /* Draft notice — the provisional-draft banner the legacy element editor puts + in `#content-notice`, with its icon and "Discard changes" button. Ported + onto current tokens: the legacy rule's blues (`--blue-600`/`--blue-800`, + plus `color.adjust()` on the SCSS `$blue*` variables) map to the accent + group, which also means the notice follows dark mode rather than staying + light-on-light. */ + + /* The legacy rule also styled `.so-notice > .draft-notice`, bleeding the + notice out of a slideout's padding with negative margins and a gradient. + Slideouts don't render through this shell, so that branch isn't carried + over. */ + .draft-notice { + display: flex; + align-items: center; + place-content: stretch center; + gap: var(--c-spacing-md); + color: var(--c-color-accent-on-quiet); + } + + #content-notice .draft-notice { + display: inline-flex; + justify-content: flex-start; + } + + .draft-notice p { + flex: 1; + margin: 0; + } + + .draft-notice .draft-icon { + position: relative; + flex-shrink: 0; + width: 34px; + height: 34px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 100%; + border: 2px solid var(--c-color-accent-border-quiet); + box-sizing: border-box; + /* Lifts the icon off whatever sits behind the notice. */ + box-shadow: 0 1px 1px 1px var(--c-surface-default); + } + + /* The glyph itself comes from the icon font, so it needs the colour forced + past the font's own rule — as in the legacy stylesheet. */ + .draft-notice .draft-icon::before { + position: relative; + inset-inline-start: 1px; + color: var(--c-color-accent-on-quiet) !important; + font-size: 17px; + } + + .draft-notice .draft-icon::after { + content: ""; + font-size: 0; + position: absolute; + inset: -2px; + border-radius: 100%; + box-shadow: inset 0 2px 0 var(--c-color-accent-border-quiet); + } + + .draft-notice .discard-changes-btn { + margin-inline-start: var(--c-spacing-sm); + background-color: transparent !important; + color: var(--c-color-accent-on-quiet) !important; + border: 2px solid var(--c-color-accent-border-normal) !important; + } + + /* The legacy rule darkened the border in two steps, hover then active. The + accent group has one step past `normal`, so both share it. */ + .draft-notice .discard-changes-btn:hover, + .draft-notice .discard-changes-btn:focus, + .draft-notice .discard-changes-btn:active { + border-color: var(--c-color-accent-border-loud); + } +} diff --git a/resources/js/common/composables/useAppLayout.ts b/resources/js/common/composables/useAppLayout.ts index 5d03c6c7d87..fc787cb40a7 100644 --- a/resources/js/common/composables/useAppLayout.ts +++ b/resources/js/common/composables/useAppLayout.ts @@ -20,6 +20,8 @@ export interface UseAppLayoutOptions { subnavActions?: Array; /** Caps and centres the content column. See `ScreenProps.contentMaxWidth`. */ contentMaxWidth?: boolean | string; + /** Restores Craft 5's `#main-form`/`#page-container`/`#toolbar`. See `ScreenProps.legacyIds`. */ + legacyIds?: boolean; onSave?: (options?: FormSaveOptions) => void; } diff --git a/resources/js/common/layouts/screens/PageScreen.vue b/resources/js/common/layouts/screens/PageScreen.vue index ef393a62f40..2f5dadbf92a 100644 --- a/resources/js/common/layouts/screens/PageScreen.vue +++ b/resources/js/common/layouts/screens/PageScreen.vue @@ -152,6 +152,7 @@ const hasFooter = computed( () => Boolean(props.form) || + Boolean(props.fullPageForm) || regions.has('content-footer') || regions.has('additional-buttons') ); @@ -193,6 +194,19 @@ emit('save', options); } + /** + * A Vue page drives saving through its Inertia form, so the native submit is + * cancelled. A bridged legacy screen has no such form: it posts to the + * current URL and the hidden `action` input in its own content names the + * controller action — the same contract Craft 5's page form used. + */ + function onSubmit(event: Event): void { + if (props.form) { + event.preventDefault(); + save(); + } + } + // Announce flash messages to screen readers. const {announce} = useAnnouncer(); const {errorFlash, successFlash} = useFlash(); @@ -229,11 +243,15 @@
-
+
@@ -333,7 +354,15 @@ - + +
+ +
+
-