Skip to content

Frontend Components

This documentation describes the reusable Vue components of the LLARS design system.

Overview

The LLARS design system provides a collection of globally available components with a consistent style:

Component Description
LBtn Standard button with variants
LIconBtn Icon button with tooltip
LIcon Icon wrapper for MDI icons
LTag Status tags and labels
LCheckbox Checkbox with label
LFloatingWindow Draggable floating window
LCard Card container
LLoading Loading spinner
... more components

Design basics

LLARS signature: asymmetric border radius

/* Default for buttons and windows */
border-radius: 16px 4px 16px 4px;

/* Small for tags */
border-radius: 6px 2px 6px 2px;

/* Mini for icons */
border-radius: 8px 2px 8px 2px;

Color palette

Color Hex CSS variable Usage
Primary #b0ca97 --llars-primary Primary actions, default
Secondary #D1BC8A --llars-secondary Secondary actions
Accent #88c4c8 --llars-accent Highlights
Success #98d4bb --llars-success Success
Warning #f0c674 --llars-warning Warnings
Danger #e8a087 --llars-danger Destructive actions
AI #9B59B6 - AI features

LFloatingWindow

A draggable, resizable floating window for tool panels, dialogs, and assistants.

Features

  • Draggable header: move the window via drag & drop
  • Resizable: resize handle bottom-right
  • Position persistence: stores position/size in localStorage
  • LLARS design: asymmetric border radius, theme colors
  • Flexible slots: tags, header actions, content, footer
  • Built-in buttons: close, minimize, maximize, refresh

Props

Prop Type Default Description
modelValue Boolean false v-model for visibility
title String required Window title
icon String null Header icon (mdi-*)
iconSize Number/String 18 Icon size
color String 'primary' Theme color (see below)
width Number/String 400 Initial width
height Number/String 300 Initial height
minWidth Number 300 Minimum width
minHeight Number 200 Minimum height
maxWidth Number null Max width (null = viewport - 40px)
maxHeight Number null Max height (null = viewport - 60px)
resizable Boolean true Allow resize
storageKey String null localStorage key for persistence
initialX Number null Start X (null = centered)
initialY Number null Start Y (null = centered)
showClose Boolean true Show close button
showMinimize Boolean false Show minimize button
showMaximize Boolean false Show maximize button
showRefresh Boolean false Show refresh button
refreshLoading Boolean false Refresh loading state
refreshTooltip String null Refresh tooltip
zIndex Number 9999 Z-index

Color themes

<!-- Available values for the color prop -->
color="primary"    <!-- Green - default -->
color="secondary"  <!-- Gold -->
color="accent"     <!-- Turquoise -->
color="success"    <!-- Success green -->
color="warning"    <!-- Yellow -->
color="danger"     <!-- Red -->
color="ai"         <!-- Purple - for AI features -->

Slots

Slot Description
default Main window content
tags Status tags in header (between title and actions)
header-actions Additional buttons before built-in buttons
footer Optional footer (e.g. input + submit)

Events

Event Payload Description
update:modelValue Boolean Visibility changed
refresh - Refresh clicked
minimize - Minimize clicked
maximize - Window maximized
restore - Restored from maximize
close - Window closed
drag-start - Drag started
drag-end - Drag ended
resize-start - Resize started
resize-end - Resize ended

Example: simple window

<template>
  <LBtn @click="showWindow = true">Open</LBtn>

  <LFloatingWindow
    v-model="showWindow"
    title="Settings"
    icon="mdi-cog"
    color="accent"
  >
    <div class="pa-4">
      <p>Window content here</p>
    </div>
  </LFloatingWindow>
</template>

<script setup>
import { ref } from 'vue'
const showWindow = ref(false)
</script>
<template>
  <LFloatingWindow
    :model-value="showGitPanel"
    title="Git Panel"
    icon="mdi-source-branch"
    color="primary"
    :width="800"
    :height="500"
    storage-key="llars-git-panel"
    :show-refresh="true"
    :refresh-loading="isLoading"
    @update:model-value="showGitPanel = $event"
    @refresh="refreshChanges"
  >
    <!-- Status tags -->
    <template #tags>
      <LTag v-if="changedCount > 0" variant="warning" size="small">
        {{ changedCount }} changed
      </LTag>
      <LTag v-else variant="success" size="small">
        In sync
      </LTag>
    </template>

    <!-- Content -->
    <div class="git-content">
      <FileList :files="changedFiles" />
      <DiffViewer :file="selectedFile" />
    </div>

    <!-- Footer -->
    <template #footer>
      <v-text-field
        v-model="commitMessage"
        placeholder="Commit message..."
        density="compact"
        hide-details
      />
      <LBtn variant="primary" @click="commit">
        Commit
      </LBtn>
    </template>
  </LFloatingWindow>
</template>

Example: AI assistant

<template>
  <LFloatingWindow
    v-model="showAssistant"
    title="AI Assistant"
    icon="mdi-robot-happy"
    color="ai"
    :width="380"
    :height="500"
    storage-key="llars-ai-assistant"
  >
    <template #tags>
      <LTag v-if="hasSelection" variant="accent" size="small">
        <LIcon size="12">mdi-selection</LIcon>
        Selection
      </LTag>
    </template>

    <ChatMessages :messages="messages" />
    <ChatInput v-model="input" @send="sendMessage" />
  </LFloatingWindow>
</template>

Position persistence

If storageKey is set, position and size are stored in localStorage:

// Saved format
{
  "x": 100,      // X position
  "y": 50,       // Y position
  "width": 800,  // Width
  "height": 500  // Height
}

The window will open at the same position next time.

Exposed methods

<template>
  <LFloatingWindow ref="windowRef" ... />
</template>

<script setup>
const windowRef = ref(null)

// Available methods:
windowRef.value.close()           // Close the window
windowRef.value.toggleMaximize()  // Maximize/Restore

// Available refs:
windowRef.value.position     // { x, y }
windowRef.value.size         // { width, height }
windowRef.value.isMaximized  // Boolean
</script>

Best Practices

When to use LFloatingWindow?

Use for:

  • Tool panels (Git, Debug, etc.)
  • AI assistants
  • Detail views that should not block the main content
  • Windows the user should freely position

Do not use for:

  • Confirmation dialogs -> v-dialog
  • Modal actions -> v-dialog
  • Full-screen editors -> dedicated view
  • Permanent sidebars -> regular sidebar component

Storage Keys

Use unique, descriptive storage keys:

<!-- Good -->
storage-key="llars-git-panel"
storage-key="llars-ai-assistant-latex"
storage-key="llars-prompt-git-panel"

<!-- Bad -->
storage-key="window1"
storage-key="panel"

Responsive sizes

Set sensible min/max values:

<LFloatingWindow
  :width="800"
  :height="500"
  :min-width="400"
  :min-height="300"
  :max-width="1200"
/>