From 6bc57ed2a2f740b76e5679d680335c91517b24bf Mon Sep 17 00:00:00 2001 From: Peter Kurhajec <61538034+PTKu@users.noreply.github.com> Date: Fri, 12 Jun 2026 12:25:06 +0200 Subject: [PATCH] feat(sandbox): refurbish ix-integration-blazor demo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit App was stuck mid-migration: Bootstrap commented out but markup, jQuery, and ix-bootstrap bundle still in place — broken styling misrepresented what AXSharp + Operon can do. Rebuilt as a customer demo for PLC programmers, fully offline for the hardware rig. - replace Bootstrap remnants with Tailwind 4 + Operon components, light/dark/system theming via Operon CSS variables - consolidate 12 standalone pages into story chapters: /rendering, /layouts, /customize, /integrate - add landing hero: weather.st declaration beside its live rendered control - add first PresentationTemplate consumer: SVG gauge template for Measurement twin (needle=Acquired, scale=Min/Max, color=Result), culture-safe SVG coordinates - drop Showdown CDN script; ST snippets render as static pre/code panels - sync integration-sandbox-showcase spec, archive openspec change --- .../.openspec.yaml | 2 + .../design.md | 92 + .../proposal.md | 35 + .../integration-sandbox-showcase/spec.md | 91 + .../tasks.md | 42 + .../integration-sandbox-showcase/spec.md | 95 + .../Components/IxComponentView.razor | 24 +- .../Components/MeasurementServiceView.razor | 14 +- .../Templates/MeasurementGaugeView.razor | 73 + .../ix-integration-blazor/Pages/Arrays.razor | 4 - .../Pages/AutoRendering.razor | 70 - .../Pages/ClassInjecting.razor | 23 - .../Pages/Customize.razor | 109 + .../ix-integration-blazor/Pages/Error.cshtml | 47 +- .../ix-integration-blazor/Pages/Index.razor | 81 +- .../Pages/Integrate.razor | 95 + .../ix-integration-blazor/Pages/Layouts.razor | 125 + .../Pages/Localizations.razor | 6 - .../Pages/Measurement.razor | 70 - .../Pages/Pollings/Polling.cs | 13 - .../Pages/Pollings/Polling.razor | 35 - .../Pages/Rendering.razor | 120 + .../Pages/RenderingExamples.razor | 40 - .../Pages/ShadowProperties.razor | 8 - .../Pages/StackedLayout.razor | 51 - .../Pages/TabLayout.razor | 51 - .../ix-integration-blazor/Pages/Test.razor | 10 - .../Pages/WrappedLayout - Copy.razor | 51 - .../Pages/_Layout.cshtml | 25 +- .../ix-integration-blazor/Program.cs | 1 + .../{TopRow.razor => CultureSelect.razor} | 25 +- .../Shared/MainLayout.razor | 18 +- .../Shared/MainLayout.razor.css | 70 - .../Shared/NavMenu.razor | 131 +- .../Shared/NavMenu.razor.css | 62 - .../Shared/ShowcaseSection.razor | 44 + .../ix-integration-blazor/Shared/Theme.razor | 16 + .../Shared/TopRow.razor.css | 13 - .../ix-integration-blazor/ThemeService.cs | 23 + .../ix-integration-blazor/tailwind.ps1 | 2 +- .../ix-integration-blazor/wwwroot/css/App.css | 53 +- .../wwwroot/css/tailwind/tailwind.css | 2793 +++++------------ .../ix-integration-blazor/wwwroot/js/theme.js | 22 + .../integration/ix-integration-plc/apax.yml | 2 +- 44 files changed, 1913 insertions(+), 2864 deletions(-) create mode 100644 openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/.openspec.yaml create mode 100644 openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/design.md create mode 100644 openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/proposal.md create mode 100644 openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/specs/integration-sandbox-showcase/spec.md create mode 100644 openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/tasks.md create mode 100644 openspec/specs/integration-sandbox-showcase/spec.md create mode 100644 src/sanbox/integration/ix-integration-blazor/Components/Templates/MeasurementGaugeView.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/Arrays.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/AutoRendering.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/ClassInjecting.razor create mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/Customize.razor create mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/Integrate.razor create mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/Layouts.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/Localizations.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/Measurement.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/Pollings/Polling.cs delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/Pollings/Polling.razor create mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/Rendering.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/RenderingExamples.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/ShadowProperties.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/StackedLayout.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/TabLayout.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/Test.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Pages/WrappedLayout - Copy.razor rename src/sanbox/integration/ix-integration-blazor/Shared/{TopRow.razor => CultureSelect.razor} (68%) delete mode 100644 src/sanbox/integration/ix-integration-blazor/Shared/MainLayout.razor.css delete mode 100644 src/sanbox/integration/ix-integration-blazor/Shared/NavMenu.razor.css create mode 100644 src/sanbox/integration/ix-integration-blazor/Shared/ShowcaseSection.razor create mode 100644 src/sanbox/integration/ix-integration-blazor/Shared/Theme.razor delete mode 100644 src/sanbox/integration/ix-integration-blazor/Shared/TopRow.razor.css create mode 100644 src/sanbox/integration/ix-integration-blazor/ThemeService.cs create mode 100644 src/sanbox/integration/ix-integration-blazor/wwwroot/js/theme.js diff --git a/openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/.openspec.yaml b/openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/.openspec.yaml new file mode 100644 index 000000000..8fe205551 --- /dev/null +++ b/openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-06-12 diff --git a/openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/design.md b/openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/design.md new file mode 100644 index 000000000..e8beeb3bd --- /dev/null +++ b/openspec/changes/archive/2026-06-12-refurbish-sandbox-blazor-operon/design.md @@ -0,0 +1,92 @@ +# Design — Refurbish integration sandbox Blazor app to Operon + Tailwind + +## Context + +`src/sanbox/integration/ix-integration-blazor` is a Blazor Server app that demonstrates `RenderableContentControl` against the `ix-integration-plc` twin. It is mid-migration: + +- `Pages/_Layout.cshtml:11` — Bootstrap CSS link is commented out; `css/tailwind/tailwind.css` (compiled Tailwind 4 output) is linked instead. +- `Pages/_Layout.cshtml:31-32` — `ix-bootstrap.bundle.min.js` and jQuery are still loaded from `AXSharp.Presentation.Blazor.Controls` static assets. +- `Shared/NavMenu.razor`, `Shared/TopRow.razor`, `Shared/MainLayout.razor` — still pure Bootstrap/Blazor-template markup (`navbar`, `collapse`, `nav-item`, `form-control`, `oi oi-*` open-iconic icons, `page`/`sidebar` CSS). +- Pages use scattered Bootstrap classes: `btn btn-outline-primary` (StackedLayout, TabLayout, WrappedLayout - Copy), `container`/`row` (AutoRendering, RenderingExamples), `card` (Components/IxComponentView). +- Tailwind build pipeline exists: `package.json` (@tailwindcss/cli), `tailwind.ps1` (`App.css` → `wwwroot/css/tailwind/tailwind.css`), `wwwroot/css/operon-variables.css` already copied in but not imported. +- `Inxton.Operon` NuGet package already referenced in the csproj; the renderable-content templates in `AXSharp.Presentation.Blazor.Controls` already render through `Operon.Components.BaseInput`, so the auto-generated UI is Operon-styled — only the host shell and page chrome are not. + +The reference implementation is `src/AXSharp.blazor/tests/sandbox/IxBlazor.App`, which completed the same migration: `_Host.cshtml` loads Operon CSS from `/_content/Inxton.Operon/css/momentum.css`, `MainLayout`/`NavMenu` are Tailwind, `Theme.razor` + `wwwroot/js/theme.js` implement light/dark/system toggle via `data-theme` attribute, and `Operon.Icons.HeroIcon` is used for icons. + +## Goals / Non-Goals + +**Audience:** customer demo aimed at PLC programmers — people who will read the ST declarations and judge whether RenderableContentControl saves them UI work. Pages must pair the live control with the declaration that produced it. + +**Goals:** +- Zero Bootstrap: no Bootstrap classes, no `ix-bootstrap.bundle.min.js`, no jQuery, no open-iconic. +- App shell and every demo page styled with Tailwind utilities, preferring Operon components (`BaseInput`, `Tab`/`TabPage`, `HeroIcon`) and Operon CSS variables over hand-rolled styles. +- Each page reads as a deliberate showcase of one `RenderableContentControl` capability: title, short explanation, live control, and the ST/code snippet in a styled panel. +- Full capability coverage: add demo pages for template overrides (`PresentationTemplate`), the presentation-type pipeline (Base/Manual/Service), and control parameters (`HideLabel`, `Class`/`LayoutClass`/`LayoutChildrenClass`) — implemented host-side only. +- Fully offline: no CDN or external network dependency; demo must run on the hardware rig without internet. +- Light/dark theming via Operon variables with a visible toggle. +- Compelling first impression: a redesigned Index/landing page that explains what RenderableContentControl does and links to the scenarios. + +**Non-Goals:** +- No changes to `AXSharp.Presentation.Blazor.Controls`, the connector, code generators, or PLC twin projects (`ix-integration-plc`, `ix-integration-library`) — new scenarios are chosen so existing twin types suffice. +- No work on `IxBlazor.App` or the `probes/ax-blazor-1` sandboxes; no sandbox convergence effort. +- No automated visual-regression tooling. + +## Decisions + +1. **Load Operon CSS from the NuGet static assets, mirror IxBlazor.App's `_Host.cshtml`.** + `_Layout.cshtml` will link `/_content/Inxton.Operon/css/momentum.css` plus the locally compiled `css/tailwind/tailwind.css` for page-level utilities. Alternative considered: compiling everything into one local CSS — rejected because IxBlazor.App's split is the proven pattern and keeps Operon styling updatable via package bump. + +2. **Keep the existing local Tailwind pipeline; fix its input.** + `App.css` becomes the Tailwind source (`@import "tailwindcss"; @source "./"; @import "./operon-variables.css"; @custom-variant dark ...`), matching IxBlazor.App's `tailwind.css` source file. `tailwind.ps1` already targets `App.css` → `wwwroot/css/tailwind/tailwind.css`, so only the file content changes. The compiled output is committed, as elsewhere in the repo. Alternative: switch to MSBuild-integrated Tailwind — rejected as out of scope; repo convention is the ps1 + committed output. + +3. **Port `Theme.razor` + `theme.js` from IxBlazor.App rather than reinventing.** + Same `data-theme` attribute mechanism, same light/dark/system tri-state with `HeroIcon` sun/moon/computer-desktop icons. The Operon dark variant (`@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *))`) keys off this attribute. + +4. **App shell layout: top navbar with five story links.** + Replace the `page`/`sidebar` template structure with IxBlazor.App's pattern — a top header bar (brand, nav links, culture selector, theme toggle) and a centered `max-w-screen-xl` content container. Navigation is exactly five destinations in narrative order: Home, Rendering, Layouts, Customize, Integrate (see decision 10). No grouping taxonomy, no collapse toggle, no scrollable link row. Alternative: keep the sidebar and restyle it — rejected; the top-bar pattern matches the sibling sandbox and removes the collapse-toggle JS dependency. + +5. **Shared `ShowcaseSection` scaffolding component with static code snippets — Showdown and its CDN script removed.** + A small shared component (in `Shared/`) providing the repeated section chrome: section title, description slot, live-demo panel, and a collapsible "Code" panel. Chapter pages (decision 10) compose many of these. The code panel takes the ST snippet as a plain string (or `RenderFragment`) and renders it directly into a Tailwind-styled `
` block — no runtime markdown conversion, no JS interop, no `showdown.min.js` from cdnjs. Rationale: the demo must run offline on the hardware rig, and a CDN script is a hard online dependency; the snippets are static text known at build time, so runtime conversion adds nothing. Alternative considered: self-hosting Showdown — still dead weight for static content.
+
+6. **Icons: `Operon.Icons.HeroIcon` everywhere open-iconic was used.**
+   Nav links get meaningful icons (home, squares for layouts, clock for polling, language for localizations, etc.) instead of the uniform `oi-plus`.
+
+7. **Culture selector (`TopRow.razor`) becomes a Tailwind-styled `` (en-US, sk-SK, es-ES), logic unchanged
+- [x] 2.4 Add `Shared/Theme.razor` theme toggle (light/dark/system, HeroIcon sun/moon/computer-desktop) wired to `theme.js`, placed in the header
+
+## 3. Showcase scaffolding
+
+- [x] 3.1 Create `Shared/ShowcaseSection.razor` component: section title, description slot, styled live-demo panel, optional toggleable code panel rendering a static ST snippet string into Tailwind-styled `pre/code` (no Showdown, no JS interop)
+- [x] 3.2 Create the SVG gauge template component (e.g. `Components/Templates/MeasurementGaugeView.razor`): inline SVG arc gauge for the `Measurement` twin — needle from `Acquired`, scale from `Min`/`Max`, color from `Result` enum — Tailwind/Operon-variable styling, resolvable via `PresentationTemplate`
+
+## 4. Landing page (`/`)
+
+- [x] 4.1 Rebuild `Pages/Index.razor` as the "ST in → UI out" hero: static ST declaration of the `weather` class beside the live `RenderableContentControl` of `Entry.Plc.weather`, declared-not-written headline, chapter cards linking Rendering / Layouts / Customize / Integrate
+
+## 5. Chapter pages (compose ShowcaseSection; salvage content + snippets from old pages)
+
+- [x] 5.1 `Pages/Rendering.razor` (`/rendering`): sections for Control vs Display (`weather`), ReadOnce/ReadOnly (`weather_readOnce`/`weather_readOnly`), RenderIgnore matrix (`weather_wrapped`), and presentation pipeline — Base/Manual/Service/Control on `test_example.ixcomponent_instance` with fallback rules explained
+- [x] 5.2 `Pages/Layouts.razor` (`/layouts`): sections for Stack, Wrap, Tabs, UniformGrid (`test_example.primitives_*`, `weather_*`) and GroupBox/Border (`test_example.test_groupbox`/`test_border`), each with its ST declaration snippet
+- [x] 5.3 `Pages/Customize.razor` (`/customize`): sections for gauge template override on a `Measurement` twin (default vs `PresentationTemplate` gauge side by side — live-moving via `Simulate()` — with the custom-template snippet shown), control parameters (`HideLabel`, `Class`/`LayoutClass`/`LayoutChildrenClass` before/after), and localizations (salvage `Localizations.razor` content)
+- [x] 5.4 `Pages/Integrate.razor` (`/integrate`): sections for shadow properties (salvage `ShadowProperties.razor` incl. sync buttons), polling intervals (salvage `Pollings/Polling.razor` interval comparison), arrays (salvage `Arrays.razor`), custom views from external libraries (salvage `RenderingExamples.razor` external-view part), and measurement composed views (salvage `Measurement.razor`)
+- [x] 5.5 Restyle salvaged components: `Components/IxComponentView.razor` (replace Bootstrap `card`), `Components/MeasurementServiceView.razor`
+- [x] 5.6 Delete superseded pages and routes: `AutoRendering.razor`, `StackedLayout.razor`, `WrappedLayout - Copy.razor`, `TabLayout.razor`, `RenderingExamples.razor`, `ShadowProperties.razor`, `Pollings/Polling.razor`, `Arrays.razor`, `ClassInjecting.razor`, `Localizations.razor`, `Measurement.razor`, `Test.razor`
+
+## 6. Verification
+
+- [x] 6.1 Regenerate compiled CSS: `npm install` (if needed) then run `tailwind.ps1` one-shot (without `--watch`) so `wwwroot/css/tailwind/tailwind.css` reflects all class changes; commit output
+- [x] 6.2 Grep gate per spec: no `navbar|btn btn-|form-control|container-fluid|nav-item|oi oi-|bootstrap|showdown|cdnjs|jquery` matches in project `.razor`/`.cshtml` files
+- [x] 6.3 `dotnet build` of `ix-integration-blazor.csproj` succeeds
+- [x] 6.4 Run the app, walk the story (Home → Rendering → Layouts → Customize → Integrate) in light and dark mode; verify every pre-refurbishment scenario appears as a section, theme persists across reload, culture switch still works (PLC data optional — chrome verification sufficient without rig)
+- [x] 6.5 Offline gate: with browser devtools network tab open, confirm no requests leave the app origin / `_content` package assets
diff --git a/openspec/specs/integration-sandbox-showcase/spec.md b/openspec/specs/integration-sandbox-showcase/spec.md
new file mode 100644
index 000000000..ada071246
--- /dev/null
+++ b/openspec/specs/integration-sandbox-showcase/spec.md
@@ -0,0 +1,95 @@
+# integration-sandbox-showcase
+
+## Purpose
+
+Present `RenderableContentControl` capabilities (auto-rendering, layouts, shadow presentation, polling, localization, template overrides, presentation pipeline, control parameters) to PLC programmers through the integration sandbox Blazor app (`ix-integration-blazor`) in a Bootstrap-free, Tailwind + Operon UI with light/dark theming, runnable fully offline against a real PLC.
+
+## Requirements
+
+### Requirement: Bootstrap-free integration sandbox
+The integration sandbox app (`ix-integration-blazor`) SHALL contain no Bootstrap artifacts: no Bootstrap CSS references (active or commented), no Bootstrap utility classes in markup, no `ix-bootstrap.bundle.min.js`, no jQuery, and no open-iconic (`oi oi-*`) icon classes.
+
+#### Scenario: No Bootstrap classes in markup
+- **WHEN** the project's `.razor` and `.cshtml` files are searched for Bootstrap class patterns (`navbar`, `btn btn-`, `form-control`, `container-fluid`, `nav-item`, `oi oi-`, `collapse`)
+- **THEN** no matches are found
+
+#### Scenario: No Bootstrap or jQuery scripts loaded
+- **WHEN** the rendered page's script tags are inspected
+- **THEN** neither `ix-bootstrap.bundle.min.js` nor `jquery-3.6.0.min.js` is loaded
+
+### Requirement: Offline operation
+The app SHALL run without internet access: all stylesheets, scripts, and fonts SHALL be served from the app itself or referenced package static assets, with no CDN or external URLs.
+
+#### Scenario: App runs on an offline rig
+- **WHEN** the app is served on a machine with no internet connectivity and a user navigates all pages
+- **THEN** every page renders fully styled and functional, and the host page contains no external (CDN) resource references
+
+#### Scenario: Code snippets render without runtime conversion
+- **WHEN** a user opens a code panel on any demo page
+- **THEN** the ST snippet is rendered from static pre-rendered content without invoking any JavaScript markdown converter
+
+### Requirement: Tailwind + Operon app shell
+The app shell (layout, navigation, header) SHALL be styled with Tailwind utilities and Operon components, loading Operon CSS from the `Inxton.Operon` package static assets and a locally compiled Tailwind stylesheet whose source imports the Operon CSS variables.
+
+#### Scenario: Stylesheets loaded
+- **WHEN** the app's host page is rendered
+- **THEN** it links `/_content/Inxton.Operon/css/momentum.css` and the locally compiled `css/tailwind/tailwind.css`
+
+#### Scenario: Navigation uses Operon icons
+- **WHEN** the navigation is rendered
+- **THEN** each destination is reachable via a `NavLink` decorated with an `Operon.Icons.HeroIcon` (no open-iconic spans)
+
+### Requirement: Light and dark theming
+The app SHALL support light, dark, and system theme modes driven by the Operon CSS variable system via a `data-theme` attribute, with a user-visible toggle in the header, and the selection SHALL persist across page reloads.
+
+#### Scenario: User switches to dark mode
+- **WHEN** the user selects dark mode from the theme toggle
+- **THEN** the root element carries `data-theme="dark"` and pages, including rendered `RenderableContentControl` content, restyle to dark Operon colors
+
+#### Scenario: Theme persists
+- **WHEN** the user reloads the app after selecting a theme
+- **THEN** the previously selected theme mode is applied
+
+### Requirement: Story-structured navigation
+The app SHALL organize all demos into four chapter pages in narrative order — Rendering (declare & render), Layouts (arrange), Customize, Integrate — reachable from a five-link navigation (Home + four chapters). Each demo SHALL be a section within its chapter, presented with a consistent showcase structure: a section title, a short description of the demonstrated capability, the live rendered control in a styled panel, and (where an ST snippet applies) a toggleable, styled code panel.
+
+#### Scenario: Navigation shows the story
+- **WHEN** the user views the navigation
+- **THEN** it contains exactly Home, Rendering, Layouts, Customize, and Integrate in that order
+
+#### Scenario: Layout section rendered
+- **WHEN** a user opens the Layouts chapter
+- **THEN** each layout (Stack, Wrap, Tabs, UniformGrid, GroupBox/Border) appears as a section with a description, the live `RenderableContentControl` output, and a control revealing the ST declaration snippet in a styled code panel
+
+#### Scenario: All existing scenarios preserved as sections
+- **WHEN** the user walks the four chapters
+- **THEN** every pre-refurbishment demo remains reachable as a section: AutoRendering content (Rendering), Stacked/Wrapped/Tab layouts and rendering examples (Layouts), class injecting and localizations (Customize), Measurement, Shadow presentation, Arrays, and Polling (Integrate)
+
+### Requirement: Capability coverage sections
+The app SHALL include dedicated demo sections for RenderableContentControl capabilities currently undemonstrated, implemented without modifying the PLC twin projects: template override via the `PresentationTemplate` parameter (Customize chapter), the presentation-type pipeline (Base, Manual, Service, Control — Rendering chapter), and host-side control parameters (`HideLabel`, `Class`, `LayoutClass`, `LayoutChildrenClass` — Customize chapter).
+
+#### Scenario: Gauge template override demo
+- **WHEN** the user opens the template-override section of the Customize chapter
+- **THEN** the same `Measurement` twin structure is shown rendered with its default template and with a custom app-defined SVG gauge template (needle from `Acquired`, scale from `Min`/`Max`, color from `Result`) selected via `PresentationTemplate`, side by side
+
+#### Scenario: Presentation pipeline demo
+- **WHEN** the user opens the presentation-pipeline section of the Rendering chapter
+- **THEN** one twin object is rendered under Base, Manual, Service, and Control presentation types with an explanation of the fallback rules
+
+#### Scenario: Control parameters demo
+- **WHEN** the user opens the control-parameters section of the Customize chapter
+- **THEN** a structure is rendered with and without `HideLabel` and with injected `Class`/`LayoutClass`/`LayoutChildrenClass` values, with visible difference
+
+### Requirement: Landing page hero shows ST in, UI out
+The landing page SHALL present a hero that pairs a static ST declaration with the live `RenderableContentControl` rendering of that same structure, communicating that the UI is declared rather than hand-written, and SHALL link to the four chapter pages.
+
+#### Scenario: User opens the app root
+- **WHEN** the user navigates to `/`
+- **THEN** the hero shows the ST declaration of a twin structure side by side with its live rendered control, and chapter links to Rendering, Layouts, Customize, and Integrate
+
+### Requirement: Culture selection preserved
+The header SHALL retain the culture selector (en-US, sk-SK, es-ES) with unchanged switching behavior, styled with Tailwind instead of Bootstrap form classes.
+
+#### Scenario: User changes culture
+- **WHEN** the user selects a different culture in the header selector
+- **THEN** the app navigates to the culture controller and reloads with the selected culture applied
diff --git a/src/sanbox/integration/ix-integration-blazor/Components/IxComponentView.razor b/src/sanbox/integration/ix-integration-blazor/Components/IxComponentView.razor
index 46328df5f..2f6f1bbe2 100644
--- a/src/sanbox/integration/ix-integration-blazor/Components/IxComponentView.razor
+++ b/src/sanbox/integration/ix-integration-blazor/Components/IxComponentView.razor
@@ -1,20 +1,24 @@
-@namespace AXSharp.Presentation.Blazor.Controls.Templates
+@namespace AXSharp.Presentation.Blazor.Controls.Templates
 @inherits RenderableComplexComponentBase
 
-

Should overwrite IxComponent from integration library

+
+

App-defined view (overrides the library view)

-
-

IxBool: @Component.my_bool.Cyclic

-

IxInt: @Component.my_int.Cyclic

-

IxString: @Component.my_string.Cyclic

-
+
+
IxBool
@Component.my_bool.Cyclic
+
IxInt
@Component.my_int.Cyclic
+
IxString
@Component.my_string.Cyclic
+
+
+ +
+
- -@code +@code { public override void ConfigurePolling() { StartPolling(Component); } -} \ No newline at end of file +} diff --git a/src/sanbox/integration/ix-integration-blazor/Components/MeasurementServiceView.razor b/src/sanbox/integration/ix-integration-blazor/Components/MeasurementServiceView.razor index 3fd021716..d85d47a65 100644 --- a/src/sanbox/integration/ix-integration-blazor/Components/MeasurementServiceView.razor +++ b/src/sanbox/integration/ix-integration-blazor/Components/MeasurementServiceView.razor @@ -1,11 +1,15 @@ -@namespace MeasurementExample +@namespace MeasurementExample @inherits RenderableComplexComponentBase -

IxComponentServiceView

+
+

Measurement service view

-

IxBool serviceView: @Component.Min.Cyclic

-

IxInt serviceView: @Component.Acquired.Cyclic

-

IxString serviceView: @Component.Max.Cyclic

+
+
Minimum
@Component.Min.Cyclic
+
Measured
@Component.Acquired.Cyclic
+
Maximum
@Component.Max.Cyclic
+
+
@code { diff --git a/src/sanbox/integration/ix-integration-blazor/Components/Templates/MeasurementGaugeView.razor b/src/sanbox/integration/ix-integration-blazor/Components/Templates/MeasurementGaugeView.razor new file mode 100644 index 000000000..06907c02b --- /dev/null +++ b/src/sanbox/integration/ix-integration-blazor/Components/Templates/MeasurementGaugeView.razor @@ -0,0 +1,73 @@ +@namespace ix_integration_blazor.Components.Templates +@using System.Globalization +@inherits RenderableComplexComponentBase + +
+ @Component?.AttributeName + + + @* track *@ + + @* value arc *@ + + @* needle *@ + + + + +
@Acquired.ToString("0.0")
+ +
+ @Min.ToString("0.0") + @Max.ToString("0.0") +
+ + + @ResultText + +
+ +@code { + private float Min => Component?.Min.Cyclic ?? 0; + private float Max => Component?.Max.Cyclic ?? 0; + private float Acquired => Component?.Acquired.Cyclic ?? 0; + + private double Ratio + { + get + { + var span = Max - Min; + if (span <= 0) return 0; + return Math.Clamp((Acquired - Min) / span, 0d, 1d); + } + } + + private const double Radius = 80; + private static double ArcLength => Math.PI * Radius; + + private double NeedleX => 100 + (Radius - 14) * Math.Cos(Math.PI * (1 - Ratio)); + private double NeedleY => 100 - (Radius - 14) * Math.Sin(Math.PI * (1 - Ratio)); + + private MeasurementExample.Result Result => (MeasurementExample.Result)(Component?.Result.Cyclic ?? 0); + + private string ResultColor => Result switch + { + MeasurementExample.Result.Passed => "var(--color-result-passed)", + MeasurementExample.Result.Failed => "var(--color-result-failed)", + _ => "var(--color-primary)" + }; + + private string ResultText => Result.ToString(); + + // SVG coordinates must not be culture-formatted (sk-SK uses decimal comma) + private static string Inv(double value) => value.ToString("0.##", CultureInfo.InvariantCulture); + + public override void ConfigurePolling() + { + StartPolling(this.Component, PollingInterval); + } +} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Arrays.razor b/src/sanbox/integration/ix-integration-blazor/Pages/Arrays.razor deleted file mode 100644 index d8cd4372f..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/Arrays.razor +++ /dev/null @@ -1,4 +0,0 @@ -@page "/Arrays" - - - diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/AutoRendering.razor b/src/sanbox/integration/ix-integration-blazor/Pages/AutoRendering.razor deleted file mode 100644 index 9adb4dcb9..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/AutoRendering.razor +++ /dev/null @@ -1,70 +0,0 @@ -@page "/AutoRendering" - - -Rendering - -

Rendering

- -

Structure rendering

- -
-
-
-
- Control - can edit - -
-
-
-
- Display - cannot edit - -
-
-
-
- - -

This structure has [ReadOnce()] attribute

-

- It will be read only once at the in a life time to of the application. - This can be set for items or structured that do not change during the run of the application. - This feature aim at saving load on communication with the PLC. -

- - - -

This structure has [ReadOnly()] attribute

-

- The structure values won't be written in the PLC. -

- - - -

--------------------------------

- -

Render ignore(s)

- -

This structures presentation type is Control attribute

-

- Members annotated with [RenderIgnore("Control")] must not be displayed. -

- - - - -

This structures presentation type is Display attribute

-

- Members annotated with [RenderIgnore("Display")] must not be displayed. -

- - -@code { - -} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/ClassInjecting.razor b/src/sanbox/integration/ix-integration-blazor/Pages/ClassInjecting.razor deleted file mode 100644 index 668a2be59..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/ClassInjecting.razor +++ /dev/null @@ -1,23 +0,0 @@ -@page "/classinjecting" -

Css Class Injecting

- - -

Wrap

- - -

Stack

- - - -

Tabs

- \ No newline at end of file diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Customize.razor b/src/sanbox/integration/ix-integration-blazor/Pages/Customize.razor new file mode 100644 index 000000000..cddf52a94 --- /dev/null +++ b/src/sanbox/integration/ix-integration-blazor/Pages/Customize.razor @@ -0,0 +1,109 @@ +@page "/customize" + +Customize — AX# RenderableContentControl + +

Customize

+

+ Auto-generated does not mean one-size-fits-all. Swap the rendered view for your own Razor component, + inject CSS classes into the generated markup, or localize every label — all without touching the PLC code. +

+ + + + Both panels render the same live Measurement twin. The left uses the default generated + form; the right swaps in a custom SVG gauge via the PresentationTemplate parameter. + A template is just a Razor component — the needle follows Acquired, the scale follows + Min/Max, and the color follows the Result enum, live from the PLC. + + +
+
+
Default template
+ +
+
+
PresentationTemplate — gauge
+ +
+
+
+
+ + + + Host-side parameters tune the generated markup per instance: HideLabel drops the labels, + Class wraps the whole control, and LayoutClass/LayoutChildrenClass + inject classes into the generated layout and each of its children. + + +
+
+
Default
+ +
+
+
HideLabel
+ +
+
+
+
Class + LayoutClass + LayoutChildrenClass injected
+ +
+
+
+ + + + Labels come from the PLC string resources and follow the request culture — switch the language in the + header (en-US, sk-SK, es-ES) and the generated UI re-renders localized, including this structure. + + + + + + +@code { + private const string SnippetGauge = @" +@namespace ix_integration_blazor.Components.Templates +@inherits RenderableComplexComponentBase + + + + + +@code { + public override void ConfigurePolling() + => StartPolling(this.Component, PollingInterval); +} + +// usage: +"; + + private const string SnippetParameters = @" + + +"; +} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Error.cshtml b/src/sanbox/integration/ix-integration-blazor/Pages/Error.cshtml index 88d32066b..b928925d1 100644 --- a/src/sanbox/integration/ix-integration-blazor/Pages/Error.cshtml +++ b/src/sanbox/integration/ix-integration-blazor/Pages/Error.cshtml @@ -1,4 +1,4 @@ -@page +@page @model ix_integration_blazor.Pages.ErrorModel @@ -8,34 +8,31 @@ Error - - + - -
-
-

Error.

-

An error occurred while processing your request.

+ +
+

Error.

+

An error occurred while processing your request.

- @if (Model.ShowRequestId) - { -

- Request ID: @Model.RequestId -

- } - -

Development Mode

-

- Swapping to the Development environment displays detailed information about the error that occurred. -

-

- The Development environment shouldn't be enabled for deployed applications. - It can result in displaying sensitive information from exceptions to end users. - For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development - and restarting the app. + @if (Model.ShowRequestId) + { +

+ Request ID: @Model.RequestId

-
+ } + +

Development Mode

+

+ Swapping to the Development environment displays detailed information about the error that occurred. +

+

+ The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Index.razor b/src/sanbox/integration/ix-integration-blazor/Pages/Index.razor index 29737cef2..ae98644ff 100644 --- a/src/sanbox/integration/ix-integration-blazor/Pages/Index.razor +++ b/src/sanbox/integration/ix-integration-blazor/Pages/Index.razor @@ -1,10 +1,79 @@ -@page "/" +@page "/" -Index +AX# RenderableContentControl +
+
+

+ This UI was declared, not written. +

+

+ RenderableContentControl + turns your structured-text declarations into a live, data-bound user interface. + The form on the right is generated at runtime from the PLC class on the left — no UI code involved. +

+
+
+
+
+ ST in — weather.st +
+
{#ix[Container(Layout.Tabs)]}
+CLASS weather
+    VAR PUBLIC
+        GeoLocation : GeoLocation;
+        {#ix[Container(Layout.Wrap)]}
+        Temperature : REAL;
+        Humidity : REAL;
+        Location : STRING;
+        ChillFactor : REAL;
+        Feeling : Feeling;
+    END_VAR
+END_CLASS
+
-

- This application has direct references to the AX# projects, aim at testing, poc, and demostration of AXSharp. - It won't work outside this solution. -

\ No newline at end of file +
+
+ UI out — live from the PLC +
+
+ +
+
+
+ + +
diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Integrate.razor b/src/sanbox/integration/ix-integration-blazor/Pages/Integrate.razor new file mode 100644 index 000000000..5650b77d5 --- /dev/null +++ b/src/sanbox/integration/ix-integration-blazor/Pages/Integrate.razor @@ -0,0 +1,95 @@ +@page "/integrate" +@using AXSharp.Connector + +Integrate — AX# RenderableContentControl + +

Integrate

+

+ Production scenarios: edit safely against a shadow buffer, tune communication per control, + render whole arrays, and reuse component views shipped in external libraries. +

+ + + + ShadowControl edits the twin's in-memory shadow buffer instead of writing straight to the + PLC — collect changes first, commit when ready. The values below live only in the application until + synchronized. + + + + + + + + + Each control decides how often it reads from the PLC via PollingInterval (milliseconds). + The three structures below poll the same kind of data at 500, 100, and 50 ms — watch the + update cadence differ. + + +
+
+
500 ms
+ +
+
+
100 ms
+ +
+
+
50 ms
+ +
+
+
+
Single primitive at 100 ms
+ +
+
+
+ + + + Arrays of structures render without any extra declaration — every element gets the full + layout-aware treatment. + + + + + + + + + A class library can ship Razor views for its twin types; the locator picks them up from any assembly + marked [RenderableBlazorAssembly]. The same ixcomponent type from three ST + namespaces resolves to three different library views — and the application can override any of them + by declaring a view with the same name. + + +
+ + + +
+
+
+ + + + A structure of structures — four Measurement instances, each with its own declared + layout — renders as one coherent view from a single RenderableContentControl. + + + + + + +@code { + private const string SnippetPolling = @" + + +"; +} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Layouts.razor b/src/sanbox/integration/ix-integration-blazor/Pages/Layouts.razor new file mode 100644 index 000000000..f22066044 --- /dev/null +++ b/src/sanbox/integration/ix-integration-blazor/Pages/Layouts.razor @@ -0,0 +1,125 @@ +@page "/layouts" + +Layouts — AX# RenderableContentControl + +

Arrange

+

+ Layout is declared where the data is declared. A [Container(Layout.*)] attribute on a class + or member arranges its children — stacked, wrapped, tabbed, or in a uniform grid — and + [Group(GroupLayout.*)] wraps them in a titled group box or border. No markup required. +

+ + + + Layout.Stack places members vertically, one per row. + + + + + + + + + Layout.Wrap flows members horizontally and wraps to the next line as space runs out. + + + + + + + + + Layout.Tabs renders each member on its own tab page. + + + + + + + + + Layout.UniformGrid distributes members into evenly sized grid cells. + + + + + + + + + [Group(GroupLayout.GroupBox)] frames a structure with a titled box; + [Group(GroupLayout.Border)] draws a plain border. Both combine freely with any container layout. + + +
+
+
GroupBox
+ +
+
+
Border
+ +
+
+
+
+ +@code { + private const string SnippetStack = @" +NAMESPACE Layouts.Stacked + {#ix-attr:[Container(Layout.Stack)]} + {#ix-attr:[Group(GroupLayout.GroupBox)]} + CLASS PUBLIC weather + VAR PUBLIC + Latitude : REAL; + Longitude : REAL; + Altitude : REAL; + Description : STRING; + LongDescription : STRING; + END_VAR + END_CLASS +END_NAMESPACE"; + + private const string SnippetWrap = @" +NAMESPACE Layouts.Wrapped + {#ix-attr:[Container(Layout.Wrap)]} + {#ix-attr:[Group(GroupLayout.GroupBox)]} + CLASS PUBLIC weather + VAR PUBLIC + Latitude : REAL; + Longitude : REAL; + Altitude : REAL; + Description : STRING; + LongDescription : STRING; + END_VAR + END_CLASS +END_NAMESPACE"; + + private const string SnippetTabs = @" +NAMESPACE Layouts.Tabbed + {#ix-attr:[Container(Layout.Tabs)]} + {#ix-attr:[Group(GroupLayout.GroupBox)]} + CLASS PUBLIC weather + VAR PUBLIC + Latitude : REAL; + Longitude : REAL; + Altitude : REAL; + Description : STRING; + LongDescription : STRING; + END_VAR + END_CLASS +END_NAMESPACE"; + + private const string SnippetUniform = @" +{#ix-attr:[Container(Layout.UniformGrid)]} +primitives_uniform: test_primitive;"; + + private const string SnippetGroups = @" +{#ix-attr:[Container(Layout.Stack)]} +{#ix-attr:[Group(GroupLayout.GroupBox)]} +test_groupbox: test_primitive; + +{#ix-attr:[Container(Layout.Stack)]} +{#ix-attr:[Group(GroupLayout.Border)]} +test_border: test_primitive;"; +} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Localizations.razor b/src/sanbox/integration/ix-integration-blazor/Pages/Localizations.razor deleted file mode 100644 index d0e04bc1c..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/Localizations.razor +++ /dev/null @@ -1,6 +0,0 @@ -@page "/localizations" - -Localizations - - diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Measurement.razor b/src/sanbox/integration/ix-integration-blazor/Pages/Measurement.razor deleted file mode 100644 index 28fa873d7..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/Measurement.razor +++ /dev/null @@ -1,70 +0,0 @@ -@page "/Measurement" - -Rendering - - - - - -
-
-
-
- Control - can edit - -
-
-
-
- Display - cannot edit - -
-
-
-
- -
-
-
-
- Control - can edit - -
-
-
-
- Display - cannot edit - -
-
-
-
- -
-
-
-
- Control - can edit - -
-
-
-
- Display - cannot edit - -
-
-
-
- -@code { - -} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Pollings/Polling.cs b/src/sanbox/integration/ix-integration-blazor/Pages/Pollings/Polling.cs deleted file mode 100644 index f7878bed7..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/Pollings/Polling.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ix_integration_plc; -using AXSharp.Connector; - -namespace ix_integration_blazor.Pages.Pollings -{ - public partial class Polling : IDisposable - { - public void Dispose() - { - - } - } -} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Pollings/Polling.razor b/src/sanbox/integration/ix-integration-blazor/Pages/Pollings/Polling.razor deleted file mode 100644 index 6b630bee2..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/Pollings/Polling.razor +++ /dev/null @@ -1,35 +0,0 @@ -@page "/pollings/polling" -@using ix_integration_plc -@using AXSharp.Connector; - - - - -Polling -
- - - -
- - - - - - - - - -@code -{ - - - protected override async Task OnInitializedAsync() - { - Entry.Plc.Connector.SubscriptionMode = ReadSubscriptionMode.Polling; - } - - - - -} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Rendering.razor b/src/sanbox/integration/ix-integration-blazor/Pages/Rendering.razor new file mode 100644 index 000000000..4da4f3137 --- /dev/null +++ b/src/sanbox/integration/ix-integration-blazor/Pages/Rendering.razor @@ -0,0 +1,120 @@ +@page "/rendering" + +Rendering — AX# RenderableContentControl + +

Declare & render

+

+ Every UI on this page is generated at runtime from a PLC class declaration. + The presentation mode decides whether the user can edit values, and attributes in the + ST code control what gets rendered at all. +

+ + + + The same weather structure rendered twice: Control generates editable + inputs that write back to the PLC, Display generates a read-only view. + + +
+
+
Control — can edit
+ +
+
+
Display — read only
+ +
+
+
+
+ + + + [ReadOnce()] reads a member a single time per application lifetime — ideal for values + that never change, saving communication load. [ReadOnly()] renders an input that never + writes back to the PLC. + + +
+
+
Structure with [ReadOnce()] member
+ +
+
+
Structure with [ReadOnly()] member
+ +
+
+
+
+ + + + [RenderIgnore()] excludes a member from rendering — entirely, or only for the + presentation types you name. The structure below declares one member per variant; compare which + ones survive in Control vs Display. + + +
+
+
Control
+ +
+
+
Display
+ +
+
+
+
+ + + + The renderer locates a view component by convention: <type name><presentation>View. + A presentation like Manual-Service is a fallback pipeline — each name is tried in order + until a matching view is found. ixcomponent ships a default (Base) view and a + Service view; no Manual view exists, so the pipeline below falls through to + Service. + + +
+
+
Base — default view
+ +
+
+
Service view
+ +
+
+
Manual-Service — falls back to Service
+ +
+
+
+
+ +@code { + private const string SnippetReadAttributes = @" +{#ix-attr:[ReadOnly()]} +LongDescription : STRING; + +{#ix-attr:[ReadOnce()]} +StartCounter : INT;"; + + private const string SnippetRenderIgnore = @" +{#ix-attr:[RenderIgnore()]} +RenderIgnoreAllToghether : STRING; + +{#ix-attr:[RenderIgnore(""Control"")]} +RenderIgnoreWhenControl : STRING; + +{#ix-attr:[RenderIgnore(""Display"")]} +RenderIgnoreWhenDisplay : STRING; + +{#ix-attr:[RenderIgnore(""Control"", ""ShadowControl"")]} +RenderIgnoreWhenControlAndShadow : STRING; + +{#ix-attr:[RenderIgnore(""Display"", ""ShadowDisplay"")]} +RenderIgnoreWhenDisplayAndShadow : STRING;"; +} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/RenderingExamples.razor b/src/sanbox/integration/ix-integration-blazor/Pages/RenderingExamples.razor deleted file mode 100644 index 784f6cf2f..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/RenderingExamples.razor +++ /dev/null @@ -1,40 +0,0 @@ -@page "/examples" -

RenderingExamples

- -

Custom views from external libraries

- - - - -
-
-
- -
-
- @* *@ -
-
-
-

Grouplayouts

-

GroupBox

- -

Border

- - -

Layouts

-

Stack

- -

Wrap

- -

UniformGrid

- -

Tab

- - - - diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/ShadowProperties.razor b/src/sanbox/integration/ix-integration-blazor/Pages/ShadowProperties.razor deleted file mode 100644 index 7850517b0..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/ShadowProperties.razor +++ /dev/null @@ -1,8 +0,0 @@ -@page "/ShadowProperties" - - - - - diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/StackedLayout.razor b/src/sanbox/integration/ix-integration-blazor/Pages/StackedLayout.razor deleted file mode 100644 index 60fcadc13..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/StackedLayout.razor +++ /dev/null @@ -1,51 +0,0 @@ -@page "/StackedLayout" -@using ix_integration_plc -@inject IJSRuntime JS - - - -Rendering - -

StackLayout

- -

- @text -

- -

- -

- - -
- -
- - - -@code { - - private MarkupString text; - private string code_example = - @" - NAMESPACE Layouts.Stacked - {#ix-attr:[Container(Layout.Stack)]} - {#ix-attr:[Group(GroupLayout.GroupBox)]} - CLASS PUBLIC weather - VAR PUBLIC - Latitude : REAL; - Longitude : REAL; - Altitude : REAL; - Description : STRING; - LongDescription : STRING; - END_VAR - END_CLASS - END_NAMESPACE - "; - - private async Task ShowCode() - { - text = new(await JS.InvokeAsync("converter.makeHtml", code_example)); - } -} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/TabLayout.razor b/src/sanbox/integration/ix-integration-blazor/Pages/TabLayout.razor deleted file mode 100644 index 93c7f66d6..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/TabLayout.razor +++ /dev/null @@ -1,51 +0,0 @@ -@page "/TabLayout" -@using ix_integration_plc -@inject IJSRuntime JS - - - -Rendering - -

StackLayout

- -

- @text -

- -

- -

- - -
- -
- - - -@code { - - private MarkupString text; - private string code_example = - @" - NAMESPACE Layouts.Tabbed - {#ix-attr:[Container(Layout.Tabs)]} - {#ix-attr:[Group(GroupLayout.GroupBox)]} - CLASS PUBLIC weather - VAR PUBLIC - Latitude : REAL; - Longitude : REAL; - Altitude : REAL; - Description : STRING; - LongDescription : STRING; - END_VAR - END_CLASS - END_NAMESPACE - "; - - private async Task ShowCode() - { - text = new(await JS.InvokeAsync("converter.makeHtml", code_example)); - } -} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/Test.razor b/src/sanbox/integration/ix-integration-blazor/Pages/Test.razor deleted file mode 100644 index 82615b953..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/Test.razor +++ /dev/null @@ -1,10 +0,0 @@ -@page "/Test" - -Rendering - - - - - diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/WrappedLayout - Copy.razor b/src/sanbox/integration/ix-integration-blazor/Pages/WrappedLayout - Copy.razor deleted file mode 100644 index c4e102875..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Pages/WrappedLayout - Copy.razor +++ /dev/null @@ -1,51 +0,0 @@ -@page "/WrappedLayout" -@using ix_integration_plc -@inject IJSRuntime JS - - - -Rendering - -

StackLayout

- -

- @text -

- -

- -

- - -
- -
- - - -@code { - - private MarkupString text; - private string code_example = - @" - NAMESPACE Layouts.Wrapped - {#ix-attr:[Container(Layout.Wrap)]} - {#ix-attr:[Group(GroupLayout.GroupBox)]} - CLASS PUBLIC weather - VAR PUBLIC - Latitude : REAL; - Longitude : REAL; - Altitude : REAL; - Description : STRING; - LongDescription : STRING; - END_VAR - END_CLASS - END_NAMESPACE - "; - - private async Task ShowCode() - { - text = new(await JS.InvokeAsync("converter.makeHtml", code_example)); - } -} diff --git a/src/sanbox/integration/ix-integration-blazor/Pages/_Layout.cshtml b/src/sanbox/integration/ix-integration-blazor/Pages/_Layout.cshtml index fe509f3b6..8e2f9c6c3 100644 --- a/src/sanbox/integration/ix-integration-blazor/Pages/_Layout.cshtml +++ b/src/sanbox/integration/ix-integration-blazor/Pages/_Layout.cshtml @@ -1,4 +1,4 @@ -@using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.Web @namespace ix_integration_blazor.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @@ -8,7 +8,8 @@ - @**@ + + @@ -16,23 +17,9 @@ @RenderBody() - @*
*@ - @* *@ - @* An error has occurred. This application may no longer respond until reloaded. *@ - @* *@ - @* *@ - @* An unhandled exception has occurred. See browser dev tools for details. *@ - @* *@ - @* Reload *@ - @* 🗙 *@ - @*
*@ - - - - - + + + diff --git a/src/sanbox/integration/ix-integration-blazor/Program.cs b/src/sanbox/integration/ix-integration-blazor/Program.cs index 21fd45d23..529a27ac1 100644 --- a/src/sanbox/integration/ix-integration-blazor/Program.cs +++ b/src/sanbox/integration/ix-integration-blazor/Program.cs @@ -33,6 +33,7 @@ public static void Main(string[] args) builder.Services.AddSingleton(); builder.Services.AddIxBlazorServices(); builder.Services.AddLocalization(); + builder.Services.AddScoped(); var app = builder.Build(); diff --git a/src/sanbox/integration/ix-integration-blazor/Shared/TopRow.razor b/src/sanbox/integration/ix-integration-blazor/Shared/CultureSelect.razor similarity index 68% rename from src/sanbox/integration/ix-integration-blazor/Shared/TopRow.razor rename to src/sanbox/integration/ix-integration-blazor/Shared/CultureSelect.razor index 93102c80d..8693b2819 100644 --- a/src/sanbox/integration/ix-integration-blazor/Shared/TopRow.razor +++ b/src/sanbox/integration/ix-integration-blazor/Shared/CultureSelect.razor @@ -1,19 +1,14 @@ -@using System.Globalization +@using System.Globalization @inject NavigationManager NavigationManager -
- -
- -
- - -
+ @code { private CultureInfo[] supportedCultures = new[] @@ -41,4 +36,4 @@ { Culture = CultureInfo.CurrentCulture; } -} \ No newline at end of file +} diff --git a/src/sanbox/integration/ix-integration-blazor/Shared/MainLayout.razor b/src/sanbox/integration/ix-integration-blazor/Shared/MainLayout.razor index 16173ace5..16c5ec0d4 100644 --- a/src/sanbox/integration/ix-integration-blazor/Shared/MainLayout.razor +++ b/src/sanbox/integration/ix-integration-blazor/Shared/MainLayout.razor @@ -1,17 +1,11 @@ -@inherits LayoutComponentBase +@inherits LayoutComponentBase -ix-integration-blazor +AX# RenderableContentControl -
- +
+ -
- - -
- @Body -
+
+ @Body
diff --git a/src/sanbox/integration/ix-integration-blazor/Shared/MainLayout.razor.css b/src/sanbox/integration/ix-integration-blazor/Shared/MainLayout.razor.css deleted file mode 100644 index 551e4b276..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Shared/MainLayout.razor.css +++ /dev/null @@ -1,70 +0,0 @@ -.page { - position: relative; - display: flex; - flex-direction: column; -} - -main { - flex: 1; -} - -.sidebar { - background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); -} - -.top-row { - background-color: #f7f7f7; - border-bottom: 1px solid #d6d5d5; - justify-content: flex-end; - height: 3.5rem; - display: flex; - align-items: center; -} - - .top-row ::deep a, .top-row .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - } - - .top-row a:first-child { - overflow: hidden; - text-overflow: ellipsis; - } - -@media (max-width: 640.98px) { - .top-row:not(.auth) { - display: none; - } - - .top-row.auth { - justify-content: space-between; - } - - .top-row a, .top-row .btn-link { - margin-left: 0; - } -} - -@media (min-width: 641px) { - .page { - flex-direction: row; - } - - .sidebar { - width: 250px; - height: 100vh; - position: sticky; - top: 0; - } - - .top-row { - position: sticky; - top: 0; - z-index: 1; - } - - .top-row, article { - padding-left: 2rem !important; - padding-right: 1.5rem !important; - } -} diff --git a/src/sanbox/integration/ix-integration-blazor/Shared/NavMenu.razor b/src/sanbox/integration/ix-integration-blazor/Shared/NavMenu.razor index 945041b19..f185139ab 100644 --- a/src/sanbox/integration/ix-integration-blazor/Shared/NavMenu.razor +++ b/src/sanbox/integration/ix-integration-blazor/Shared/NavMenu.razor @@ -1,85 +1,50 @@ - +
+
+
+ + + + -
- -
- -@code { - private bool collapseNavMenu = true; + - private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null; - - private void ToggleNavMenu() - { - collapseNavMenu = !collapseNavMenu; - } -} +
+ + +
+
+
+
diff --git a/src/sanbox/integration/ix-integration-blazor/Shared/NavMenu.razor.css b/src/sanbox/integration/ix-integration-blazor/Shared/NavMenu.razor.css deleted file mode 100644 index acc5f9f81..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Shared/NavMenu.razor.css +++ /dev/null @@ -1,62 +0,0 @@ -.navbar-toggler { - background-color: rgba(255, 255, 255, 0.1); -} - -.top-row { - height: 3.5rem; - background-color: rgba(0,0,0,0.4); -} - -.navbar-brand { - font-size: 1.1rem; -} - -.oi { - width: 2rem; - font-size: 1.1rem; - vertical-align: text-top; - top: -2px; -} - -.nav-item { - font-size: 0.9rem; - padding-bottom: 0.5rem; -} - - .nav-item:first-of-type { - padding-top: 1rem; - } - - .nav-item:last-of-type { - padding-bottom: 1rem; - } - - .nav-item ::deep a { - color: #d7d7d7; - border-radius: 4px; - height: 3rem; - display: flex; - align-items: center; - line-height: 3rem; - } - -.nav-item ::deep a.active { - background-color: rgba(255,255,255,0.25); - color: white; -} - -.nav-item ::deep a:hover { - background-color: rgba(255,255,255,0.1); - color: white; -} - -@media (min-width: 641px) { - .navbar-toggler { - display: none; - } - - .collapse { - /* Never collapse the sidebar for wide screens */ - display: block; - } -} diff --git a/src/sanbox/integration/ix-integration-blazor/Shared/ShowcaseSection.razor b/src/sanbox/integration/ix-integration-blazor/Shared/ShowcaseSection.razor new file mode 100644 index 000000000..cf3470ce4 --- /dev/null +++ b/src/sanbox/integration/ix-integration-blazor/Shared/ShowcaseSection.razor @@ -0,0 +1,44 @@ +
+
+
+

@Title

+ @if (Description != null) + { +
@Description
+ } +
+ @if (!string.IsNullOrWhiteSpace(Snippet)) + { + + } +
+ + @if (showCode && !string.IsNullOrWhiteSpace(Snippet)) + { +
+
@SnippetTitle
+
@Snippet.Trim()
+
+ } + +
+ @ChildContent +
+
+ +@code { + [Parameter] public string Title { get; set; } = ""; + [Parameter] public RenderFragment? Description { get; set; } + [Parameter] public RenderFragment? ChildContent { get; set; } + [Parameter] public string? Snippet { get; set; } + [Parameter] public string SnippetTitle { get; set; } = "ST declaration"; + + private bool showCode; + + private void ToggleCode() => showCode = !showCode; +} diff --git a/src/sanbox/integration/ix-integration-blazor/Shared/Theme.razor b/src/sanbox/integration/ix-integration-blazor/Shared/Theme.razor new file mode 100644 index 000000000..e567761ec --- /dev/null +++ b/src/sanbox/integration/ix-integration-blazor/Shared/Theme.razor @@ -0,0 +1,16 @@ +@inject ThemeService _themeService + + diff --git a/src/sanbox/integration/ix-integration-blazor/Shared/TopRow.razor.css b/src/sanbox/integration/ix-integration-blazor/Shared/TopRow.razor.css deleted file mode 100644 index de1fae53f..000000000 --- a/src/sanbox/integration/ix-integration-blazor/Shared/TopRow.razor.css +++ /dev/null @@ -1,13 +0,0 @@ -.top-row { - background-color: #f7f7f7; - border-bottom: 1px solid #d6d5d5; - height: 3.5rem; - display: flex; - align-items: center; -} - -@media (max-width: 769px) { - .IAmHereIndicator { - display: none; - } -} diff --git a/src/sanbox/integration/ix-integration-blazor/ThemeService.cs b/src/sanbox/integration/ix-integration-blazor/ThemeService.cs new file mode 100644 index 000000000..13649e21e --- /dev/null +++ b/src/sanbox/integration/ix-integration-blazor/ThemeService.cs @@ -0,0 +1,23 @@ +using Microsoft.JSInterop; + +namespace ix_integration_blazor +{ + public class ThemeService + { + private readonly IJSRuntime _js; + + public ThemeService(IJSRuntime js) => _js = js; + + public ValueTask InitAsync() => + _js.InvokeVoidAsync("themeManager.init"); + + public ValueTask SetLightAsync() => + _js.InvokeVoidAsync("themeManager.setLight"); + + public ValueTask SetDarkAsync() => + _js.InvokeVoidAsync("themeManager.setDark"); + + public ValueTask SetSystemAsync() => + _js.InvokeVoidAsync("themeManager.setSystem"); + } +} diff --git a/src/sanbox/integration/ix-integration-blazor/tailwind.ps1 b/src/sanbox/integration/ix-integration-blazor/tailwind.ps1 index 1e583341a..aa16810c0 100644 --- a/src/sanbox/integration/ix-integration-blazor/tailwind.ps1 +++ b/src/sanbox/integration/ix-integration-blazor/tailwind.ps1 @@ -1 +1 @@ -npx @tailwindcss/cli -i .\wwwroot\css\App.css -o .\wwwroot\css\tailwind\tailwind.css --watch --content ".\**\*.{html,js,jsx,ts,tsx,vue,razor}" +npx @tailwindcss/cli -i .\wwwroot\css\App.css -o .\wwwroot\css\tailwind\tailwind.css --watch --content ".\**\*.{html,cshtml,js,jsx,ts,tsx,vue,razor}" diff --git a/src/sanbox/integration/ix-integration-blazor/wwwroot/css/App.css b/src/sanbox/integration/ix-integration-blazor/wwwroot/css/App.css index 9eaafa193..f5ea8bfc1 100644 --- a/src/sanbox/integration/ix-integration-blazor/wwwroot/css/App.css +++ b/src/sanbox/integration/ix-integration-blazor/wwwroot/css/App.css @@ -1,28 +1,22 @@ @import "tailwindcss"; -@import "../../Operon/operon.css"; -@source "../../Operon/Components"; -@source "../../Operon/Icons"; +@source "./"; +@import "./operon-variables.css"; +@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *)); html, body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } -h1:focus { - outline: none; -} - -a, .btn-link { - color: #0071c1; +.app-nav-link { + @apply flex items-center gap-1.5 rounded-md px-2.5 py-1.5 text-text-light transition hover:bg-primary-light hover:text-primary; } -.btn-primary { - color: #fff; - background-color: #1b6ec2; - border-color: #1861ac; +.app-nav-link.active { + @apply bg-primary-light text-primary font-medium; } -.content { - padding-top: 1.1rem; +h1:focus { + outline: none; } .valid.modified:not([type=checkbox]) { @@ -36,32 +30,3 @@ a, .btn-link { .validation-message { color: red; } - -#blazor-error-ui { - background: lightyellow; - bottom: 0; - box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); - display: none; - left: 0; - padding: 0.6rem 1.25rem 0.7rem 1.25rem; - position: fixed; - width: 100%; - z-index: 1000; -} - - #blazor-error-ui .dismiss { - cursor: pointer; - position: absolute; - right: 0.75rem; - top: 0.5rem; - } - -.blazor-error-boundary { - background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; - padding: 1rem 1rem 1rem 3.7rem; - color: white; -} - - .blazor-error-boundary::after { - content: "An error has occurred." - } diff --git a/src/sanbox/integration/ix-integration-blazor/wwwroot/css/tailwind/tailwind.css b/src/sanbox/integration/ix-integration-blazor/wwwroot/css/tailwind/tailwind.css index 57e158990..a2d2ab0a0 100644 --- a/src/sanbox/integration/ix-integration-blazor/wwwroot/css/tailwind/tailwind.css +++ b/src/sanbox/integration/ix-integration-blazor/wwwroot/css/tailwind/tailwind.css @@ -1,4 +1,4 @@ -/*! tailwindcss v4.1.6 | MIT License | https://tailwindcss.com */ +/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */ @layer properties; @layer theme, base, components, utilities; @layer theme { @@ -7,143 +7,11 @@ "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; - --color-red-50: oklch(97.1% 0.013 17.38); - --color-red-100: oklch(93.6% 0.032 17.717); - --color-red-200: oklch(88.5% 0.062 18.334); - --color-red-300: oklch(80.8% 0.114 19.571); - --color-red-400: oklch(70.4% 0.191 22.216); - --color-red-500: oklch(63.7% 0.237 25.331); - --color-red-600: oklch(57.7% 0.245 27.325); - --color-red-700: oklch(50.5% 0.213 27.518); - --color-red-800: oklch(44.4% 0.177 26.899); - --color-red-900: oklch(39.6% 0.141 25.723); - --color-red-950: oklch(25.8% 0.092 26.042); - --color-orange-50: oklch(98% 0.016 73.684); - --color-orange-100: oklch(95.4% 0.038 75.164); - --color-orange-200: oklch(90.1% 0.076 70.697); - --color-orange-300: oklch(83.7% 0.128 66.29); - --color-orange-400: oklch(75% 0.183 55.934); - --color-orange-500: oklch(70.5% 0.213 47.604); - --color-orange-600: oklch(64.6% 0.222 41.116); - --color-orange-700: oklch(55.3% 0.195 38.402); - --color-orange-800: oklch(47% 0.157 37.304); - --color-orange-900: oklch(40.8% 0.123 38.172); - --color-orange-950: oklch(26.6% 0.079 36.259); - --color-amber-50: oklch(98.7% 0.022 95.277); - --color-amber-100: oklch(96.2% 0.059 95.617); - --color-amber-200: oklch(92.4% 0.12 95.746); - --color-amber-300: oklch(87.9% 0.169 91.605); - --color-amber-400: oklch(82.8% 0.189 84.429); - --color-amber-500: oklch(76.9% 0.188 70.08); - --color-amber-600: oklch(66.6% 0.179 58.318); - --color-amber-700: oklch(55.5% 0.163 48.998); - --color-amber-800: oklch(47.3% 0.137 46.201); - --color-amber-900: oklch(41.4% 0.112 45.904); - --color-amber-950: oklch(27.9% 0.077 45.635); - --color-yellow-500: oklch(79.5% 0.184 86.047); - --color-yellow-600: oklch(68.1% 0.162 75.834); - --color-lime-500: oklch(76.8% 0.233 130.85); - --color-lime-600: oklch(64.8% 0.2 131.684); - --color-green-50: oklch(98.2% 0.018 155.826); - --color-green-100: oklch(96.2% 0.044 156.743); - --color-green-200: oklch(92.5% 0.084 155.995); - --color-green-300: oklch(87.1% 0.15 154.449); - --color-green-400: oklch(79.2% 0.209 151.711); - --color-green-500: oklch(72.3% 0.219 149.579); - --color-green-600: oklch(62.7% 0.194 149.214); - --color-green-700: oklch(52.7% 0.154 150.069); - --color-green-800: oklch(44.8% 0.119 151.328); - --color-green-900: oklch(39.3% 0.095 152.535); - --color-green-950: oklch(26.6% 0.065 152.934); - --color-emerald-50: oklch(97.9% 0.021 166.113); - --color-emerald-100: oklch(95% 0.052 163.051); - --color-emerald-200: oklch(90.5% 0.093 164.15); - --color-emerald-300: oklch(84.5% 0.143 164.978); - --color-emerald-400: oklch(76.5% 0.177 163.223); - --color-emerald-500: oklch(69.6% 0.17 162.48); - --color-emerald-600: oklch(59.6% 0.145 163.225); - --color-emerald-700: oklch(50.8% 0.118 165.612); - --color-emerald-800: oklch(43.2% 0.095 166.913); - --color-emerald-900: oklch(37.8% 0.077 168.94); - --color-emerald-950: oklch(26.2% 0.051 172.552); - --color-teal-500: oklch(70.4% 0.14 182.503); - --color-teal-600: oklch(60% 0.118 184.704); - --color-cyan-50: oklch(98.4% 0.019 200.873); - --color-cyan-100: oklch(95.6% 0.045 203.388); - --color-cyan-200: oklch(91.7% 0.08 205.041); - --color-cyan-300: oklch(86.5% 0.127 207.078); - --color-cyan-400: oklch(78.9% 0.154 211.53); - --color-cyan-500: oklch(71.5% 0.143 215.221); - --color-cyan-600: oklch(60.9% 0.126 221.723); - --color-cyan-700: oklch(52% 0.105 223.128); - --color-cyan-800: oklch(45% 0.085 224.283); - --color-cyan-900: oklch(39.8% 0.07 227.392); - --color-cyan-950: oklch(30.2% 0.056 229.695); - --color-sky-50: oklch(97.7% 0.013 236.62); - --color-sky-100: oklch(95.1% 0.026 236.824); - --color-sky-200: oklch(90.1% 0.058 230.902); - --color-sky-300: oklch(82.8% 0.111 230.318); - --color-sky-400: oklch(74.6% 0.16 232.661); - --color-sky-500: oklch(68.5% 0.169 237.323); - --color-sky-600: oklch(58.8% 0.158 241.966); - --color-sky-700: oklch(50% 0.134 242.749); - --color-sky-800: oklch(44.3% 0.11 240.79); - --color-sky-900: oklch(39.1% 0.09 240.876); - --color-sky-950: oklch(29.3% 0.066 243.157); - --color-blue-500: oklch(62.3% 0.214 259.815); - --color-blue-600: oklch(54.6% 0.245 262.881); - --color-indigo-500: oklch(58.5% 0.233 277.117); - --color-indigo-600: oklch(51.1% 0.262 276.966); - --color-violet-500: oklch(60.6% 0.25 292.717); - --color-violet-600: oklch(54.1% 0.281 293.009); - --color-purple-500: oklch(62.7% 0.265 303.9); - --color-purple-600: oklch(55.8% 0.288 302.321); - --color-fuchsia-50: oklch(97.7% 0.017 320.058); - --color-fuchsia-100: oklch(95.2% 0.037 318.852); - --color-fuchsia-200: oklch(90.3% 0.076 319.62); - --color-fuchsia-300: oklch(83.3% 0.145 321.434); - --color-fuchsia-400: oklch(74% 0.238 322.16); - --color-fuchsia-500: oklch(66.7% 0.295 322.15); - --color-fuchsia-600: oklch(59.1% 0.293 322.896); - --color-fuchsia-700: oklch(51.8% 0.253 323.949); - --color-fuchsia-800: oklch(45.2% 0.211 324.591); - --color-fuchsia-900: oklch(40.1% 0.17 325.612); - --color-fuchsia-950: oklch(29.3% 0.136 325.661); - --color-pink-50: oklch(97.1% 0.014 343.198); - --color-pink-100: oklch(94.8% 0.028 342.258); - --color-pink-200: oklch(89.9% 0.061 343.231); - --color-pink-300: oklch(82.3% 0.12 346.018); - --color-pink-400: oklch(71.8% 0.202 349.761); - --color-pink-500: oklch(65.6% 0.241 354.308); - --color-pink-600: oklch(59.2% 0.249 0.584); - --color-pink-700: oklch(52.5% 0.223 3.958); - --color-pink-800: oklch(45.9% 0.187 3.815); - --color-pink-900: oklch(40.8% 0.153 2.432); - --color-pink-950: oklch(28.4% 0.109 3.907); - --color-rose-500: oklch(64.5% 0.246 16.439); - --color-rose-600: oklch(58.6% 0.253 17.585); - --color-slate-500: oklch(55.4% 0.046 257.417); - --color-slate-600: oklch(44.6% 0.043 257.281); - --color-gray-50: oklch(98.5% 0.002 247.839); - --color-gray-100: oklch(96.7% 0.003 264.542); - --color-gray-200: oklch(92.8% 0.006 264.531); - --color-gray-300: oklch(87.2% 0.01 258.338); - --color-gray-400: oklch(70.7% 0.022 261.325); - --color-gray-500: oklch(55.1% 0.027 264.364); - --color-gray-600: oklch(44.6% 0.03 256.802); - --color-gray-700: oklch(37.3% 0.034 259.733); - --color-gray-800: oklch(27.8% 0.033 256.848); - --color-gray-900: oklch(21% 0.034 264.665); - --color-zinc-500: oklch(55.2% 0.016 285.938); - --color-zinc-600: oklch(44.2% 0.017 285.786); - --color-neutral-500: oklch(55.6% 0 0); - --color-neutral-600: oklch(43.9% 0 0); - --color-stone-500: oklch(55.3% 0.013 58.071); - --color-stone-600: oklch(44.4% 0.011 73.639); - --color-black: #000; - --color-white: #fff; + --color-black: #0B0C0C; + --color-white: #FFFFFF; --spacing: 0.25rem; - --container-7xl: 80rem; + --breakpoint-xl: 80rem; + --container-3xl: 48rem; --text-xs: 0.75rem; --text-xs--line-height: calc(1 / 0.75); --text-sm: 0.875rem; @@ -157,40 +25,92 @@ --text-2xl: 1.5rem; --text-2xl--line-height: calc(2 / 1.5); --text-3xl: 1.875rem; - --text-3xl--line-height: calc(2.25 / 1.875); + --text-3xl--line-height: calc(2 / 1.5); --text-4xl: 2.25rem; - --text-4xl--line-height: calc(2.5 / 2.25); + --text-4xl--line-height: calc(2 / 1.5); --text-5xl: 3rem; - --text-5xl--line-height: 1; + --text-5xl--line-height: calc(2 / 1.5); + --font-weight-light: 300; --font-weight-normal: 400; --font-weight-medium: 500; + --font-weight-semibold: 600; --font-weight-bold: 700; - --tracking-wider: 0.05em; + --tracking-tight: -0.025em; + --tracking-wide: 0.025em; + --leading-relaxed: 1.625; --radius-md: 0.375rem; --radius-lg: 0.5rem; --radius-xl: 0.75rem; + --radius-2xl: 1rem; --default-transition-duration: 150ms; --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); --default-font-family: var(--font-sans); --default-mono-font-family: var(--font-mono); - --color-primary-500: var(--color-amber-500); - --color-primary-600: var(--color-amber-600); - --color-secondary-500: var(--color-emerald-500); - --color-secondary-600: var(--color-emerald-600); - --color-active-500: var(--color-sky-500); - --color-active-600: var(--color-sky-600); - --color-inactive-500: var(--color-pink-500); - --color-inactive-600: var(--color-pink-600); - --color-info-500: var(--color-cyan-500); - --color-info-600: var(--color-cyan-600); - --color-success-500: var(--color-green-500); - --color-success-600: var(--color-green-600); - --color-warning-500: var(--color-orange-500); - --color-warning-600: var(--color-orange-600); - --color-danger-500: var(--color-red-500); - --color-danger-600: var(--color-red-600); - --color-attention-500: var(--color-fuchsia-500); - --color-attention-600: var(--color-fuchsia-600); + --radius-full: calc(infinity * 1px); + --color-gray-1: #F3F2F1; + --color-gray-2: #DEE0E2; + --color-gray-3: #949494; + --color-background: #FEFEFE; + --color-background-light: #F1F8FF; + --color-background-dark: #F0F8FF; + --color-background-modal: #F5FAFF; + --color-background-modal-light: #FFFFFF; + --color-text: #0B0C0C; + --color-text-light: #626A6E; + --color-border: #BFC1C3; + --color-link: #0065B3; + --color-link-hover: #003078; + --color-primary: #0A319E; + --color-primary-light: #E0E8FF; + --color-success: #00703C; + --color-success-light: #D4F7D4; + --color-warning: #EC9811; + --color-warning-light: #FFEAC9; + --color-danger: #D0190F; + --color-danger-light: #FFDCDA; + --color-info: #2B8CC4; + --color-info-light: #D4ECF7; + --color-neutral: #7C7C7C; + --color-neutral-light: #DEE0E2; + --color-result-failed: var(--color-danger); + --color-result-passed: var(--color-success); + --color-btn-primary: var(--color-primary); + --color-form-text: var(--color-text); + --color-form-bg: var(--color-white); + --color-form-border: var(--color-border); + --color-form-placeholder-text: color-mix(in srgb, #0B0C0C 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-placeholder-text: color-mix(in srgb, var(--color-text) 50%, transparent); + } + --color-form-focus-border: var(--color-primary); + --color-form-disabled-text: color-mix(in srgb, #0B0C0C 40%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-disabled-text: color-mix(in srgb, var(--color-text) 40%, transparent); + } + --color-form-disabled-bg: var(--color-gray-1); + --color-form-disabled-border: color-mix(in srgb, #BFC1C3 40%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-disabled-border: color-mix(in srgb, var(--color-border) 40%, transparent); + } + --color-form-disabled-placeholder-text: color-mix(in srgb, #0B0C0C 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-disabled-placeholder-text: color-mix(in srgb, var(--color-text) 20%, transparent); + } + --color-form-readonly-text: color-mix(in srgb, #0B0C0C 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-readonly-text: color-mix(in srgb, var(--color-text) 80%, transparent); + } + --color-form-readonly-bg: var(--color-gray-1); + --color-form-readonly-border: color-mix(in srgb, #BFC1C3 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-readonly-border: color-mix(in srgb, var(--color-border) 80%, transparent); + } + --color-form-readonly-placeholder-text: color-mix(in srgb, #0B0C0C 40%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-readonly-placeholder-text: color-mix(in srgb, var(--color-text) 40%, transparent); + } + --color-form-invalid: var(--color-danger); + --color-input-placeholder-text: var(--color-form-placeholder-text); } } @layer base { @@ -325,6 +245,9 @@ ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field { padding-block: 0; } + ::-webkit-calendar-picker-indicator { + line-height: 1; + } :-moz-ui-invalid { box-shadow: none; } @@ -339,33 +262,18 @@ } } @layer utilities { - .collapse { - visibility: collapse; - } - .absolute { - position: absolute; - } - .fixed { - position: fixed; - } - .relative { - position: relative; - } .static { position: static; } - .inset-0 { - inset: calc(var(--spacing) * 0); + .sticky { + position: sticky; + } + .top-0 { + top: calc(var(--spacing) * 0); } .z-40 { z-index: 40; } - .z-50 { - z-index: 50; - } - .z-500 { - z-index: 500; - } .container { width: 100%; @media (width >= 40rem) { @@ -384,56 +292,44 @@ max-width: 96rem; } } - .-mx-1 { - margin-inline: calc(var(--spacing) * -1); - } - .mx-2 { - margin-inline: calc(var(--spacing) * 2); - } .mx-auto { margin-inline: auto; } - .my-auto { - margin-block: auto; - } - .ms-2 { - margin-inline-start: calc(var(--spacing) * 2); - } - .ms-auto { - margin-inline-start: auto; - } - .me-2 { - margin-inline-end: calc(var(--spacing) * 2); - } - .me-auto { - margin-inline-end: auto; + .-mt-2 { + margin-top: calc(var(--spacing) * -2); } .mt-1 { margin-top: calc(var(--spacing) * 1); } + .mt-2 { + margin-top: calc(var(--spacing) * 2); + } .mt-3 { margin-top: calc(var(--spacing) * 3); } + .mt-4 { + margin-top: calc(var(--spacing) * 4); + } .mt-6 { margin-top: calc(var(--spacing) * 6); } - .mr-3 { - margin-right: calc(var(--spacing) * 3); + .mt-8 { + margin-top: calc(var(--spacing) * 8); } - .mb-2 { - margin-bottom: calc(var(--spacing) * 2); + .mt-10 { + margin-top: calc(var(--spacing) * 10); } - .mb-3 { - margin-bottom: calc(var(--spacing) * 3); + .mt-14 { + margin-top: calc(var(--spacing) * 14); } - .mb-4 { - margin-bottom: calc(var(--spacing) * 4); + .mb-2 { + margin-bottom: calc(var(--spacing) * 2); } - .ml-1 { - margin-left: calc(var(--spacing) * 1); + .mb-10 { + margin-bottom: calc(var(--spacing) * 10); } - .block { - display: block; + .mb-12 { + margin-bottom: calc(var(--spacing) * 12); } .flex { display: flex; @@ -441,11 +337,8 @@ .grid { display: grid; } - .inline-flex { - display: inline-flex; - } - .table { - display: table; + .hidden { + display: none; } .size-4 { width: calc(var(--spacing) * 4); @@ -459,62 +352,85 @@ width: calc(var(--spacing) * 6); height: calc(var(--spacing) * 6); } - .max-h-100 { - max-height: calc(var(--spacing) * 100); + .size-7 { + width: calc(var(--spacing) * 7); + height: calc(var(--spacing) * 7); } - .w-full { - width: 100%; + .h-16 { + height: calc(var(--spacing) * 16); } - .max-w-7xl { - max-width: var(--container-7xl); + .min-h-screen { + min-height: 100vh; } - .min-w-4 { - min-width: calc(var(--spacing) * 4); + .w-56 { + width: calc(var(--spacing) * 56); } - .min-w-6 { - min-width: calc(var(--spacing) * 6); + .max-w-3xl { + max-width: var(--container-3xl); } - .transform { - transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); + .max-w-screen-xl { + max-width: var(--breakpoint-xl); } - .cursor-pointer { - cursor: pointer; + .flex-1 { + flex: 1; } - .grid-cols-2 { - grid-template-columns: repeat(2, minmax(0, 1fr)); + .shrink-0 { + flex-shrink: 0; + } + .grid-cols-1 { + grid-template-columns: repeat(1, minmax(0, 1fr)); } .flex-col { flex-direction: column; } - .flex-wrap { - flex-wrap: wrap; - } .items-center { align-items: center; } + .items-end { + align-items: flex-end; + } + .items-start { + align-items: flex-start; + } .justify-between { justify-content: space-between; } - .justify-center { - justify-content: center; + .gap-1 { + gap: calc(var(--spacing) * 1); + } + .gap-1\.5 { + gap: calc(var(--spacing) * 1.5); } .gap-2 { gap: calc(var(--spacing) * 2); } + .gap-3 { + gap: calc(var(--spacing) * 3); + } + .gap-4 { + gap: calc(var(--spacing) * 4); + } .gap-6 { gap: calc(var(--spacing) * 6); } + .space-y-1 { + :where(& > :not(:last-child)) { + --tw-space-y-reverse: 0; + margin-block-start: calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse)); + margin-block-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse))); + } + } + .overflow-hidden { + overflow: hidden; + } .overflow-x-auto { overflow-x: auto; } - .overflow-y-auto { - overflow-y: auto; - } .rounded { border-radius: 0.25rem; } .rounded-full { - border-radius: calc(infinity * 1px); + border-radius: var(--radius-full); } .rounded-lg { border-radius: var(--radius-lg); @@ -522,53 +438,34 @@ .rounded-md { border-radius: var(--radius-md); } + .rounded-xl { + border-radius: var(--radius-xl); + } .border { border-style: var(--tw-border-style); border-width: 1px; } - .border-4 { - border-style: var(--tw-border-style); - border-width: 4px; - } - .border-t-2 { - border-top-style: var(--tw-border-style); - border-top-width: 2px; - } - .border-gray-200 { - border-color: var(--color-gray-200); - } - .border-green-500 { - border-color: var(--color-green-500); - } - .border-transparent { - border-color: transparent; - } - .bg-gray-100 { - background-color: var(--color-gray-100); - } - .bg-gray-200 { - background-color: var(--color-gray-200); + .border-b { + border-bottom-style: var(--tw-border-style); + border-bottom-width: 1px; } - .bg-gray-800\/70 { - background-color: color-mix(in srgb, oklch(27.8% 0.033 256.848) 70%, transparent); - @supports (color: color-mix(in lab, red, red)) { - background-color: color-mix(in oklab, var(--color-gray-800) 70%, transparent); - } + .border-border { + border-color: var(--color-border); } - .bg-orange-50 { - background-color: var(--color-orange-50); + .bg-background { + background-color: var(--color-background); } - .bg-primary-500 { - background-color: var(--color-primary-500); + .bg-background-light { + background-color: var(--color-background-light); } - .bg-white { - background-color: var(--color-white); + .bg-primary-light { + background-color: var(--color-primary-light); } - .p-1 { - padding: calc(var(--spacing) * 1); + .p-0\.5 { + padding: calc(var(--spacing) * 0.5); } - .p-2 { - padding: calc(var(--spacing) * 2); + .p-1\.5 { + padding: calc(var(--spacing) * 1.5); } .p-3 { padding: calc(var(--spacing) * 3); @@ -579,8 +476,11 @@ .p-5 { padding: calc(var(--spacing) * 5); } - .px-1 { - padding-inline: calc(var(--spacing) * 1); + .p-6 { + padding: calc(var(--spacing) * 6); + } + .px-1\.5 { + padding-inline: calc(var(--spacing) * 1.5); } .px-2 { padding-inline: calc(var(--spacing) * 2); @@ -591,11 +491,20 @@ .px-4 { padding-inline: calc(var(--spacing) * 4); } - .py-1 { - padding-block: calc(var(--spacing) * 1); + .py-0\.5 { + padding-block: calc(var(--spacing) * 0.5); } - .ps-3 { - padding-inline-start: calc(var(--spacing) * 3); + .py-1\.5 { + padding-block: calc(var(--spacing) * 1.5); + } + .py-2 { + padding-block: calc(var(--spacing) * 2); + } + .py-8 { + padding-block: calc(var(--spacing) * 8); + } + .py-12 { + padding-block: calc(var(--spacing) * 12); } .text-center { text-align: center; @@ -604,9 +513,17 @@ font-size: var(--text-2xl); line-height: var(--tw-leading, var(--text-2xl--line-height)); } - .text-5xl { - font-size: var(--text-5xl); - line-height: var(--tw-leading, var(--text-5xl--line-height)); + .text-3xl { + font-size: var(--text-3xl); + line-height: var(--tw-leading, var(--text-3xl--line-height)); + } + .text-4xl { + font-size: var(--text-4xl); + line-height: var(--tw-leading, var(--text-4xl--line-height)); + } + .text-base { + font-size: var(--text-base); + line-height: var(--tw-leading, var(--text-base--line-height)); } .text-lg { font-size: var(--text-lg); @@ -616,1885 +533,677 @@ font-size: var(--text-sm); line-height: var(--tw-leading, var(--text-sm--line-height)); } + .text-xl { + font-size: var(--text-xl); + line-height: var(--tw-leading, var(--text-xl--line-height)); + } .text-xs { font-size: var(--text-xs); line-height: var(--tw-leading, var(--text-xs--line-height)); } + .leading-relaxed { + --tw-leading: var(--leading-relaxed); + line-height: var(--leading-relaxed); + } .font-bold { --tw-font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold); } + .font-light { + --tw-font-weight: var(--font-weight-light); + font-weight: var(--font-weight-light); + } .font-medium { --tw-font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium); } - .font-normal { - --tw-font-weight: var(--font-weight-normal); - font-weight: var(--font-weight-normal); + .font-semibold { + --tw-font-weight: var(--font-weight-semibold); + font-weight: var(--font-weight-semibold); } - .text-blue-500 { - color: var(--color-blue-500); + .tracking-tight { + --tw-tracking: var(--tracking-tight); + letter-spacing: var(--tracking-tight); } - .text-gray-200 { - color: var(--color-gray-200); + .tracking-wide { + --tw-tracking: var(--tracking-wide); + letter-spacing: var(--tracking-wide); } - .text-gray-400 { - color: var(--color-gray-400); + .text-danger { + color: var(--color-danger); } - .text-gray-500 { - color: var(--color-gray-500); + .text-primary { + color: var(--color-primary); } - .text-gray-600 { - color: var(--color-gray-600); + .text-success { + color: var(--color-success); } - .text-gray-700 { - color: var(--color-gray-700); + .text-text { + color: var(--color-text); } - .text-gray-800 { - color: var(--color-gray-800); + .text-text-light { + color: var(--color-text-light); } .text-white { color: var(--color-white); } + .uppercase { + text-transform: uppercase; + } .shadow { --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } + .shadow-md { + --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } + .shadow-sm { + --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } .transition { - transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-duration: var(--tw-duration, var(--default-transition-duration)); } - .duration-100 { - --tw-duration: 100ms; - transition-duration: 100ms; - } - .duration-200 { - --tw-duration: 200ms; - transition-duration: 200ms; + .group-hover\:text-primary { + &:is(:where(.group):hover *) { + @media (hover: hover) { + color: var(--color-primary); + } + } } - .hover\:bg-gray-200 { + .hover\:border-primary { &:hover { @media (hover: hover) { - background-color: var(--color-gray-200); + border-color: var(--color-primary); } } } - .hover\:bg-gray-300 { + .hover\:bg-primary-light { &:hover { @media (hover: hover) { - background-color: var(--color-gray-300); + background-color: var(--color-primary-light); } } } - .hover\:bg-primary-600 { + .hover\:text-primary { &:hover { @media (hover: hover) { - background-color: var(--color-primary-600); + color: var(--color-primary); } } } + .focus\:border-primary { + &:focus { + border-color: var(--color-primary); + } + } .focus\:outline-none { &:focus { --tw-outline-style: none; outline-style: none; } } - .sm\:w-80 { + .sm\:inline { + @media (width >= 40rem) { + display: inline; + } + } + .sm\:grid-cols-2 { + @media (width >= 40rem) { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + } + .sm\:gap-2 { + @media (width >= 40rem) { + gap: calc(var(--spacing) * 2); + } + } + .sm\:px-6 { @media (width >= 40rem) { - width: calc(var(--spacing) * 80); + padding-inline: calc(var(--spacing) * 6); } } - .sm\:flex-row { + .sm\:text-5xl { @media (width >= 40rem) { - flex-direction: row; + font-size: var(--text-5xl); + line-height: var(--tw-leading, var(--text-5xl--line-height)); + } + } + .md\:inline { + @media (width >= 48rem) { + display: inline; + } + } + .lg\:grid-cols-2 { + @media (width >= 64rem) { + grid-template-columns: repeat(2, minmax(0, 1fr)); } } + .lg\:grid-cols-3 { + @media (width >= 64rem) { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + } + .lg\:grid-cols-4 { + @media (width >= 64rem) { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + } + .lg\:px-8 { + @media (width >= 64rem) { + padding-inline: calc(var(--spacing) * 8); + } + } +} +@layer theme { + :root, :host { + --font-sans: "Familjen Grotesk", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + } } @layer base { h1 { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; font-size: var(--text-5xl); line-height: var(--tw-leading, var(--text-5xl--line-height)); --tw-font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold); text-wrap: wrap; + overflow-wrap: break-word; + color: var(--color-text); } h2 { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; font-size: var(--text-4xl); line-height: var(--tw-leading, var(--text-4xl--line-height)); --tw-font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold); text-wrap: wrap; + overflow-wrap: break-word; + color: var(--color-text); } h3 { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; font-size: var(--text-3xl); line-height: var(--tw-leading, var(--text-3xl--line-height)); --tw-font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold); text-wrap: wrap; + overflow-wrap: break-word; + color: var(--color-text); } h4 { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; font-size: var(--text-2xl); line-height: var(--tw-leading, var(--text-2xl--line-height)); --tw-font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold); text-wrap: wrap; + overflow-wrap: break-word; + color: var(--color-text); } h5 { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; font-size: var(--text-xl); line-height: var(--tw-leading, var(--text-xl--line-height)); --tw-font-weight: var(--font-weight-normal); font-weight: var(--font-weight-normal); text-wrap: wrap; + overflow-wrap: break-word; + color: var(--color-text); } h6 { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; font-size: var(--text-lg); line-height: var(--tw-leading, var(--text-lg--line-height)); --tw-font-weight: var(--font-weight-normal); font-weight: var(--font-weight-normal); text-wrap: wrap; + overflow-wrap: break-word; + color: var(--color-text); } p { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; font-size: var(--text-base); line-height: var(--tw-leading, var(--text-base--line-height)); --tw-font-weight: var(--font-weight-normal); font-weight: var(--font-weight-normal); text-wrap: wrap; + overflow-wrap: break-word; + color: var(--color-text-light); } a { cursor: pointer; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; font-size: var(--text-base); line-height: var(--tw-leading, var(--text-base--line-height)); --tw-font-weight: var(--font-weight-normal); font-weight: var(--font-weight-normal); + text-wrap: wrap; + overflow-wrap: break-word; + text-decoration-line: underline; + color: var(--color-link); &:hover { @media (hover: hover) { - --tw-font-weight: var(--font-weight-medium); - font-weight: var(--font-weight-medium); + color: var(--color-link-hover); } } } hr { + color: var(--color-text-light); opacity: 30%; } + span { + font-size: var(--text-base); + line-height: var(--tw-leading, var(--text-base--line-height)); + --tw-font-weight: var(--font-weight-normal); + font-weight: var(--font-weight-normal); + text-wrap: wrap; + overflow-wrap: break-word; + color: var(--color-text); + } + div { + font-size: var(--text-base); + line-height: var(--tw-leading, var(--text-base--line-height)); + --tw-font-weight: var(--font-weight-normal); + font-weight: var(--font-weight-normal); + text-wrap: wrap; + overflow-wrap: break-word; + color: var(--color-text); + } + input[type="date"], input[type="time"], input[type="datetime-local"] { + color-scheme: light; + } + [data-theme="dark"] input[type="date"], [data-theme="dark"] input[type="time"], [data-theme="dark"] input[type="datetime-local"] { + color-scheme: dark; + } +} +[data-theme="dark"] { + --color-black: #FFFFFF; + --color-white: #121212; + --color-gray-1: #1F1F1F; + --color-gray-2: #949494; + --color-gray-3: #F3F2F1; + --color-background: #121212; + --color-background-light: #1F1F1F; + --color-background-dark: #1F1F1F; + --color-background-modal: #1E1E1E; + --color-background-modal-light: #252525; + --color-text: #F2F2F2; + --color-text-light: #626A6E; + --color-border: #BFC1C3 /*#4B5563*/; + --color-border-input: #F2F2F2 /*#F2F2F2*/; + --color-link: #0065B3 /*#60A5FA*/; + --color-link-hover: #89C4FF /*#93C5FD*/; + --color-link-visited: #A08AE1 /*#C4B5FD*/; + --color-primary: #89C4FF; + --color-primary-light: #0A319E /*#1e3a8a*/; + --color-success: #4ADE80; + --color-success-light: #14532d; + --color-warning: #FBBF24; + --color-warning-light: #78350f; + --color-danger: #F87171; + --color-danger-light: #7f1d1d; + --color-info: #38BDF8; + --color-info-light: #0c4a6e; + --color-noactive: #A1A1AA; + --color-noactive-light: #27272a; + --color-result-failed: #F87171; + --color-result-passed: #4ADE80; + --color-result-inprogress: #60A5FA; + --color-result-exclude: #A78BFA; + --color-result-bypasse: #E879F9; + --color-result-inconcllusive: #FCD34D; + --color-result-runnig: #2DD4BF; + --color-result-noaction: #A1A1AA; + --color-diagnostic-debug: #60A5FA; + --color-diagnostic-verbose: #5EEAD4; + --color-diagnostic-information: #38BDF8; + --color-diagnostic-warning: #FBBF24; + --color-diagnostic-error: #F87171; + --color-diagnostic-fatal: #EF4444; + --color-automat: #4ADE80; + --color-ground: #38BDF8; + --color-grounded: #60A5FA; + --color-idle: #A1A1AA; + --color-manual: #FBBF24; + --color-oee: #89C4FF; + --color-availability: #B6D069; + --color-performance: #A08AE1; + --color-quality: #FBBF24; + --color-downtime-unassigned: #C7C7C7; + --color-downtime-material: #FBBF24; + --color-downtime-operator: #F08584; + --color-downtime-working: #B6D069; + --color-downtime-technical: #A08AE1; + --color-downtime-planned: #7DCDD2; + --color-btn-primary: var(--color-primary); + --color-btn-primary-hover: var(--color-primary-light); + --color-btn-danger: var(--color-danger); + --color-btn-danger-hover: var(--color-danger-light); + --color-btn-success: var(--color-success); + --color-btn-success-hover: var(--color-success-light); + --color-btn-warning: var(--color-warning); + --color-btn-warning-hover: var(--color-warning-light); + --color-btn-info: var(--color-info); + --color-btn-info-hover: var(--color-info-light); + --color-btn-neutral: var(--color-neutral); + --color-btn-neutral-hover: var(--color-neutral-light); + --color-btn-outline-bg: transparent; + --color-btn-no-bg-bg: transparent; + --color-action-btn-text: var(--color-text); + --color-action-btn-bg: color-mix(in srgb, #FEFEFE 60%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-action-btn-bg: color-mix(in srgb, var(--color-background) 60%, transparent); + } + --color-action-btn-border: var(--color-border); + --color-action-btn-hover-bg: color-mix(in srgb, #F0F8FF 70%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-action-btn-hover-bg: color-mix(in srgb, var(--color-background-dark) 70%, transparent); + } + --color-action-btn-active-bg: color-mix(in srgb, #0A319E 40%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-action-btn-active-bg: color-mix(in srgb, var(--color-primary) 40%, transparent); + } + --color-form-text: var(--color-text); + --color-form-bg: var(--color-white); + --color-form-border: var(--color-border); + --color-form-placeholder-text: color-mix(in srgb, #0B0C0C 50%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-placeholder-text: color-mix(in srgb, var(--color-text) 50%, transparent); + } + --color-form-focus-border: var(--color-primary); + --color-form-disabled-text: color-mix(in srgb, #0B0C0C 40%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-disabled-text: color-mix(in srgb, var(--color-text) 40%, transparent); + } + --color-form-disabled-bg: var(--color-gray-1); + --color-form-disabled-border: color-mix(in srgb, #BFC1C3 40%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-disabled-border: color-mix(in srgb, var(--color-border) 40%, transparent); + } + --color-form-disabled-placeholder-text: color-mix(in srgb, #0B0C0C 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-disabled-placeholder-text: color-mix(in srgb, var(--color-text) 20%, transparent); + } + --color-form-readonly-text: color-mix(in srgb, #0B0C0C 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-readonly-text: color-mix(in srgb, var(--color-text) 80%, transparent); + } + --color-form-readonly-bg: var(--color-gray-1); + --color-form-readonly-border: color-mix(in srgb, #BFC1C3 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-readonly-border: color-mix(in srgb, var(--color-border) 80%, transparent); + } + --color-form-readonly-placeholder-text: color-mix(in srgb, #0B0C0C 40%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-form-readonly-placeholder-text: color-mix(in srgb, var(--color-text) 40%, transparent); + } + --color-form-invalid: var(--color-danger); + --color-input-text: var(--color-form-text); + --color-input-bg: var(--color-form-bg); + --color-input-border: var(--color-form-border); + --color-input-placeholder-text: var(--color-form-placeholder-text); + --color-input-focus-border: var(--color-form-focus-border); + --color-input-disabled-text: var(--color-form-disabled-text); + --color-input-disabled-bg: var(--color-form-disabled-bg); + --color-input-disabled-border: var(--color-form-disabled-border); + --color-input-disabled-placeholder-text: var(--color-form-disabled-placeholder-text); + --color-input-readonly-text: var(--color-form-readonly-text); + --color-input-readonly-bg: var(--color-form-readonly-bg); + --color-input-readonly-border: var(--color-form-readonly-border); + --color-input-readonly-placeholder-text: var(--color-form-readonly-placeholder-text); + --color-input-invalid: var(--color-form-invalid); + --color-feedback-invalid: var(--color-danger); + --color-feedback-valid: var(--color-success); + --color-feedback: var(--color-text); + --color-textarea-text: var(--color-form-text); + --color-textarea-bg: var(--color-white); + --color-textarea-border: var(--color-form-border); + --color-textarea-placeholder-text: var(--color-input-placeholder-text); + --color-textarea-focus-border: var(--color-form-focus-border); + --color-textarea-disabled-text: var(--color-form-disabled-text); + --color-textarea-disabled-bg: var(--color-form-disabled-bg); + --color-textarea-disabled-border: var(--color-form-disabled-border); + --color-textarea-disabled-placeholder-text: var(--color-form-disabled-placeholder-text); + --color-textarea-readonly-text: var(--color-form-readonly-text); + --color-textarea-readonly-bg: var(--color-form-readonly-bg); + --color-textarea-readonly-border: var(--color-form-readonly-border); + --color-textarea-readonly-placeholder-text: var(--color-form-readonly-placeholder-text); + --color-textarea-invalid: var(--color-form-invalid); + --color-checkbox-bg: var(--color-white); + --color-checkbox-border: var(--color-form-border); + --color-checkbox-focus-border: var(--color-form-focus-border); + --color-checkbox-disabled-bg: var(--color-form-disabled-bg); + --color-checkbox-disabled-border: var(--color-form-disabled-border); + --color-checkbox-check: var(--color-primary); + --color-checkbox-invalid: var(--color-form-invalid); + --color-toggle-bg: var(--color-gray-2); + --color-toggle-thumb: var(--color-white); + --color-toggle-focus: var(--color-primary); + --color-toggle-text-off: var(--color-text); + --color-toggle-text-on: var(--color-primary); + --color-toggle-invalid: var(--color-form-invalid); + --color-radio-bg: var(--color-white); + --color-radio-border: var(--color-form-border); + --color-radio-focus-border: var(--color-form-focus-border); + --color-radio-disabled-bg: var(--color-form-disabled-bg); + --color-radio-disabled-border: var(--color-form-disabled-border); + --color-radio-fill: var(--color-primary); + --color-radio-invalid: var(--color-form-invalid); + --color-select-text: var(--color-form-text); + --color-select-bg: var(--color-white); + --color-select-border: var(--color-form-border); + --color-select-placeholder-text: var(--color-input-placeholder-text); + --color-select-focus-border: var(--color-form-focus-border); + --color-select-disabled-text: var(--color-form-disabled-text); + --color-select-disabled-bg: var(--color-form-disabled-bg); + --color-select-disabled-border: var(--color-form-disabled-border); + --color-select-disabled-placeholder-text: var(--color-form-disabled-placeholder-text); + --color-select-invalid: var(--color-form-invalid); + --color-file-text: var(--color-form-text); + --color-file-border: var(--color-form-border); + --color-file-button-text: var(--color-form-text); + --color-file-button-bg: var(--color-background-dark); + --color-color-border: var(--color-form-border); + --color-nav-item-active-text: var(--color-primary); + --color-nav-item-ctive-border: var(--color-primary); + --color-nav-item-text: color-mix(in srgb, #0B0C0C 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-nav-item-text: color-mix(in srgb, var(--color-text) 80%, transparent); + } + --color-nav-item-description-text: color-mix(in srgb, #0B0C0C 60%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-nav-item-description-text: color-mix(in srgb, var(--color-text) 60%, transparent); + } + --color-breadcrumb-active-text: var(--color-text); + --color-card-title-text: var(--color-primary); + --color-simple-border-border: var(--color-border); + --color-alert-text: var(--color-text); + --color-alert-primary-bg: color-mix(in srgb, #0A319E 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-alert-primary-bg: color-mix(in srgb, var(--color-primary) 20%, transparent); + } + --color-alert-success-bg: color-mix(in srgb, #00703C 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-alert-success-bg: color-mix(in srgb, var(--color-success) 20%, transparent); + } + --color-alert-warning-bg: color-mix(in srgb, #EC9811 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-alert-warning-bg: color-mix(in srgb, var(--color-warning) 20%, transparent); + } + --color-alert-danger-bg: color-mix(in srgb, #D0190F 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-alert-danger-bg: color-mix(in srgb, var(--color-danger) 20%, transparent); + } + --color-alert-info-bg: color-mix(in srgb, #2B8CC4 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-alert-info-bg: color-mix(in srgb, var(--color-info) 20%, transparent); + } + --color-list-group-text: var(--color-primary); + --color-list-group-bg: var(--color-white); + --color-list-group-border: var(--color-border); + --color-list-group-item-border: var(--color-border); + --color-list-group-item-action-text: var(--color-link); + --color-list-group-item-action-hover-text: var(--color-link-hover); + --color-list-group-item-action-disabled-text: color-mix(in srgb, #0B0C0C 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-list-group-item-action-disabled-text: color-mix(in srgb, var(--color-text) 80%, transparent); + } + --color-tab-bg: color-mix(in srgb, #F0F8FF 70%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-tab-bg: color-mix(in srgb, var(--color-background-dark) 70%, transparent); + } + --color-tab-btn-text: var(--color-text); + --color-tab-btn-bg: var(--color-background-dark); + --color-tab-btn-border: var(--color-border); + --color-tab-btn-hover-bg: color-mix(in srgb, #FEFEFE 40%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-tab-btn-hover-bg: color-mix(in srgb, var(--color-background) 40%, transparent); + } + --color-tab-btn-active-text: var(--color-btn-primary); + --color-tab-btn-active-bg: var(--color-background); + --color-tab-btn-active-border: var(--color-border); + --color-dropdown-body-bg: var(--color-background-modal-light); + --color-dropdown-body-border: var(--color-border); + --color-dropdown-item-text: color-mix(in srgb, #0B0C0C 70%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-dropdown-item-text: color-mix(in srgb, var(--color-text) 70%, transparent); + } + --color-dropdown-item-hover-text: color-mix(in srgb, #0B0C0C 90%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-dropdown-item-hover-text: color-mix(in srgb, var(--color-text) 90%, transparent); + } + --color-tooltip-bg: var(--color-background-modal); + --color-tooltip-border: var(--color-primary); + --color-modal-bg: var(--color-background-modal); + --color-modal-border: var(--color-border); + --color-modal-overlay-bg: color-mix(in srgb, #FFFFFF 60%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-modal-overlay-bg: color-mix(in srgb, var(--color-white) 60%, transparent); + } + --color-accordion-border: var(--color-border); + --color-accordion-button-text: color-mix(in srgb, #0A319E 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-accordion-button-text: color-mix(in srgb, var(--color-primary) 80%, transparent); + } + --color-accordion-button-hover-text: var(--color-primary); + --color-toast-bg: var(--color-background-modal); + --color-toast-divider-text: var(--color-text); + --color-spinner-text: color-mix(in srgb, #F0F8FF 70%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-spinner-text: color-mix(in srgb, var(--color-background-dark) 70%, transparent); + } + --color-spinner-fill: color-mix(in srgb, #0B0C0C 70%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-spinner-fill: color-mix(in srgb, var(--color-text) 70%, transparent); + } + --color-table-h-text: var(--color-text); + --color-table-d-text: var(--color-text); + --color-table-striped-odd-bg: color-mix(in srgb, #F0F8FF 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-table-striped-odd-bg: color-mix(in srgb, var(--color-background-dark) 20%, transparent); + } + --color-table-striped-even-bg: color-mix(in srgb, #F0F8FF 80%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-table-striped-even-bg: color-mix(in srgb, var(--color-background-dark) 80%, transparent); + } + --color-table-hover-bg: color-mix(in srgb, #F0F8FF 90%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-table-hover-bg: color-mix(in srgb, var(--color-background-dark) 90%, transparent); + } + --color-pagination-number-text: color-mix(in srgb, #0B0C0C 60%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-pagination-number-text: color-mix(in srgb, var(--color-text) 60%, transparent); + } + --color-pagination-number-hover-bg: color-mix(in srgb, #0B0C0C 10%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-pagination-number-hover-bg: color-mix(in srgb, var(--color-text) 10%, transparent); + } + --color-pagination-number-active-bg: color-mix(in srgb, #0B0C0C 20%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-pagination-number-active-bg: color-mix(in srgb, var(--color-text) 20%, transparent); + } + --color-pagination-number-disabled-text: color-mix(in srgb, #0B0C0C 40%, transparent); + @supports (color: color-mix(in lab, red, red)) { + --color-pagination-number-disabled-text: color-mix(in srgb, var(--color-text) 40%, transparent); + } +} +:root { + --btn-hover-translate: -0.1rem; +} +html, body { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; } -.nav { +.app-nav-link { display: flex; - border-top-right-radius: var(--radius-lg); - border-bottom-right-radius: var(--radius-lg); - border-left-style: var(--tw-border-style); - border-left-width: 2px; - border-color: var(--color-gray-300); - padding-block: calc(var(--spacing) * 2); - padding-inline-start: calc(var(--spacing) * 3); - color: var(--color-gray-500); - transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; + align-items: center; + gap: calc(var(--spacing) * 1.5); + border-radius: var(--radius-md); + padding-inline: calc(var(--spacing) * 2.5); + padding-block: calc(var(--spacing) * 1.5); + color: var(--color-text-light); + transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; &:hover { @media (hover: hover) { - border-color: var(--color-gray-500); + background-color: var(--color-primary-light); } } &:hover { @media (hover: hover) { - color: var(--color-gray-800); + color: var(--color-primary); } } } -.nav-collapse-button { - transform: rotate(0deg); - transition: transform .2s linear; -} -.nav-collapse-button.open { - transform: rotate(180deg); - transition: transform .2s linear; -} -.nav-active { - border-color: var(--color-gray-600); - --tw-font-weight: var(--font-weight-bold); - font-weight: var(--font-weight-bold); - color: var(--color-black); -} -.simple-border { - border-radius: var(--radius-xl); - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-gray-300); - background-clip: border-box; - padding: calc(var(--spacing) * 2); -} -.btn { - display: inline-flex; - cursor: pointer; - border-radius: var(--radius-lg); - padding-inline: calc(var(--spacing) * 4); - padding-block: calc(var(--spacing) * 2); +.app-nav-link.active { + background-color: var(--color-primary-light); --tw-font-weight: var(--font-weight-medium); font-weight: var(--font-weight-medium); - transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; - &:disabled { - pointer-events: none; - } - &:disabled { - opacity: 70%; - } + color: var(--color-primary); } -.btn-red { - background-color: var(--color-red-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-red-600); - } - } +h1:focus { + outline: none; } -.btn-outline-red { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-red-500); - background-color: transparent; - color: var(--color-red-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-red-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; } -.btn-no-bg-red { - background-color: transparent; - color: var(--color-red-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } +.invalid { + outline: 1px solid red; } -.btn-orange { - background-color: var(--color-orange-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-orange-600); - } - } +.validation-message { + color: red; } -.btn-outline-orange { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-orange-500); - background-color: transparent; - color: var(--color-orange-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-orange-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } +@property --tw-space-y-reverse { + syntax: "*"; + inherits: false; + initial-value: 0; } -.btn-no-bg-orange { - background-color: transparent; - color: var(--color-orange-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } +@property --tw-border-style { + syntax: "*"; + inherits: false; + initial-value: solid; } -.btn-amber { - background-color: var(--color-amber-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-amber-600); - } - } +@property --tw-leading { + syntax: "*"; + inherits: false; } -.btn-outline-amber { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-amber-500); - background-color: transparent; - color: var(--color-amber-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-amber-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } +@property --tw-font-weight { + syntax: "*"; + inherits: false; } -.btn-no-bg-amber { - background-color: transparent; - color: var(--color-amber-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } +@property --tw-tracking { + syntax: "*"; + inherits: false; } -.btn-yellow { - background-color: var(--color-yellow-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-yellow-600); - } - } +@property --tw-shadow { + syntax: "*"; + inherits: false; + initial-value: 0 0 #0000; } -.btn-outline-yellow { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-yellow-500); - background-color: transparent; - color: var(--color-yellow-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-yellow-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } +@property --tw-shadow-color { + syntax: "*"; + inherits: false; } -.btn-no-bg-yellow { - background-color: transparent; - color: var(--color-yellow-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-lime { - background-color: var(--color-lime-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-lime-600); - } - } -} -.btn-outline-lime { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-lime-500); - background-color: transparent; - color: var(--color-lime-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-lime-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-lime { - background-color: transparent; - color: var(--color-lime-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-green { - background-color: var(--color-green-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-green-600); - } - } -} -.btn-outline-green { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-green-500); - background-color: transparent; - color: var(--color-green-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-green-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-green { - background-color: transparent; - color: var(--color-green-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-emerald { - background-color: var(--color-emerald-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-emerald-600); - } - } -} -.btn-outline-emerald { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-emerald-500); - background-color: transparent; - color: var(--color-emerald-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-emerald-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-emerald { - background-color: transparent; - color: var(--color-emerald-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-teal { - background-color: var(--color-teal-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-teal-600); - } - } -} -.btn-outline-teal { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-teal-500); - background-color: transparent; - color: var(--color-teal-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-teal-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-teal { - background-color: transparent; - color: var(--color-teal-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-cyan { - background-color: var(--color-cyan-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-cyan-600); - } - } -} -.btn-outline-cyan { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-cyan-500); - background-color: transparent; - color: var(--color-cyan-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-cyan-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-cyan { - background-color: transparent; - color: var(--color-cyan-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-sky { - background-color: var(--color-sky-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-sky-600); - } - } -} -.btn-outline-sky { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-sky-500); - background-color: transparent; - color: var(--color-sky-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-sky-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-sky { - background-color: transparent; - color: var(--color-sky-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-blue { - background-color: var(--color-blue-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-blue-600); - } - } -} -.btn-outline-blue { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-blue-500); - background-color: transparent; - color: var(--color-blue-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-blue-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-blue { - background-color: transparent; - color: var(--color-blue-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-indigo { - background-color: var(--color-indigo-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-indigo-600); - } - } -} -.btn-outline-indigo { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-indigo-500); - background-color: transparent; - color: var(--color-indigo-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-indigo-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-indigo { - background-color: transparent; - color: var(--color-indigo-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-violet { - background-color: var(--color-violet-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-violet-600); - } - } -} -.btn-outline-violet { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-violet-500); - background-color: transparent; - color: var(--color-violet-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-violet-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-violet { - background-color: transparent; - color: var(--color-violet-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-purple { - background-color: var(--color-purple-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-purple-600); - } - } -} -.btn-outline-purple { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-purple-500); - background-color: transparent; - color: var(--color-purple-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-purple-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-purple { - background-color: transparent; - color: var(--color-purple-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-fuchsia { - background-color: var(--color-fuchsia-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-fuchsia-600); - } - } -} -.btn-outline-fuchsia { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-fuchsia-500); - background-color: transparent; - color: var(--color-fuchsia-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-fuchsia-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-fuchsia { - background-color: transparent; - color: var(--color-fuchsia-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-pink { - background-color: var(--color-pink-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-pink-600); - } - } -} -.btn-outline-pink { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-pink-500); - background-color: transparent; - color: var(--color-pink-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-pink-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-pink { - background-color: transparent; - color: var(--color-pink-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-rose { - background-color: var(--color-rose-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-rose-600); - } - } -} -.btn-outline-rose { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-rose-500); - background-color: transparent; - color: var(--color-rose-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-rose-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-rose { - background-color: transparent; - color: var(--color-rose-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-slate { - background-color: var(--color-slate-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-slate-600); - } - } -} -.btn-outline-slate { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-slate-500); - background-color: transparent; - color: var(--color-slate-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-slate-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-slate { - background-color: transparent; - color: var(--color-slate-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-gray { - background-color: var(--color-gray-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-600); - } - } -} -.btn-outline-gray { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-gray-500); - background-color: transparent; - color: var(--color-gray-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-gray { - background-color: transparent; - color: var(--color-gray-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-zinc { - background-color: var(--color-zinc-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-zinc-600); - } - } -} -.btn-outline-zinc { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-zinc-500); - background-color: transparent; - color: var(--color-zinc-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-zinc-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-zinc { - background-color: transparent; - color: var(--color-zinc-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-neutral { - background-color: var(--color-neutral-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-neutral-600); - } - } -} -.btn-outline-neutral { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-neutral-500); - background-color: transparent; - color: var(--color-neutral-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-neutral-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-neutral { - background-color: transparent; - color: var(--color-neutral-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-stone { - background-color: var(--color-stone-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-stone-600); - } - } -} -.btn-outline-stone { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-stone-500); - background-color: transparent; - color: var(--color-stone-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-stone-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-stone { - background-color: transparent; - color: var(--color-stone-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-primary { - background-color: var(--color-primary-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-primary-600); - } - } -} -.btn-outline-primary { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-primary-500); - background-color: transparent; - color: var(--color-primary-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-primary-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-primary { - background-color: transparent; - color: var(--color-primary-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-secondary { - background-color: var(--color-secondary-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-secondary-600); - } - } -} -.btn-outline-secondary { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-secondary-500); - background-color: transparent; - color: var(--color-secondary-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-secondary-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-secondary { - background-color: transparent; - color: var(--color-secondary-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-active { - background-color: var(--color-active-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-active-600); - } - } -} -.btn-outline-active { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-active-500); - background-color: transparent; - color: var(--color-active-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-active-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-active { - background-color: transparent; - color: var(--color-active-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-inactive { - background-color: var(--color-inactive-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-inactive-600); - } - } -} -.btn-outline-inactive { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-inactive-500); - background-color: transparent; - color: var(--color-inactive-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-inactive-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-inactive { - background-color: transparent; - color: var(--color-inactive-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-info { - background-color: var(--color-info-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-info-600); - } - } -} -.btn-outline-info { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-info-500); - background-color: transparent; - color: var(--color-info-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-info-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-info { - background-color: transparent; - color: var(--color-info-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-success { - background-color: var(--color-success-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-success-600); - } - } -} -.btn-outline-success { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-success-500); - background-color: transparent; - color: var(--color-success-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-success-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-success { - background-color: transparent; - color: var(--color-success-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-warning { - background-color: var(--color-warning-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-warning-600); - } - } -} -.btn-outline-warning { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-warning-500); - background-color: transparent; - color: var(--color-warning-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-warning-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-warning { - background-color: transparent; - color: var(--color-warning-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-danger { - background-color: var(--color-danger-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-danger-600); - } - } -} -.btn-outline-danger { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-danger-500); - background-color: transparent; - color: var(--color-danger-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-danger-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-danger { - background-color: transparent; - color: var(--color-danger-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-attention { - background-color: var(--color-attention-500); - color: var(--color-white); - &:hover { - @media (hover: hover) { - background-color: var(--color-attention-600); - } - } -} -.btn-outline-attention { - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-attention-500); - background-color: transparent; - color: var(--color-attention-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-attention-500); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-white); - } - } -} -.btn-no-bg-attention { - background-color: transparent; - color: var(--color-attention-500); - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.btn-group { - display: inline-flex; - flex-wrap: wrap; - align-items: center; - border-radius: var(--radius-lg); -} -.btn-group > .btn { - border-radius: 0; - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-gray-200); -} -.btn-group > .btn:first-child { - border-top-left-radius: var(--radius-lg); - border-bottom-left-radius: var(--radius-lg); -} -.btn-group > .btn:last-child { - border-top-right-radius: var(--radius-lg); - border-bottom-right-radius: var(--radius-lg); -} -.disabled { - color: var(--color-gray-500); -} -.invalid-feedback:not(.is-invalid) { - display: none; -} -.invalid-feedback { - margin-inline-start: calc(var(--spacing) * 1); - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); -} -.is-invalid { - color: var(--color-red-500); -} -.input { - display: flex; - flex-wrap: wrap; - align-items: center; -} -.input > input { - margin-block: calc(var(--spacing) * 1); - max-width: 100%; - border-radius: var(--radius-lg); - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-gray-200); - padding-inline: calc(var(--spacing) * 3); - padding-block: calc(var(--spacing) * 1); - &:focus { - outline-style: var(--tw-outline-style); - outline-width: 2px; - } - &:focus { - outline-color: var(--color-primary-500); - } -} -.input > label { - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - color: var(--color-gray-800); -} -.input-checkbox { - margin-block: calc(var(--spacing) * 1); - display: flex; - align-items: center; -} -.input-checkbox > label:first-child { - position: relative; - display: flex; - cursor: pointer; - align-items: center; -} -.input-checkbox > label:first-child > input { - height: calc(var(--spacing) * 5); - width: calc(var(--spacing) * 5); - cursor: pointer; - appearance: none; - border-radius: 0.25rem; - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-gray-200); - transition-property: all; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - &:checked { - border-color: var(--color-primary-500); - } - &:checked { - background-color: var(--color-primary-500); - } -} -.input-checkbox > label:first-child > span { - position: absolute; - top: calc(1/2 * 100%); - left: calc(1/2 * 100%); - --tw-translate-x: calc(calc(1/2 * 100%) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - --tw-translate-y: calc(calc(1/2 * 100%) * -1); - translate: var(--tw-translate-x) var(--tw-translate-y); - transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); - color: var(--color-white); - opacity: 0%; - &:is(:where(.peer):checked ~ *) { - opacity: 100%; - } -} -.input-checkbox > label:last-child { - margin-left: calc(var(--spacing) * 2); - cursor: pointer; - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - color: var(--color-gray-800); -} -.input-radio { - display: flex; - align-items: center; - column-gap: calc(var(--spacing) * 3); -} -.input-radio > input { - position: relative; - width: calc(var(--spacing) * 4); - height: calc(var(--spacing) * 4); - appearance: none; - border-radius: calc(infinity * 1px); - border-style: var(--tw-border-style); - border-width: 1px; - border-color: var(--color-gray-200); - &::before { - content: var(--tw-content); - position: absolute; - } - &::before { - content: var(--tw-content); - inset: calc(var(--spacing) * 1); - } - &::before { - content: var(--tw-content); - border-radius: calc(infinity * 1px); - } - &::before { - content: var(--tw-content); - background-color: var(--color-white); - } - &:not(*:checked) { - &::before { - content: var(--tw-content); - display: none; - } - } - &:checked { - border-color: var(--color-primary-500); - } - &:checked { - background-color: var(--color-primary-500); - } - &:focus-visible { - outline-style: var(--tw-outline-style); - outline-width: 2px; - } - &:focus-visible { - outline-offset: 2px; - } - &:focus-visible { - outline-color: var(--color-primary-500); - } - &:disabled { - border-color: var(--color-gray-200); - } - &:disabled { - background-color: var(--color-gray-100); - } - &:disabled { - &::before { - content: var(--tw-content); - background-color: var(--color-gray-400); - } - } - @media (forced-colors: active) { - appearance: auto; - } - @media (forced-colors: active) { - &::before { - content: var(--tw-content); - display: none; - } - } -} -.input-radio > label { - display: block; - color: var(--color-gray-800); -} -.select { - cursor: pointer; - border-radius: var(--radius-lg); - background-color: var(--color-gray-100); - padding: calc(var(--spacing) * 2); - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - color: var(--color-gray-900); - &:focus { - --tw-outline-style: none; - outline-style: none; - } -} -.input-file { - display: flex; - flex-wrap: wrap; - align-items: center; -} -.input-file > input { - max-width: 100%; - cursor: pointer; - border-radius: var(--radius-lg); - color: var(--color-gray-900); -} -.input-file > label { - color: var(--color-gray-800); -} -.input-file > input::file-selector-button { - cursor: pointer; - background-color: var(--color-gray-50); - padding: calc(var(--spacing) * 2); - color: var(--color-gray-900); -} -.card { - border-radius: var(--radius-xl); - background-color: var(--color-white); - background-clip: border-box; - padding: calc(var(--spacing) * 4); - --tw-shadow: 0 4px 6px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 2px 4px -2px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); - box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); -} -.collapse-button-icon { - margin-block: auto; - transform: rotate(0deg); - transition: transform .2s linear; -} -.collapse-button-icon.open { - transform: rotate(180deg); - transition: transform .2s linear; -} -.dropdown { - position: relative; - display: inline-block; - text-align: left; -} -.dropdown-body, .dropdown-body-start { - position: absolute; - left: calc(var(--spacing) * 0); - z-index: 10; -} -.dropdown-body-end { - position: absolute; - right: calc(var(--spacing) * 0); - z-index: 10; -} -.alert { - display: flex; - border-radius: var(--radius-lg); - padding-inline: calc(var(--spacing) * 4); - padding-block: calc(var(--spacing) * 4); - color: var(--color-gray-700); -} -.tab { - display: flex; - cursor: pointer; - border-bottom-style: var(--tw-border-style); - border-bottom-width: 2px; - border-color: var(--color-gray-300); - padding-inline: calc(var(--spacing) * 6); - padding-block: calc(var(--spacing) * 4); - font-size: var(--text-base); - line-height: var(--tw-leading, var(--text-base--line-height)); - --tw-font-weight: var(--font-weight-medium); - font-weight: var(--font-weight-medium); - color: var(--color-gray-500); - &:hover { - @media (hover: hover) { - border-color: var(--color-gray-800); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-gray-800); - } - } -} -.tab-active { - border-color: var(--color-primary-500); - --tw-font-weight: var(--font-weight-bold); - font-weight: var(--font-weight-bold); - color: var(--color-primary-500); - &:hover { - @media (hover: hover) { - border-color: var(--color-primary-600); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-primary-600); - } - } -} -.accordion { - width: 100%; -} -.accordion > .accordion-item { - width: 100%; - padding-inline: calc(var(--spacing) * 4); -} -.accordion > .accordion-item > .accordion-button { - display: flex; - width: 100%; - cursor: pointer; - border-bottom-style: var(--tw-border-style); - border-bottom-width: 2px; - border-color: var(--color-gray-300); - padding-inline: calc(var(--spacing) * 4); - padding-block: calc(var(--spacing) * 4); - font-size: var(--text-base); - line-height: var(--tw-leading, var(--text-base--line-height)); - --tw-font-weight: var(--font-weight-medium); - font-weight: var(--font-weight-medium); - color: var(--color-gray-500); - transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, visibility, content-visibility, overlay, pointer-events; - transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); - transition-duration: var(--tw-duration, var(--default-transition-duration)); - --tw-duration: 200ms; - transition-duration: 200ms; - &:hover { - @media (hover: hover) { - border-color: var(--color-gray-800); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-gray-800); - } - } -} -.accordion > .accordion-item > .accordion-button.accordion-button-active { - border-color: var(--color-primary-500); - --tw-font-weight: var(--font-weight-bold); - font-weight: var(--font-weight-bold); - color: var(--color-primary-500); - &:hover { - @media (hover: hover) { - border-color: var(--color-primary-600); - } - } - &:hover { - @media (hover: hover) { - color: var(--color-primary-600); - } - } -} -.accordion > .accordion-item > .accordion-button > .accordion-button-icon { - margin-block: auto; - margin-inline-start: auto; - transform: rotate(0deg); - transition: transform .2s linear; -} -.accordion > .accordion-item > .accordion-button > .accordion-button-icon.open { - transform: rotate(180deg); - transition: transform .2s linear; -} -.accordion > .accordion-item > .accordion-body { - border-bottom-style: var(--tw-border-style); - border-bottom-width: 2px; - border-color: var(--color-gray-300); - padding-inline: calc(var(--spacing) * 1); - padding-block: calc(var(--spacing) * 4); -} -.accordion > .accordion-item:last-child > .accordion-body { - border-bottom-style: var(--tw-border-style); - border-bottom-width: 0px; -} -.table { - table-layout: auto; - display: table; - width: 100%; - :where(& > :not(:last-child)) { - --tw-divide-y-reverse: 0; - border-bottom-style: var(--tw-border-style); - border-top-style: var(--tw-border-style); - border-top-width: calc(1px * var(--tw-divide-y-reverse)); - border-bottom-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - } - :where(& > :not(:last-child)) { - border-color: var(--color-gray-200); - } - text-align: left; - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - white-space: nowrap; -} -.table:not(.table-stripped) > tbody { - :where(& > :not(:last-child)) { - --tw-divide-y-reverse: 0; - border-bottom-style: var(--tw-border-style); - border-top-style: var(--tw-border-style); - border-top-width: calc(1px * var(--tw-divide-y-reverse)); - border-bottom-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - } - :where(& > :not(:last-child)) { - border-color: var(--color-gray-200); - } -} -.table-striped > tbody > tr { - &:nth-child(odd) { - background-color: var(--color-white); - } - &:nth-child(even) { - background-color: var(--color-gray-50); - } -} -.table th { - padding-inline: calc(var(--spacing) * 6); - padding-block: calc(var(--spacing) * 3); - font-size: var(--text-base); - line-height: var(--tw-leading, var(--text-base--line-height)); - --tw-font-weight: var(--font-weight-bold); - font-weight: var(--font-weight-bold); - --tw-tracking: var(--tracking-wider); - letter-spacing: var(--tracking-wider); - color: var(--color-gray-800); -} -.table td { - padding-inline: calc(var(--spacing) * 6); - padding-block: calc(var(--spacing) * 4); - font-size: var(--text-sm); - line-height: var(--tw-leading, var(--text-sm--line-height)); - color: var(--color-gray-700); -} -.table > tbody > tr { - --tw-duration: 100ms; - transition-duration: 100ms; - &:hover { - @media (hover: hover) { - background-color: var(--color-gray-100); - } - } -} -.table-dense td { - padding-inline: calc(var(--spacing) * 2); - padding-block: calc(var(--spacing) * 1.5); -} -html, body { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; -} -h1:focus { - outline: none; -} -a, .btn-link { - color: #0071c1; -} -.btn-primary { - color: #fff; - background-color: #1b6ec2; - border-color: #1861ac; -} -.content { - padding-top: 1.1rem; -} -.valid.modified:not([type=checkbox]) { - outline: 1px solid #26b050; -} -.invalid { - outline: 1px solid red; -} -.validation-message { - color: red; -} -#blazor-error-ui { - background: lightyellow; - bottom: 0; - box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); - display: none; - left: 0; - padding: 0.6rem 1.25rem 0.7rem 1.25rem; - position: fixed; - width: 100%; - z-index: 1000; -} -#blazor-error-ui .dismiss { - cursor: pointer; - position: absolute; - right: 0.75rem; - top: 0.5rem; -} -.blazor-error-boundary { - background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; - padding: 1rem 1rem 1rem 3.7rem; - color: white; -} -.blazor-error-boundary::after { - content: "An error has occurred."; -} -@property --tw-rotate-x { - syntax: "*"; - inherits: false; -} -@property --tw-rotate-y { - syntax: "*"; - inherits: false; -} -@property --tw-rotate-z { - syntax: "*"; - inherits: false; -} -@property --tw-skew-x { - syntax: "*"; - inherits: false; -} -@property --tw-skew-y { - syntax: "*"; - inherits: false; -} -@property --tw-border-style { - syntax: "*"; - inherits: false; - initial-value: solid; -} -@property --tw-font-weight { - syntax: "*"; - inherits: false; -} -@property --tw-shadow { - syntax: "*"; - inherits: false; - initial-value: 0 0 #0000; -} -@property --tw-shadow-color { - syntax: "*"; - inherits: false; -} -@property --tw-shadow-alpha { - syntax: ""; - inherits: false; - initial-value: 100%; +@property --tw-shadow-alpha { + syntax: ""; + inherits: false; + initial-value: 100%; } @property --tw-inset-shadow { syntax: "*"; @@ -2547,54 +1256,14 @@ a, .btn-link { inherits: false; initial-value: 0 0 #0000; } -@property --tw-duration { - syntax: "*"; - inherits: false; -} -@property --tw-outline-style { - syntax: "*"; - inherits: false; - initial-value: solid; -} -@property --tw-translate-x { - syntax: "*"; - inherits: false; - initial-value: 0; -} -@property --tw-translate-y { - syntax: "*"; - inherits: false; - initial-value: 0; -} -@property --tw-translate-z { - syntax: "*"; - inherits: false; - initial-value: 0; -} -@property --tw-content { - syntax: "*"; - initial-value: ""; - inherits: false; -} -@property --tw-divide-y-reverse { - syntax: "*"; - inherits: false; - initial-value: 0; -} -@property --tw-tracking { - syntax: "*"; - inherits: false; -} @layer properties { @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) { *, ::before, ::after, ::backdrop { - --tw-rotate-x: initial; - --tw-rotate-y: initial; - --tw-rotate-z: initial; - --tw-skew-x: initial; - --tw-skew-y: initial; + --tw-space-y-reverse: 0; --tw-border-style: solid; + --tw-leading: initial; --tw-font-weight: initial; + --tw-tracking: initial; --tw-shadow: 0 0 #0000; --tw-shadow-color: initial; --tw-shadow-alpha: 100%; @@ -2609,14 +1278,6 @@ a, .btn-link { --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; - --tw-duration: initial; - --tw-outline-style: solid; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-translate-z: 0; - --tw-content: ""; - --tw-divide-y-reverse: 0; - --tw-tracking: initial; } } } diff --git a/src/sanbox/integration/ix-integration-blazor/wwwroot/js/theme.js b/src/sanbox/integration/ix-integration-blazor/wwwroot/js/theme.js new file mode 100644 index 000000000..459ba97eb --- /dev/null +++ b/src/sanbox/integration/ix-integration-blazor/wwwroot/js/theme.js @@ -0,0 +1,22 @@ +window.themeManager = { + init: () => { + if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { + document.documentElement.setAttribute('data-theme', 'dark'); + } else { + document.documentElement.setAttribute('data-theme', 'light'); + } + }, + setLight: () => { + localStorage.theme = 'light'; + document.documentElement.setAttribute('data-theme', 'light'); + }, + setDark: () => { + localStorage.theme = 'dark'; + document.documentElement.setAttribute('data-theme', 'dark'); + }, + setSystem: () => { + localStorage.removeItem('theme'); + // re-run init to pick up OS setting + window.themeManager.init(); + } +}; diff --git a/src/sanbox/integration/ix-integration-plc/apax.yml b/src/sanbox/integration/ix-integration-plc/apax.yml index 1632b9fda..003d21d5a 100644 --- a/src/sanbox/integration/ix-integration-plc/apax.yml +++ b/src/sanbox/integration/ix-integration-plc/apax.yml @@ -16,7 +16,7 @@ variables: AXTARGET: 192.168.100.85 AXTARGETPLATFORMINPUT: .\bin\1500\ AX_USERNAME: "admin" - AX_TARGET_PWD: "123ABCDabcd$#!" + AX_TARGET_PWD: "/op" USE_PLC_SIM_ADVANCED: "false" HWCONFIG: "HWC" COM_CERT_PATH: .\certs\Communication.cer