@teslina/appssystemkit (0.1.0)
Installation
@teslina:registry=https://forge.teslina.net/api/packages/Teslina/npm/npm install @teslina/appssystemkit@0.1.0"@teslina/appssystemkit": "0.1.0"About this package
Teslina AppsSystemKit
A production-ready design system for Teslina Applications inspired by Fluent design language. Implements consistent UI/UX components using Vue 3, TypeScript, and SCSS with a focus on accessibility, performance, and maintainability.
🚀 Quick Start
Installation
# Install dependencies
npm install
# Run development server
npm run dev
# Build for production
npm run build
Basic Usage
<template>
<div>
<TslButton variant="primary" @click="handleAction">
Create Resource
</TslButton>
<TslInput
v-model="name"
label="Name"
placeholder="Enter name"
/>
<TslBadge variant="success" dot>Active</TslBadge>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import TslButton from './components/base/Button.vue';
import TslInput from './components/forms/Input.vue';
import TslBadge from './components/base/Badge.vue';
const name = ref('');
const handleAction = () => {
console.log('Action:', name.value);
};
</script>
Project Structure
Teslina_AppsSystemKit/
├── components/ # Vue 3 components
│ ├── base/ # Buttons, Badges, Cards, Avatars
│ ├── forms/ # Inputs, Checkboxes, Selects
│ ├── feedback/ # Alerts, Progress, Spinners, Dialogs
│ ├── navigation/ # Tabs, Breadcrumbs, Menus
│ ├── layout/ # Shell, Rail, Topbar, Subnav
│ ├── modals/ # Wizards and modal dialogs
│ └── widgets/ # Date pickers, file uploads, charts
├── styles/
│ ├── tokens/ # Design tokens (SCSS variables)
│ ├── base/ # CSS variables, reset, typography
│ └── utilities/ # Utility classes
├── pages/
│ └── examples/ # Working demo pages (components, widgets, shell, cloud)
├── layouts/ # Nuxt layouts
├── CLAUDE.md # AI assistant instructions
└── README.md # This file
🎨 Design System Overview
Design Principles
1. Neutral First, Accent Rare
The interface lives in grayscale. Blue accent (#0f6cbd) is reserved for primary actions, selection, and links—never decorative.
2. Subtle Depth
Fluent shadows (depth 2→64) separate layers. Flat surfaces are primary; elevation signals interactivity or temporality.
3. Comfortable Density
- 32px target control height
- 4px grid system
- Generous spacing around titles
- Readable without being sparse
4. Purposeful Motion
- Short transitions (100–300ms) with deceleration
- Motion explains state, doesn't distract
Design Tokens
Colors
Brand (Fluent Communication Blue):
$brand-100: #0f6cbd; // Primary
$brand-90: #115ea3; // Hover
$brand-80: #0f548c; // Pressed
$brand-tint-40: #ebf3fc; // Selected fill
$brand-tint-50: #f6fafe; // Hover fill
Neutrals:
$neutral-bg-1: #ffffff; // Card background
$neutral-bg-2: #fafafa; // Subtle background
$neutral-bg-3: #f5f5f5; // Canvas
$neutral-bg-4: #f0f0f0; // Hover
$neutral-fg-1: #242424; // Primary text
$neutral-fg-2: #424242; // Secondary text
$neutral-fg-3: #616161; // Tertiary text
$neutral-fg-disabled: #bdbdbd; // Disabled text
Status:
$status-success: #0e7c41;
$status-warning-fg: #bc4b09;
$status-danger: #b10e1c;
$status-info: #0f6cbd;
Spacing (4px Grid)
$sp-4: 4px; $sp-8: 8px; $sp-12: 12px;
$sp-16: 16px; $sp-20: 20px; $sp-24: 24px;
$sp-32: 32px; $sp-40: 40px; $sp-48: 48px;
Typography Scale
.t-display // 68px / 600 — Hero headings
.t-title1 // 40px / 600 — Page titles
.t-title2 // 28px / 600 — Section titles
.t-title3 // 20px / 600 — Subsection titles
.t-subtitle // 16px / 600 — Card titles
.t-body-strong // 14px / 600 — Emphasized body
.t-body // 14px / 400 — Default body
.t-caption // 12px / 400 — Metadata (muted)
.t-mono // 12.5px mono — Code/IDs
Border Radius
$radius-sm: 2px; // Sharp
$radius-md: 4px; // Standard controls
$radius-lg: 6px; // Small cards
$radius-xl: 8px; // Large cards
$radius-circular: 999px; // Pills, avatars
Shadows (Fluent Depth)
$shadow-2: 0 0 2px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.14); // Cards at rest
$shadow-8: 0 0 2px rgba(0,0,0,0.12), 0 4px 8px rgba(0,0,0,0.14); // Menus
$shadow-16: 0 0 2px rgba(0,0,0,0.12), 0 8px 16px rgba(0,0,0,0.14); // Popovers
$shadow-28: 0 0 8px rgba(0,0,0,0.12), 0 14px 28px rgba(0,0,0,0.18);// Flyouts
$shadow-64: 0 0 8px rgba(0,0,0,0.12), 0 32px 64px rgba(0,0,0,0.24);// Dialogs
Motion
$dur-fast: 100ms; // Hover, color changes
$dur-normal: 200ms; // Dialogs, focus
$dur-slow: 300ms; // Panels, wizards
$ease-decel: cubic-bezier(0.1, 0.9, 0.2, 1); // Entrance
$ease-accel: cubic-bezier(0.7, 0, 1, 0.5); // Exit
$ease-standard: cubic-bezier(0.33, 0, 0.67, 1); // General UI
📦 Component Catalog
Base Components
TslButton
Purpose: Interactive buttons with multiple visual variants and sizes
Location: components/base/Button.vue
Props: variant (primary|secondary|subtle|outline-accent|danger|link), size (sm|default|lg), disabled, loading, icon, type
Events: click
TslBadge
Purpose: Status indicators with colored variants and optional dots
Location: components/base/Badge.vue
Props: variant (neutral|info|success|warning|danger|important), dot
Events: None
TslCard
Purpose: Content containers with subtle elevation and hover states
Location: components/base/Card.vue
Props: padding, hover, flat
Events: click
TslAvatar
Purpose: User representation with initials, images, and size variants
Location: components/base/Avatar.vue
Props: src, alt, initials, size (sm|default|lg), color
Events: None
TslPersona
Purpose: Combined avatar with user metadata (name, subtitle)
Location: components/base/Persona.vue
Props: name (required), subtitle, src, initials, size, color
Events: None
TslIconButton
Purpose: Compact icon-only button for toolbars and actions
Location: components/base/IconButton.vue
Props: variant, size, disabled, label, type
Events: click
Form Components
TslInput
Purpose: Text input field with label, hint, and Fluent-style focus border
Location: components/forms/Input.vue
Props: modelValue, label, placeholder, hint, error, disabled, type, id
Events: update:modelValue, focus, blur
Notes: error renders in place of hint and adds an error border. Falls through unbound attrs ($attrs) to the <input>; label is linked to the input via id/for (auto-generated with useId() if id isn't passed).
TslCheckbox
Purpose: Boolean selection control with indeterminate state support
Location: components/forms/Checkbox.vue
Props: modelValue, indeterminate, disabled
Events: update:modelValue, change
TslRadio
Purpose: Single selection from a group of options
Location: components/forms/Radio.vue
Props: modelValue, value, name, disabled
Events: update:modelValue, change
TslSwitch
Purpose: Toggle control with animated track for binary choices
Location: components/forms/Switch.vue
Props: modelValue, disabled
Events: update:modelValue, change
TslSelect
Purpose: Dropdown selector with Fluent chevron icon
Location: components/forms/Select.vue
Props: modelValue, label, placeholder, hint, error, disabled
Events: update:modelValue, change
Notes: Options are passed as <option> elements via the default slot, not an options prop.
TslTextarea
Purpose: Multi-line text input with auto-resize support
Location: components/forms/Textarea.vue
Props: modelValue, label, placeholder, rows, disabled
Events: update:modelValue
Feedback Components
TslAlert
Purpose: Message bars for info, success, warning, and error states
Location: components/feedback/Alert.vue
Props: variant (info|success|warning|danger), dismissible
Events: dismiss
Slots: default, icon
TslProgress
Purpose: Linear progress indicator with determinate and indeterminate modes
Location: components/feedback/Progress.vue
Props: value (0-100), max, label, showPercentage, indeterminate, variant, size
Events: None
TslSpinner
Purpose: Loading indicator with size and color variants
Location: components/feedback/Spinner.vue
Props: size (sm|default|lg), variant (neutral|primary|success|danger), label
Events: None
TslDialog
Purpose: Modal dialog with scrim, teleport, and slot support
Location: components/feedback/Dialog.vue
Props: modelValue, title, size, closable, closeOnScrimClick
Events: update:modelValue, close
Slots: default, footer
Navigation Components
TslTabs
Purpose: Horizontal tab navigation with active indicator
Location: components/navigation/Tabs.vue
Props: modelValue, tabs (array of strings)
Events: update:modelValue, change
TslBreadcrumb
Purpose: Hierarchical navigation with separators
Location: components/navigation/Breadcrumb.vue
Props: items (array of {label, to}), separator
Events: click
TslMenu
Purpose: Dropdown and context menu, composed from TslMenuItem/TslMenuDivider children
Location: components/navigation/Menu.vue
Props: modelValue (required, open state), anchorEl, position
Events: update:modelValue, close
Notes: Menu content is slot-based, not driven by an items prop.
- TslMenuItem (
components/navigation/MenuItem.vue) — Props:disabled,danger,shortcut; Events:click; Slots:icon,default - TslMenuDivider (
components/navigation/MenuDivider.vue) — Visual separator between menu items, no props
TslAppSwitcher
Purpose: Application switcher panel for multi-app navigation
Location: components/navigation/AppSwitcher.vue
Props: apps (array)
Events: None
Layout Components
TslShell
Purpose: Complete application shell with topbar, rail, and content area
Location: components/layout/Shell.vue
Props: None
Slots: topbar, rail, subnav, default
Notes: Internally composes LayoutShellContent.vue (components/layout/LayoutShellContent.vue), which lays out the subnav/default slots — not used directly.
TslTopbar
Purpose: Application header with branding, navigation, and actions
Location: components/layout/Topbar.vue
Props: None
Slots: start, center, end
TslRail
Purpose: Vertical navigation rail, composed of TslRailItem children
Location: components/layout/Rail.vue
Props: None
Slots: default
- TslRailItem (
components/layout/RailItem.vue) — Props:label,to,active; Events:click; Slots:icon
TslSubnav
Purpose: Secondary horizontal navigation below topbar, composed of TslSubnavItem children
Location: components/layout/Subnav.vue
Props: title
Slots: default
- TslSubnavItem (
components/layout/SubnavItem.vue) — Props:label,href,active; Events:click; Slots:icon
Modal Components
TslResourceWizard
Purpose: Multi-step wizard for resource creation workflows
Location: components/modals/ResourceWizard.vue
Props: modelValue
Events: update:modelValue, create
Notes: Wizard steps (components/modals/wizard-steps/Step*.vue — Product, Region, Specs, Options, Settings, Review) are internal to this component and not configurable via props.
Widget Components
DatePicker
Purpose: Single date selection with calendar dropdown
Location: components/widgets/DatePicker.vue
Props: modelValue, label, disabled, weekStartsOn (0-6, defaults to locale-derived week start)
Events: update:modelValue
DateRangePicker
Purpose: Start and end date selection with range highlighting
Location: components/widgets/DateRangePicker.vue
Props: modelValue ({ start: Date, end: Date }), label, disabled, weekStartsOn (0-6, defaults to locale-derived week start)
Events: update:modelValue
MiniCalendar
Purpose: Compact calendar display with event indicators
Location: components/widgets/MiniCalendar.vue
Props: modelValue, events
Events: update:modelValue
TimePicker
Purpose: Time selection with 12/24 hour format support
Location: components/widgets/TimePicker.vue
Props: modelValue, use24Hour
Events: update:modelValue
FileUpload
Purpose: File selection with type filtering and size validation
Location: components/widgets/FileUpload.vue
Props: modelValue, multiple, accept, maxSize, disabled
Events: update:modelValue
FileDropZone
Purpose: Drag-and-drop file upload area
Location: components/widgets/FileDropZone.vue
Props: modelValue
Events: update:modelValue
ColorPicker
Purpose: Color selection with hex, RGB, and HSL support
Location: components/widgets/ColorPicker.vue
Props: modelValue
Events: update:modelValue
ThemeConfigurator
Purpose: Real-time theme customization with token controls
Location: components/widgets/ThemeConfigurator.vue
Props: None
Events: None
Timer
Purpose: Countdown/countup timer with controls
Location: components/widgets/Timer.vue
Props: modelValue (required, seconds)
Events: update:modelValue, complete
Countdown
Purpose: Simple countdown to a target date/time
Location: components/widgets/Countdown.vue
Props: targetDate (required, Date)
Events: None
SkeletonLoader
Purpose: Placeholder loading state for content
Location: components/widgets/SkeletonLoader.vue
Props: variant (text|card|list|table)
Events: None
KanbanBoard
Purpose: Drag-and-drop kanban board for task management
Location: components/widgets/KanbanBoard.vue
Props: modelValue (Column[])
Events: update:modelValue
CircularProgress
Purpose: Circular progress indicator with percentage display
Location: components/widgets/CircularProgress.vue
Props: value (0-100), size, strokeWidth, variant
Events: None
StatsWidget
Purpose: Metric display with title, value, and trend
Location: components/widgets/StatsWidget.vue
Props: title, value, trend, trendLabel, description, format, loading, hover
Events: None
StatusWidget
Purpose: System status display listing multiple status items
Location: components/widgets/StatusWidget.vue
Props: title, items (StatusItem[]), loading
Events: None
ActivityWidget
Purpose: Recent activity feed with timestamps
Location: components/widgets/ActivityWidget.vue
Props: title, items (required), loading
Events: None
QuickActionsWidget
Purpose: Grid of quick action buttons
Location: components/widgets/QuickActionsWidget.vue
Props: title, actions (required), loading
Events: None
WidgetContainer
Purpose: Container wrapper for dashboard widgets
Location: components/widgets/WidgetContainer.vue
Props: title, collapsible, loading, empty, emptyMessage, hover, padding
Slots: default, header, footer, actions
ChartWidget
Purpose: Progress-ring, bar, or sparkline chart visualization
Location: components/widgets/ChartWidget.vue
Props: title, type (progress-ring|bar|sparkline), value, label, barData, sparklineData, loading
Events: None
💡 Examples
This kit includes complete working examples as Nuxt pages under pages/examples/:
- components-demo.vue — All base, form, and feedback components with interactive states
- widgets-demo.vue — Date pickers, file uploads, calendars, charts, and dashboard widgets
- shell-demo.vue — Application shell layout with topbar, rail, subnav, and content areas
- cloud-demo.vue — Real-world cloud console example with resource creation wizard
Running Examples
npm run dev
Navigate to:
http://localhost:3000/examples/components-demohttp://localhost:3000/examples/widgets-demohttp://localhost:3000/examples/shell-demohttp://localhost:3000/examples/cloud-demo
📐 Usage Rules & Patterns
Component Composition
Button Groups:
<div class="flex gap-8">
<TslButton variant="primary">Save</TslButton>
<TslButton variant="secondary">Cancel</TslButton>
</div>
Form Fields:
<TslInput
v-model="name"
label="Project Name"
hint="3 to 24 lowercase characters"
placeholder="ex. tsl-prod-eu"
/>
Status Badges:
<TslBadge variant="success" dot>Running</TslBadge>
<TslBadge variant="warning">Pending</TslBadge>
<TslBadge variant="danger">Failed</TslBadge>
Card Layouts:
<TslCard padding hover>
<h3 class="t-subtitle mb-8">Title</h3>
<p class="muted">Description text</p>
</TslCard>
Accessibility Guidelines
All components follow WCAG 2.1 AA standards:
- ✅ Proper semantic HTML elements
- ✅ ARIA labels and roles where needed
- ✅ Keyboard navigation support (Tab, Enter, Space, Arrows)
- ✅ Focus indicators with sufficient contrast
- ✅ Color contrast ratios meet AA requirements (4.5:1 for text)
- ✅ Screen reader compatible announcements
- ✅ Logical tab order
Anti-Patterns to Avoid
❌ No inline styles — Always use classes from design tokens
❌ No !important — Only allowed in utility classes
❌ No hardcoded colors — Use SCSS variables from styles/tokens/_tokens.scss
❌ No magic numbers — Use spacing scale variables ($sp-4 through $sp-48)
❌ No AI-generated clichés — Avoid gradient abuse, unnecessary animations, oversized shadows
🏗️ Architecture Guidelines
Component Structure
Each component follows strict separation of concerns:
<template>
<!-- Clean, semantic HTML structure -->
<button :class="buttonClasses" @click="handleClick">
<slot />
</button>
</template>
<script setup lang="ts">
import { computed } from 'vue';
// TypeScript interface for props
interface Props {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'default' | 'lg';
disabled?: boolean;
}
// Props with defaults
const props = withDefaults(defineProps<Props>(), {
variant: 'primary',
size: 'default',
disabled: false,
});
// Computed classes
const buttonClasses = computed(() => [
'tsl-btn',
`tsl-btn--${props.variant}`,
`tsl-btn--${props.size}`,
]);
// Event emission
const emit = defineEmits<{
click: [event: MouseEvent];
}>();
const handleClick = (event: MouseEvent) => {
if (!props.disabled) {
emit('click', event);
}
};
</script>
<style scoped lang="scss">
@use '/styles/tokens/tokens' as *;
.tsl-btn {
// Use design tokens
padding: $sp-12 $sp-16;
border-radius: $radius-md;
background: $brand-100;
color: white;
transition: background $dur-fast $ease-standard;
&:hover {
background: $brand-90;
}
&--secondary {
background: $neutral-bg-1;
color: $neutral-fg-1;
border: 1px solid $stroke-1;
}
}
</style>
Development Rules
- One component per Vue file — No separate
.scssfiles - Scoped SCSS within component — All styles in
<style scoped lang="scss"> - Minimal dependencies — Only import what's necessary
- Object-oriented approach — Use classes and TypeScript interfaces
- TypeScript interfaces for all props — Proper typing for better DX
- Accessibility-first — Keyboard navigation, ARIA, focus management
Design Token Import
@use '/styles/tokens/tokens' as *;
.component {
padding: $sp-16; // Spacing
color: $neutral-fg-1; // Colors
border-radius: $radius-md; // Border radius
box-shadow: $shadow-2; // Shadows
transition: all $dur-fast $ease-standard; // Motion
}
🤖 AI Agent Reference
Quick Component Lookup Table
| Component | Category | Path | Primary Props |
|---|---|---|---|
| TslButton | base | components/base/Button.vue | variant, size, disabled, loading, icon |
| TslBadge | base | components/base/Badge.vue | variant, dot |
| TslCard | base | components/base/Card.vue | padding, hover, flat |
| TslAvatar | base | components/base/Avatar.vue | src, initials, alt, size, color |
| TslPersona | base | components/base/Persona.vue | name, subtitle, src, initials, size |
| TslIconButton | base | components/base/IconButton.vue | variant, size, label |
| TslInput | forms | components/forms/Input.vue | modelValue, label, placeholder, hint, error |
| TslCheckbox | forms | components/forms/Checkbox.vue | modelValue, indeterminate |
| TslRadio | forms | components/forms/Radio.vue | modelValue, value, name |
| TslSwitch | forms | components/forms/Switch.vue | modelValue |
| TslSelect | forms | components/forms/Select.vue | modelValue, label, hint, error (options via default slot) |
| TslTextarea | forms | components/forms/Textarea.vue | modelValue, rows |
| TslAlert | feedback | components/feedback/Alert.vue | variant, dismissible |
| TslProgress | feedback | components/feedback/Progress.vue | value, max, label, indeterminate |
| TslSpinner | feedback | components/feedback/Spinner.vue | size, variant, label |
| TslDialog | feedback | components/feedback/Dialog.vue | modelValue, title, size, closable |
| TslTabs | navigation | components/navigation/Tabs.vue | modelValue, tabs |
| TslBreadcrumb | navigation | components/navigation/Breadcrumb.vue | items, separator |
| TslMenu | navigation | components/navigation/Menu.vue | modelValue, anchorEl, position (items via slot) |
| TslMenuItem | navigation | components/navigation/MenuItem.vue | disabled, danger, shortcut |
| TslAppSwitcher | navigation | components/navigation/AppSwitcher.vue | apps |
| TslShell | layout | components/layout/Shell.vue | (slots only) |
| TslTopbar | layout | components/layout/Topbar.vue | (slots: start, center, end) |
| TslRail | layout | components/layout/Rail.vue | (slots only) |
| TslRailItem | layout | components/layout/RailItem.vue | label, to, active |
| TslSubnav | layout | components/layout/Subnav.vue | title |
| TslSubnavItem | layout | components/layout/SubnavItem.vue | label, href, active |
| TslResourceWizard | modals | components/modals/ResourceWizard.vue | modelValue |
| DatePicker | widgets | components/widgets/DatePicker.vue | modelValue, label, weekStartsOn |
| DateRangePicker | widgets | components/widgets/DateRangePicker.vue | modelValue, label, weekStartsOn |
| TimePicker | widgets | components/widgets/TimePicker.vue | modelValue, use24Hour |
| KanbanBoard | widgets | components/widgets/KanbanBoard.vue | modelValue |
| Timer | widgets | components/widgets/Timer.vue | modelValue |
| Countdown | widgets | components/widgets/Countdown.vue | targetDate |
File Path Patterns
Components:
components/
base/ — Buttons, badges, cards, avatars
forms/ — Inputs, checkboxes, selects, switches
feedback/ — Alerts, progress, spinners, dialogs
navigation/ — Tabs, breadcrumbs, menus
layout/ — Shell, topbar, rail, subnav
modals/ — Wizards and modal dialogs
widgets/ — Date pickers, charts, utilities
Styles:
styles/
tokens/_tokens.scss — All design tokens
base/_variables.scss — CSS custom properties
base/_reset.scss — Minimal reset
base/_typography.scss — Typography classes
utilities/_utilities.scss — Utility classes
main.scss — Entry point
Common Import Patterns
Component Import:
<script setup lang="ts">
import TslButton from './components/base/Button.vue';
import TslInput from './components/forms/Input.vue';
import TslCard from './components/base/Card.vue';
</script>
Token Import in SCSS:
@use '/styles/tokens/tokens' as *;
.component {
padding: $sp-16;
color: $neutral-fg-1;
background: $neutral-bg-1;
}
Design Token Categories
Colors: $brand-*, $neutral-*, $status-*, $stroke-*
Spacing: $sp-4 through $sp-48
Typography: .t-display, .t-title1, .t-subtitle, .t-body, .t-caption
Radius: $radius-sm, $radius-md, $radius-lg, $radius-xl, $radius-circular
Shadows: $shadow-2, $shadow-8, $shadow-16, $shadow-28, $shadow-64
Motion: $dur-fast, $dur-normal, $dur-slow + $ease-decel, $ease-accel, $ease-standard
Common Component Patterns
Form Field with v-model:
<TslInput
v-model="value"
label="Field Label"
placeholder="Enter value"
hint="Helper text"
/>
Dialog with Footer:
<TslDialog v-model="showDialog" title="Confirm">
<p>Dialog content</p>
<template #footer>
<TslButton variant="primary" @click="confirm">OK</TslButton>
<TslButton variant="secondary" @click="cancel">Cancel</TslButton>
</template>
</TslDialog>
Card Grid Layout:
<div class="grid gap-24">
<TslCard padding hover>
<h3 class="t-subtitle">Title</h3>
<p class="muted">Description</p>
</TslCard>
</div>
Dependencies
Dependencies
| ID | Version |
|---|---|
| @nuxt/icon | ^2.2.3 |
| @nuxtjs/device | ^4.0.0 |
| @nuxtjs/i18n | ^10.4.0 |
| @nuxtjs/mdc | ^0.22.0 |
| nuxt | ^4.4.8 |
| vue | ^3.5.35 |
| vue-router | ^5.1.0 |
Development Dependencies
| ID | Version |
|---|---|
| @iconify-json/fluent | ^1.2.50 |
| @iconify-json/svg-spinners | ^1.2.4 |
| sass | ^1.101.0 |