Restructure layout components architecture

- Move layout components from layouts/ directory to components/layout/
- Reorganize divider component from data-display to layout category
- Add comprehensive layout component collection including aspect-ratio, bento-grid, box, breakpoint-container, center, column, dashboard-shell, feed-layout, flex, grid-container, hstack, list-detail-layout, scroll-container, section, sidebar-layout, stack, supporting-pane-layout, tabs-container, and vstack
- Update all demo components to match new layout structure
- Refactor routing and index exports to reflect reorganized component architecture

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
skyai_dev
2025-09-04 12:28:47 +10:00
parent 2f56ee01b3
commit 876eb301a0
130 changed files with 15848 additions and 4746 deletions

View File

@@ -0,0 +1,240 @@
@use '../../../../../ui-design-system/src/styles/semantic/index' as *;
.demo-container {
padding: $semantic-spacing-component-lg;
background: $semantic-color-surface;
min-height: 100vh;
h2 {
font-family: map-get($semantic-typography-heading-h2, font-family);
font-size: map-get($semantic-typography-heading-h2, font-size);
font-weight: map-get($semantic-typography-heading-h2, font-weight);
line-height: map-get($semantic-typography-heading-h2, line-height);
color: $semantic-color-text-primary;
margin-bottom: $semantic-spacing-content-heading;
border-bottom: $semantic-border-width-1 solid $semantic-color-border-secondary;
padding-bottom: $semantic-spacing-component-sm;
}
}
.demo-section {
margin-bottom: $semantic-spacing-layout-section-lg;
h3 {
font-family: map-get($semantic-typography-heading-h3, font-family);
font-size: map-get($semantic-typography-heading-h3, font-size);
font-weight: map-get($semantic-typography-heading-h3, font-weight);
line-height: map-get($semantic-typography-heading-h3, line-height);
color: $semantic-color-text-primary;
margin-bottom: $semantic-spacing-component-md;
}
}
.demo-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: $semantic-spacing-grid-gap-md;
margin-bottom: $semantic-spacing-component-lg;
}
.demo-card {
border: $semantic-border-width-1 solid $semantic-color-border-secondary;
border-radius: $semantic-border-card-radius;
background: $semantic-color-surface-secondary;
padding: $semantic-spacing-component-md;
h4 {
font-family: map-get($semantic-typography-heading-h4, font-family);
font-size: map-get($semantic-typography-heading-h4, font-size);
font-weight: map-get($semantic-typography-heading-h4, font-weight);
line-height: map-get($semantic-typography-heading-h4, line-height);
color: $semantic-color-text-primary;
margin-bottom: $semantic-spacing-component-sm;
}
}
.sidebar-demo-container {
height: 300px;
border: $semantic-border-width-1 solid $semantic-color-border-subtle;
border-radius: $semantic-border-radius-sm;
overflow: hidden;
position: relative;
&--interactive {
height: 400px;
}
.demo-content {
padding: $semantic-spacing-component-md;
color: $semantic-color-text-primary;
h4, h5 {
font-family: map-get($semantic-typography-heading-h4, font-family);
font-size: map-get($semantic-typography-heading-h4, font-size);
font-weight: map-get($semantic-typography-heading-h4, font-weight);
line-height: map-get($semantic-typography-heading-h4, line-height);
margin-bottom: $semantic-spacing-component-xs;
}
p {
font-family: map-get($semantic-typography-body-medium, font-family);
font-size: map-get($semantic-typography-body-medium, font-size);
font-weight: map-get($semantic-typography-body-medium, font-weight);
line-height: map-get($semantic-typography-body-medium, line-height);
color: $semantic-color-text-secondary;
margin-bottom: $semantic-spacing-content-paragraph;
}
ul {
list-style: none;
padding: 0;
margin: 0;
li {
padding: $semantic-spacing-content-line-tight;
color: $semantic-color-text-secondary;
border-bottom: $semantic-border-width-1 solid $semantic-color-border-subtle;
&:last-child {
border-bottom: none;
}
}
}
}
}
// Sidebar content styling
[slot="sidebar"] {
color: $semantic-color-text-primary;
h5 {
font-family: map-get($semantic-typography-heading-h5, font-family);
font-size: map-get($semantic-typography-heading-h5, font-size);
font-weight: map-get($semantic-typography-heading-h5, font-weight);
line-height: map-get($semantic-typography-heading-h5, line-height);
margin-bottom: $semantic-spacing-component-sm;
color: $semantic-color-text-primary;
}
ul {
list-style: none;
padding: 0;
margin: 0;
li {
padding: $semantic-spacing-component-xs;
margin-bottom: $semantic-spacing-component-xs;
border-radius: $semantic-border-radius-sm;
color: $semantic-color-text-secondary;
cursor: pointer;
transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease;
&:hover {
background: $semantic-color-surface-elevated;
color: $semantic-color-text-primary;
}
}
}
nav ul li {
display: flex;
align-items: center;
gap: $semantic-spacing-component-xs;
}
}
.demo-controls {
display: flex;
flex-wrap: wrap;
gap: $semantic-spacing-component-md;
margin-bottom: $semantic-spacing-component-lg;
padding: $semantic-spacing-component-md;
background: $semantic-color-surface-elevated;
border-radius: $semantic-border-radius-md;
border: $semantic-border-width-1 solid $semantic-color-border-secondary;
label {
display: flex;
flex-direction: column;
gap: $semantic-spacing-component-xs;
font-family: map-get($semantic-typography-label, font-family);
font-size: map-get($semantic-typography-label, font-size);
font-weight: map-get($semantic-typography-label, font-weight);
line-height: map-get($semantic-typography-label, line-height);
color: $semantic-color-text-primary;
select, input {
padding: $semantic-spacing-interactive-input-padding-y $semantic-spacing-interactive-input-padding-x;
border: $semantic-border-width-1 solid $semantic-color-border-primary;
border-radius: $semantic-border-input-radius;
background: $semantic-color-surface;
color: $semantic-color-text-primary;
font-family: map-get($semantic-typography-input, font-family);
font-size: map-get($semantic-typography-input, font-size);
transition: border-color $semantic-motion-duration-fast $semantic-motion-easing-ease;
&:focus {
outline: 2px solid $semantic-color-focus;
outline-offset: 2px;
border-color: $semantic-color-border-focus;
}
}
input[type="checkbox"] {
width: auto;
margin-right: $semantic-spacing-component-xs;
}
}
}
.demo-button {
padding: $semantic-spacing-interactive-button-padding-y $semantic-spacing-interactive-button-padding-x;
background: $semantic-color-primary;
color: $semantic-color-on-primary;
border: none;
border-radius: $semantic-border-button-radius;
font-family: map-get($semantic-typography-button-medium, font-family);
font-size: map-get($semantic-typography-button-medium, font-size);
font-weight: map-get($semantic-typography-button-medium, font-weight);
line-height: map-get($semantic-typography-button-medium, line-height);
cursor: pointer;
transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease;
&:hover {
box-shadow: $semantic-shadow-button-hover;
}
&:focus-visible {
outline: 2px solid $semantic-color-focus;
outline-offset: 2px;
}
&:active {
box-shadow: $semantic-shadow-button-rest;
}
}
// Responsive design
@media (max-width: 768px) {
.demo-row {
grid-template-columns: 1fr;
}
.demo-controls {
flex-direction: column;
label {
flex-direction: row;
align-items: center;
gap: $semantic-spacing-component-sm;
}
}
.sidebar-demo-container {
height: 250px;
&--interactive {
height: 300px;
}
}
}

