feat: refine workspace bevel hierarchy
This commit is contained in:
@@ -51,7 +51,7 @@
|
||||
--interactive-selected: oklch(93% 0.02 230);
|
||||
--bevel-highlight: #fff;
|
||||
--bevel-shadow: #000;
|
||||
--bevel-face-width: 2px;
|
||||
--bevel-face-width: 1px;
|
||||
--shadow-overlay: 0 12px 32px oklch(0% 0 0 / 0.14);
|
||||
|
||||
--font-sans: "Gen Interface JP", sans-serif;
|
||||
|
||||
@@ -1,60 +1,51 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
import BevelLine from '$lib/workspace/ui/BevelLine.svelte';
|
||||
import Bevel from '$lib/workspace/ui/Bevel.svelte';
|
||||
import './sidebar.css';
|
||||
|
||||
type Props = {
|
||||
children: Snippet<[]>;
|
||||
folded?: boolean;
|
||||
};
|
||||
|
||||
let { children }: Props = $props();
|
||||
let folded = $state(false);
|
||||
let { children, folded = $bindable(false) }: Props = $props();
|
||||
|
||||
function toggleFold() {
|
||||
folded = !folded;
|
||||
}
|
||||
</script>
|
||||
|
||||
<aside class="sidebar-frame" class:folded aria-label="Sidebar">
|
||||
{#if !folded}
|
||||
<div class="sidebar-frame-content">
|
||||
{@render children()}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="sidebar-control-row">
|
||||
<button
|
||||
class="sidebar-fold-button"
|
||||
type="button"
|
||||
aria-label={folded ? 'Unfold sidebar' : 'Fold sidebar'}
|
||||
aria-expanded={!folded}
|
||||
title={folded ? 'Unfold sidebar' : 'Fold sidebar'}
|
||||
onclick={toggleFold}
|
||||
>
|
||||
{#if folded}
|
||||
<svg class="sidebar-icon" aria-hidden="true" viewBox="0 0 24 24">
|
||||
<path d="m6 17 5-5-5-5" />
|
||||
<path d="m13 17 5-5-5-5" />
|
||||
</svg>
|
||||
{:else}
|
||||
<svg class="sidebar-icon" aria-hidden="true" viewBox="0 0 24 24">
|
||||
<path d="m11 17-5-5 5-5" />
|
||||
<path d="m18 17-5-5 5-5" />
|
||||
</svg>
|
||||
<div class="sidebar-frame" class:folded>
|
||||
<Bevel as="div" class="sidebar-frame__bevel" depth="inset" top={false} bottom={false} left={false} fill>
|
||||
<aside class="sidebar-frame__surface" aria-label="Sidebar">
|
||||
{#if !folded}
|
||||
<div class="sidebar-frame-content">
|
||||
{@render children()}
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<BevelLine
|
||||
class="sidebar-frame__divider sidebar-frame__divider--vertical"
|
||||
direction="y"
|
||||
length="100%"
|
||||
decorative
|
||||
/>
|
||||
<BevelLine
|
||||
class="sidebar-frame__divider sidebar-frame__divider--horizontal"
|
||||
direction="x"
|
||||
length="100%"
|
||||
decorative
|
||||
/>
|
||||
</aside>
|
||||
<div class="sidebar-control-row">
|
||||
<button
|
||||
class="sidebar-fold-button"
|
||||
type="button"
|
||||
aria-label={folded ? 'Unfold sidebar' : 'Fold sidebar'}
|
||||
aria-expanded={!folded}
|
||||
title={folded ? 'Unfold sidebar' : 'Fold sidebar'}
|
||||
onclick={toggleFold}
|
||||
>
|
||||
{#if folded}
|
||||
<svg class="sidebar-icon" aria-hidden="true" viewBox="0 0 24 24">
|
||||
<path d="m6 17 5-5-5-5" />
|
||||
<path d="m13 17 5-5-5-5" />
|
||||
</svg>
|
||||
{:else}
|
||||
<svg class="sidebar-icon" aria-hidden="true" viewBox="0 0 24 24">
|
||||
<path d="m11 17-5-5 5-5" />
|
||||
<path d="m18 17-5-5 5-5" />
|
||||
</svg>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
</Bevel>
|
||||
</div>
|
||||
|
||||
@@ -5,31 +5,28 @@
|
||||
--sidebar-item-hover: oklch(96% 0 0);
|
||||
--sidebar-item-active: oklch(92.5% 0 0);
|
||||
|
||||
display: grid;
|
||||
grid-column: 1;
|
||||
grid-row: 1 / 3;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: clamp(220px, 20vw, 280px);
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.sidebar-frame .bevel.sidebar-frame__bevel {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
.sidebar-frame__surface {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding-block: var(--space-4);
|
||||
}
|
||||
.sidebar-frame__divider {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
}
|
||||
.sidebar-frame__divider--vertical {
|
||||
inset-block: 0;
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
.sidebar-frame__divider--horizontal {
|
||||
display: none;
|
||||
inset-inline: 0;
|
||||
inset-block-end: 0;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.sidebar-frame {
|
||||
--sidebar-item-hover: oklch(24% 0 0);
|
||||
@@ -39,7 +36,6 @@
|
||||
.sidebar-frame.folded {
|
||||
width: max-content;
|
||||
overflow: hidden;
|
||||
padding-inline: 0;
|
||||
}
|
||||
.sidebar-frame-content {
|
||||
flex: 1 1 auto;
|
||||
@@ -628,17 +624,18 @@
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.sidebar-frame,
|
||||
.sidebar-frame.folded {
|
||||
.sidebar-frame {
|
||||
z-index: 20;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
width: auto;
|
||||
grid-row: 2;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.sidebar-frame__divider--vertical {
|
||||
.sidebar-frame.folded {
|
||||
display: none;
|
||||
}
|
||||
.sidebar-frame__divider--horizontal {
|
||||
display: block;
|
||||
.sidebar-control-row {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
inset: 0;
|
||||
box-sizing: border-box;
|
||||
border-style: solid;
|
||||
border-color: var(--line-strong);
|
||||
border-color: var(--_fallback-border, var(--line-strong));
|
||||
border-width: var(--_top-w) var(--_right-w) var(--_bottom-w) var(--_left-w);
|
||||
border-radius: inherit;
|
||||
pointer-events: none;
|
||||
@@ -155,11 +155,11 @@
|
||||
}
|
||||
|
||||
.bevel[data-profile='edge'][data-depth='inset']::before {
|
||||
border-color: var(--line);
|
||||
--_fallback-border: var(--line);
|
||||
}
|
||||
|
||||
.bevel[data-profile='ridge'][data-depth='inset']::before {
|
||||
border-color: var(--line);
|
||||
--_fallback-border: var(--line);
|
||||
}
|
||||
|
||||
.bevel[data-profile='ridge']::after {
|
||||
@@ -168,7 +168,7 @@
|
||||
var(--bevel-right-inset)
|
||||
var(--bevel-bottom-inset)
|
||||
var(--bevel-left-inset);
|
||||
border-color: var(--line);
|
||||
--_fallback-border: var(--line);
|
||||
border-radius:
|
||||
max(0px, calc(var(--bevel-top-left-radius) - var(--bevel-face-width)))
|
||||
max(0px, calc(var(--bevel-top-right-radius) - var(--bevel-face-width)))
|
||||
@@ -177,7 +177,7 @@
|
||||
}
|
||||
|
||||
.bevel[data-profile='ridge'][data-depth='inset']::after {
|
||||
border-color: var(--line-strong);
|
||||
--_fallback-border: var(--line-strong);
|
||||
}
|
||||
|
||||
.bevel[data-invalid='true'],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { page } from '$app/state';
|
||||
import { setContext } from 'svelte';
|
||||
import WorkspaceAlerts from '$lib/workspace/alerts/WorkspaceAlerts.svelte';
|
||||
import BevelLine from '$lib/workspace/ui/BevelLine.svelte';
|
||||
import Bevel from '$lib/workspace/ui/Bevel.svelte';
|
||||
import { provideHeaderController, type HeaderController } from '$lib/workspace/header/context';
|
||||
import GlobalSidebar from '$lib/workspace/sidebar/GlobalSidebar.svelte';
|
||||
import SidebarFrame from '$lib/workspace/sidebar/SidebarFrame.svelte';
|
||||
@@ -17,6 +17,11 @@
|
||||
sidebar = activeSidebar;
|
||||
});
|
||||
const headerController = $state<HeaderController>({ content: null });
|
||||
let sidebarFolded = $state(false);
|
||||
|
||||
function toggleSidebar() {
|
||||
sidebarFolded = !sidebarFolded;
|
||||
}
|
||||
|
||||
provideHeaderController(headerController);
|
||||
setContext<SidebarController>(SIDEBAR_CONTEXT, {
|
||||
@@ -26,8 +31,8 @@
|
||||
|
||||
<WorkspaceAlerts />
|
||||
|
||||
<div class="app-shell">
|
||||
<SidebarFrame>
|
||||
<div class="app-shell" class:sidebar-open={!sidebarFolded}>
|
||||
<SidebarFrame bind:folded={sidebarFolded}>
|
||||
<GlobalSidebar
|
||||
currentPath={page.url.pathname}
|
||||
content={sidebar}
|
||||
@@ -35,25 +40,39 @@
|
||||
workspaceError={data.workspaceCatalogError}
|
||||
/>
|
||||
</SidebarFrame>
|
||||
<header class="app-shell__topbar">
|
||||
<div class="app-shell__topbar-location">
|
||||
{#if headerController.content}{@render headerController.content()}{/if}
|
||||
</div>
|
||||
<nav class="app-shell__topbar-actions" aria-label="Global navigation">
|
||||
<a class="app-shell__icon-button" href="/account" aria-label="Open Account" title="Account">
|
||||
<svg class="app-shell__icon" aria-hidden="true" viewBox="0 0 24 24">
|
||||
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
|
||||
<circle cx="12" cy="7" r="4" />
|
||||
</svg>
|
||||
</a>
|
||||
</nav>
|
||||
<BevelLine
|
||||
class="app-shell__topbar-divider"
|
||||
direction="x"
|
||||
length="100%"
|
||||
decorative
|
||||
/>
|
||||
</header>
|
||||
<Bevel as="div" class="app-shell__topbar-bevel" depth="inset" top={false} right={false} left={false} fill>
|
||||
<header class="app-shell__topbar">
|
||||
<div class="app-shell__topbar-location">
|
||||
{#if headerController.content}{@render headerController.content()}{/if}
|
||||
</div>
|
||||
<nav class="app-shell__topbar-actions" aria-label="Global navigation">
|
||||
<button
|
||||
class="app-shell__icon-button app-shell__mobile-sidebar-toggle"
|
||||
type="button"
|
||||
aria-label={sidebarFolded ? 'Show sidebar' : 'Hide sidebar'}
|
||||
aria-expanded={!sidebarFolded}
|
||||
title={sidebarFolded ? 'Show sidebar' : 'Hide sidebar'}
|
||||
onclick={toggleSidebar}
|
||||
>
|
||||
<svg class="app-shell__icon" aria-hidden="true" viewBox="0 0 24 24">
|
||||
{#if sidebarFolded}
|
||||
<path d="m6 17 5-5-5-5" />
|
||||
<path d="m13 17 5-5-5-5" />
|
||||
{:else}
|
||||
<path d="m11 17-5-5 5-5" />
|
||||
<path d="m18 17-5-5 5-5" />
|
||||
{/if}
|
||||
</svg>
|
||||
</button>
|
||||
<a class="app-shell__icon-button" href="/account" aria-label="Open Account" title="Account">
|
||||
<svg class="app-shell__icon" aria-hidden="true" viewBox="0 0 24 24">
|
||||
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
|
||||
<circle cx="12" cy="7" r="4" />
|
||||
</svg>
|
||||
</a>
|
||||
</nav>
|
||||
</header>
|
||||
</Bevel>
|
||||
<main class="app-shell__main">
|
||||
{@render children()}
|
||||
</main>
|
||||
@@ -72,11 +91,14 @@
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.app-shell__topbar {
|
||||
position: relative;
|
||||
.app-shell :global(.bevel.app-shell__topbar-bevel) {
|
||||
z-index: 30;
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.app-shell__topbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@@ -88,12 +110,6 @@
|
||||
backdrop-filter: blur(14px);
|
||||
}
|
||||
|
||||
:global(.app-shell__topbar-divider) {
|
||||
position: absolute;
|
||||
inset-inline: 0;
|
||||
inset-block-end: 0;
|
||||
}
|
||||
|
||||
.app-shell__topbar-location {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
@@ -123,6 +139,14 @@
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.app-shell__mobile-sidebar-toggle {
|
||||
display: none;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.app-shell__icon {
|
||||
width: 1.1rem;
|
||||
height: 1.1rem;
|
||||
@@ -150,25 +174,36 @@
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.app-shell {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto auto 1fr;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-rows: auto minmax(0, 1fr);
|
||||
width: 100vw;
|
||||
height: auto;
|
||||
min-height: 100dvh;
|
||||
overflow: visible;
|
||||
height: 100dvh;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.app-shell :global(.bevel.app-shell__topbar-bevel) {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.app-shell__topbar {
|
||||
grid-column: 1;
|
||||
grid-row: 2;
|
||||
padding: 0 var(--space-4);
|
||||
}
|
||||
|
||||
.app-shell__mobile-sidebar-toggle {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.app-shell__main {
|
||||
grid-column: 1;
|
||||
grid-row: 3;
|
||||
overflow: visible;
|
||||
grid-row: 2;
|
||||
overflow-y: auto;
|
||||
padding: var(--space-5) var(--space-4);
|
||||
}
|
||||
|
||||
.app-shell.sidebar-open .app-shell__main {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -167,7 +167,6 @@
|
||||
gap: var(--space-4);
|
||||
padding: var(--space-3) var(--space-4);
|
||||
border-radius: inherit;
|
||||
background: var(--bg-raised);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
@@ -297,6 +296,7 @@
|
||||
|
||||
.resource-list {
|
||||
min-width: 0;
|
||||
margin-inline: var(--space-2);
|
||||
}
|
||||
|
||||
.resource-row {
|
||||
@@ -409,7 +409,7 @@
|
||||
|
||||
.key-value,
|
||||
.technical-values {
|
||||
margin: 0;
|
||||
margin: 0 var(--space-2);
|
||||
}
|
||||
|
||||
.key-value > div:not(.bevel-line),
|
||||
@@ -553,6 +553,7 @@
|
||||
.sample-form {
|
||||
display: grid;
|
||||
gap: var(--space-5);
|
||||
margin-inline: var(--space-2);
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
|
||||
@@ -39,10 +39,15 @@ Deno.test("Bevel keeps depth visual while semantic controls remain children", as
|
||||
assert(
|
||||
source.includes("@supports") &&
|
||||
source.includes("border-style: solid") &&
|
||||
source.includes(
|
||||
"border-color: var(--_fallback-border, var(--line-strong))",
|
||||
) &&
|
||||
source.includes("--_fallback-border: var(--line)") &&
|
||||
source.includes("--_fallback-border: var(--line-strong)") &&
|
||||
source.includes(
|
||||
"border-width: var(--_top-w) var(--_right-w) var(--_bottom-w) var(--_left-w)",
|
||||
),
|
||||
"Bevel must retain a side-selective plain border fallback around the enhanced edge",
|
||||
"Bevel fallback colors must not outrank the enhanced transparent border",
|
||||
);
|
||||
assert(
|
||||
source.includes("calc(max(cos(180deg - var(--_L)), 0) * 100%)") &&
|
||||
@@ -52,12 +57,12 @@ Deno.test("Bevel keeps depth visual while semantic controls remain children", as
|
||||
"Bevel must clamp unlit faces to the configured shadow without ambient light",
|
||||
);
|
||||
assert(
|
||||
appCss.includes("--bevel-face-width: 2px") &&
|
||||
appCss.includes("--bevel-face-width: 1px") &&
|
||||
source.includes("--_W: var(--bevel-face-width)") &&
|
||||
source.includes("inset: var(--bevel-face-width)") &&
|
||||
!source.includes("BevelSize") &&
|
||||
!source.includes("data-size"),
|
||||
"Bevel must use the project-wide 2px edge and compose ridge from two 2px faces",
|
||||
"Bevel must use the project-wide 1px edge and compose ridge from two 1px faces",
|
||||
);
|
||||
assert(
|
||||
source.includes("data-top={top ? 'true' : 'false'}") &&
|
||||
@@ -94,9 +99,8 @@ Deno.test("Bevel keeps depth visual while semantic controls remain children", as
|
||||
"Bevel must use the shared highlight and shadow palette without owning a surface tone",
|
||||
);
|
||||
assert(
|
||||
designLanguage.includes("Bevelはedge") &&
|
||||
designLanguage.includes("lightingだけを所有する") &&
|
||||
designLanguage.includes("text/content areaだけとする"),
|
||||
designLanguage.includes("Bevel自体へbackgroundやsurface toneを与えず") &&
|
||||
designLanguage.includes("text/content areaへ適用する"),
|
||||
"The design language must prohibit Bevel surface colors outside the child content area",
|
||||
);
|
||||
assert(
|
||||
@@ -118,6 +122,15 @@ Deno.test("Workspace showroom exercises raised inset and ridge edges", async ()
|
||||
import.meta.url,
|
||||
),
|
||||
);
|
||||
const showroomCss = await Deno.readTextFile(
|
||||
new URL(
|
||||
"../src/routes/design-lab/workspace-web-ux/showroom.css",
|
||||
import.meta.url,
|
||||
),
|
||||
);
|
||||
const tactileGroupRule = showroomCss.match(
|
||||
/\.tactile-group \{([\s\S]*?)\n \}/,
|
||||
)?.[1];
|
||||
|
||||
assert(
|
||||
workspaceSource.includes('profile="edge" depth="raised"') &&
|
||||
@@ -128,6 +141,10 @@ Deno.test("Workspace showroom exercises raised inset and ridge edges", async ()
|
||||
workspaceSource.includes("pressed"),
|
||||
"Workspace showroom must demonstrate edge and ridge depths with full and adjacent side selections",
|
||||
);
|
||||
assert(
|
||||
tactileGroupRule && !tactileGroupRule.includes("background"),
|
||||
"Showroom ridge items must leave their content area background unset",
|
||||
);
|
||||
assert(
|
||||
settingsSource.includes('profile="edge" depth="inset"') &&
|
||||
settingsSource.includes('aria-invalid="true"'),
|
||||
|
||||
@@ -28,14 +28,20 @@ Deno.test("BevelLine exposes a semantic directional separator", async () => {
|
||||
}
|
||||
|
||||
assert(
|
||||
appCss.includes("--bevel-face-width: 2px") &&
|
||||
appCss.includes("--bevel-face-width: 1px") &&
|
||||
source.includes("--bevel-line-face-width: var(--bevel-face-width)") &&
|
||||
source.includes(
|
||||
"--bevel-line-width: calc(var(--bevel-line-face-width) * 2)",
|
||||
) &&
|
||||
!source.includes("BevelLineWeight") &&
|
||||
!source.includes("data-weight"),
|
||||
"BevelLine must compose a fixed 4px ridge from two project-wide 2px faces",
|
||||
"BevelLine must compose a fixed 2px ridge from two project-wide 1px faces",
|
||||
);
|
||||
assert(
|
||||
!source.includes("--bevel-line-inset") &&
|
||||
!source.includes("padding-inline") &&
|
||||
!source.includes("padding-block"),
|
||||
"BevelLine must fill its parent layer without independent endpoint spacing",
|
||||
);
|
||||
assert(
|
||||
source.includes("background: var(--line-strong)") &&
|
||||
@@ -76,7 +82,7 @@ Deno.test("Workspace showroom demonstrates both BevelLine directions", async ()
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test("Workspace shell and showroom use BevelLine for structural separators", async () => {
|
||||
Deno.test("Shell regions use single-edge Bevel while open separators use BevelLine", async () => {
|
||||
const rootLayout = await Deno.readTextFile(
|
||||
new URL("../src/routes/+layout.svelte", import.meta.url),
|
||||
);
|
||||
@@ -95,18 +101,50 @@ Deno.test("Workspace shell and showroom use BevelLine for structural separators"
|
||||
import.meta.url,
|
||||
),
|
||||
);
|
||||
const designLanguage = await Deno.readTextFile(
|
||||
new URL(
|
||||
"../../../docs/development/ui-ux/design-language.md",
|
||||
import.meta.url,
|
||||
),
|
||||
);
|
||||
|
||||
assert(
|
||||
rootLayout.includes("app-shell__topbar-divider") &&
|
||||
sidebarFrame.includes("sidebar-frame__divider--vertical") &&
|
||||
sidebarFrame.includes("sidebar-frame__divider--horizontal"),
|
||||
"Workspace shell must render structural dividers through BevelLine",
|
||||
rootLayout.includes('class="app-shell__topbar-bevel"') &&
|
||||
rootLayout.includes('depth="inset"') &&
|
||||
rootLayout.includes("top={false} right={false} left={false}") &&
|
||||
rootLayout.includes("bind:folded={sidebarFolded}") &&
|
||||
rootLayout.includes("app-shell__mobile-sidebar-toggle") &&
|
||||
rootLayout.includes("class:sidebar-open={!sidebarFolded}") &&
|
||||
!rootLayout.includes("BevelLine") &&
|
||||
sidebarFrame.includes('class="sidebar-frame__bevel"') &&
|
||||
sidebarFrame.includes('depth="inset"') &&
|
||||
sidebarFrame.includes("top={false} bottom={false} left={false}") &&
|
||||
sidebarFrame.includes("$bindable(false)") &&
|
||||
!sidebarFrame.includes("BevelLine") &&
|
||||
sidebarCss.includes(".sidebar-frame.folded") &&
|
||||
sidebarCss.includes("display: none") &&
|
||||
sidebarCss.includes("display: grid"),
|
||||
"Desktop shell boundaries must use one Bevel edge and Mobile must share Header fold state",
|
||||
);
|
||||
assert(
|
||||
designLanguage.includes(
|
||||
"Headerのbottom edgeとSidebarのright edgeだけを有効",
|
||||
) &&
|
||||
designLanguage.includes("Mobileのfold controlはHeaderに置く") &&
|
||||
designLanguage.includes("main contentと同時表示しない") &&
|
||||
designLanguage.includes("同じlayerではheading、本文、Lineの端を揃え") &&
|
||||
designLanguage.includes(
|
||||
"親layoutがそのlayer全体へinline方向の余白を与え",
|
||||
) &&
|
||||
showroomCss.includes(".resource-list {") &&
|
||||
showroomCss.includes("margin-inline: var(--space-2)"),
|
||||
"The design language and showroom must align same-layer lines and inset nested layers as a whole",
|
||||
);
|
||||
assert(
|
||||
!sidebarCss.includes("border-right:") &&
|
||||
!sidebarCss.includes("border-bottom:") &&
|
||||
!showroomCss.includes("border-top: 1px solid") &&
|
||||
!showroomCss.includes("border-bottom: 1px solid"),
|
||||
"Shell and showroom structural separators must not fall back to one-sided solid borders",
|
||||
"Shell and showroom structural boundaries must not fall back to one-sided solid borders",
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user