View File

@@ -0,0 +1,259 @@
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { SidebarLayoutComponent } from '../../../../../ui-essentials/src/lib/components/layout/sidebar-layout/sidebar-layout.component';
@Component({
selector: 'ui-sidebar-layout-demo',
standalone: true,
imports: [CommonModule, FormsModule, SidebarLayoutComponent],
template: `
<div class="demo-container">
<h2>Sidebar Layout Demo</h2>
<!-- Position Variants -->
<section class="demo-section">
<h3>Position Variants</h3>
<div class="demo-row">
<div class="demo-card">
<h4>Left Sidebar (Default)</h4>
<div class="sidebar-demo-container">
<ui-sidebar-layout position="left" sidebarWidth="sm">
<div slot="sidebar">
<h5>Left Navigation</h5>
<ul>
<li>Dashboard</li>
<li>Analytics</li>
<li>Settings</li>
</ul>
</div>
<div class="demo-content">
<h4>Main Content Area</h4>
<p>This is the main content area with left sidebar navigation.</p>
</div>
</ui-sidebar-layout>
</div>
</div>
<div class="demo-card">
<h4>Right Sidebar</h4>
<div class="sidebar-demo-container">
<ui-sidebar-layout position="right" sidebarWidth="sm">
<div slot="sidebar">
<h5>Right Panel</h5>
<ul>
<li>Quick Actions</li>
<li>Recent Items</li>
<li>Help</li>
</ul>
</div>
<div class="demo-content">
<h4>Main Content Area</h4>
<p>This is the main content area with right sidebar panel.</p>
</div>
</ui-sidebar-layout>
</div>
</div>
</div>
</section>
<!-- Width Variants -->
<section class="demo-section">
<h3>Sidebar Widths</h3>
<div class="demo-row">
@for (width of widths; track width) {
<div class="demo-card">
<h4>{{ width.toUpperCase() }} Width</h4>
<div class="sidebar-demo-container">
<ui-sidebar-layout [sidebarWidth]="width">
<div slot="sidebar">
<h5>{{ width.toUpperCase() }} Sidebar</h5>
<p>Width: {{ width }}</p>
</div>
<div class="demo-content">
<h4>Content</h4>
<p>Main content with {{ width }} sidebar.</p>
</div>
</ui-sidebar-layout>
</div>
</div>
}
</div>
</section>
<!-- Visual Variants -->
<section class="demo-section">
<h3>Visual Variants</h3>
<div class="demo-row">
@for (variant of variants; track variant) {
<div class="demo-card">
<h4>{{ variant | titlecase }}</h4>
<div class="sidebar-demo-container">
<ui-sidebar-layout [variant]="variant" sidebarWidth="sm">
<div slot="sidebar">
<h5>{{ variant | titlecase }} Style</h5>
<ul>
<li>Item One</li>
<li>Item Two</li>
<li>Item Three</li>
</ul>
</div>
<div class="demo-content">
<h4>Content</h4>
<p>Content area with {{ variant }} sidebar variant.</p>
</div>
</ui-sidebar-layout>
</div>
</div>
}
</div>
</section>
<!-- Collapse States -->
<section class="demo-section">
<h3>Collapse States</h3>
<div class="demo-row">
<div class="demo-card">
<h4>Collapsed Sidebar</h4>
<div class="sidebar-demo-container">
<ui-sidebar-layout [collapsed]="true" collapseMode="collapsed">
<div slot="sidebar">
<h5>Nav</h5>
<ul>
<li>🏠</li>
<li>📊</li>
<li>⚙️</li>
</ul>
</div>
<div class="demo-content">
<h4>Collapsed Mode</h4>
<p>Sidebar is collapsed showing minimal width.</p>
</div>
</ui-sidebar-layout>
</div>
</div>
<div class="demo-card">
<h4>Hidden Sidebar</h4>
<div class="sidebar-demo-container">
<ui-sidebar-layout [collapsed]="true" collapseMode="hidden">
<div slot="sidebar">
<h5>Hidden Sidebar</h5>
<p>This sidebar is hidden when collapsed.</p>
</div>
<div class="demo-content">
<h4>Hidden Mode</h4>
<p>Sidebar is completely hidden, content takes full width.</p>
</div>
</ui-sidebar-layout>
</div>
</div>
</div>
</section>
<!-- Interactive Example -->
<section class="demo-section">
<h3>Interactive Controls</h3>
<div class="demo-controls">
<label>
Position:
<select [(ngModel)]="interactivePosition">
<option value="left">Left</option>
<option value="right">Right</option>
</select>
</label>
<label>
Width:
<select [(ngModel)]="interactiveWidth">
<option value="sm">Small</option>
<option value="md">Medium</option>
<option value="lg">Large</option>
<option value="xl">Extra Large</option>
</select>
</label>
<label>
Variant:
<select [(ngModel)]="interactiveVariant">
<option value="default">Default</option>
<option value="bordered">Bordered</option>
<option value="elevated">Elevated</option>
</select>
</label>
<label>
<input type="checkbox" [(ngModel)]="interactiveCollapsed">
Collapsed
</label>
<label>
Collapse Mode:
<select [(ngModel)]="interactiveCollapseMode">
<option value="collapsed">Collapsed</option>
<option value="hidden">Hidden</option>
<option value="overlay">Overlay</option>
</select>
</label>
</div>
<div class="sidebar-demo-container sidebar-demo-container--interactive">
<ui-sidebar-layout
[position]="interactivePosition"
[sidebarWidth]="interactiveWidth"
[variant]="interactiveVariant"
[collapsed]="interactiveCollapsed"
[collapseMode]="interactiveCollapseMode">
<div slot="sidebar">
<h5>Interactive Sidebar</h5>
<nav>
<ul>
<li>📱 Dashboard</li>
<li>📊 Analytics</li>
<li>👥 Users</li>
<li>⚙️ Settings</li>
<li>❓ Help</li>
</ul>
</nav>
</div>
<div class="demo-content">
<h4>Interactive Demo</h4>
<p>Use the controls above to test different sidebar configurations:</p>
<ul>
<li><strong>Position:</strong> {{ interactivePosition }}</li>
<li><strong>Width:</strong> {{ interactiveWidth }}</li>
<li><strong>Variant:</strong> {{ interactiveVariant }}</li>
<li><strong>Collapsed:</strong> {{ interactiveCollapsed }}</li>
<li><strong>Collapse Mode:</strong> {{ interactiveCollapseMode }}</li>
</ul>
<button
(click)="toggleCollapse()"
class="demo-button">
{{ interactiveCollapsed ? 'Expand' : 'Collapse' }} Sidebar
</button>
</div>
</ui-sidebar-layout>
</div>
</section>
</div>
`,
styleUrl: './sidebar-layout-demo.component.scss'
})
export class SidebarLayoutDemoComponent {
widths = ['sm', 'md', 'lg', 'xl'] as const;
variants = ['default', 'bordered', 'elevated'] as const;
// Interactive demo properties
interactivePosition: 'left' | 'right' = 'left';
interactiveWidth: 'sm' | 'md' | 'lg' | 'xl' = 'md';
interactiveVariant: 'default' | 'bordered' | 'elevated' = 'default';
interactiveCollapsed = false;
interactiveCollapseMode: 'hidden' | 'collapsed' | 'overlay' = 'collapsed';
toggleCollapse(): void {
this.interactiveCollapsed = !this.interactiveCollapsed;
}
}