Layout Components

High-level layout components for structuring pages, sections, and application-wide elements.

Application Layout

AppHeader

Main application header with navigation and branding.

AppFooter

Application footer component.

Layout Components

High-level layout components for structuring pages, sections, and application-wide elements.

Application Layout

App Components

Located in src/components/layout/app/:

Page Layout Components

ListView

A comprehensive list view component that provides a standardized layout for displaying collections of resources.

Location: src/components/layout/list/ListView.vue

Props:

Slots:

Events:

Complete Usage Example (Contexts.vue):

<ListView
  title="Contexts"
  description="Manage contexts in your inventory system. Contexts can be set as default for the entire database."
  add-button-route="/contexts/new"
  add-button-label="Add Context"
  color="green"
  :is-empty="filteredContexts.length === 0"
  empty-title="No contexts found"
  empty-message="Get started by creating a new context."
  @retry="fetchContexts"
>
  <template #icon>
    <ContextIcon />
  </template>
  
  <template #filters>
    <FilterButton
      label="All Contexts"
      :is-active="filterMode === 'all'"
      :count="contexts.length"
      variant="primary"
      @click="filterMode = 'all'"
    />
    <FilterButton
      label="Default"
      :is-active="filterMode === 'default'"
      :count="defaultContexts.length"
      variant="success"
      @click="filterMode = 'default'"
    />
  </template>

  <template #search>
    <SearchControl v-model="searchQuery" placeholder="Search contexts..." />
  </template>
  
  <template #headers>
    <TableRow>
      <TableHeader
        sortable
        :sort-direction="sortKey === 'internal_name' ? sortDirection : null"
        @sort="handleSort('internal_name')"
      >
        Context
      </TableHeader>
      <TableHeader class="hidden md:table-cell">Default</TableHeader>
      <TableHeader class="hidden lg:table-cell">Created</TableHeader>
      <TableHeader class="hidden sm:table-cell" variant="actions">
        <span class="sr-only">Actions</span>
      </TableHeader>
    </TableRow>
  </template>

  <template #rows>
    <TableRow
      v-for="context in filteredContexts"
      :key="context.id"
      class="cursor-pointer hover:bg-green-50 transition"
      @click="openContextDetail(context.id)"
    >
      <TableCell>
        <InternalName
          small
          :internal-name="context.internal_name"
          :backward-compatibility="context.backward_compatibility"
        >
          <template #icon>
            <ContextIcon class="h-5 w-5 text-green-600" />
          </template>
        </InternalName>
      </TableCell>
      <TableCell class="hidden md:table-cell">
        <div @click.stop>
          <Toggle
            small
            title="Default"
            :status-text="context.is_default ? 'Default' : 'Not default'"
            :is-active="context.is_default"
            @toggle="updateContextStatus(context, 'is_default', !context.is_default)"
          />
        </div>
      </TableCell>
      <TableCell class="hidden lg:table-cell">
        <DateDisplay :date="context.created_at" format="short" variant="small-dark" />
      </TableCell>
      <TableCell class="hidden sm:table-cell">
        <div class="flex space-x-2" @click.stop>
          <ViewButton @click="router.push(`/contexts/${context.id}`)" />
          <EditButton @click="router.push(`/contexts/${context.id}?edit=true`)" />
          <DeleteButton @click="handleDeleteContext(context)" />
        </div>
      </TableCell>
    </TableRow>
  </template>
</ListView>

Required List Page Features:

All list pages must implement:

  1. Filtering System: Filter buttons with counts and active states
  2. Sorting System: Sortable table headers with direction indicators
  3. Search System: SearchControl component for text-based filtering
  4. Action Buttons: ViewButton, EditButton, DeleteButton in every row
  5. Status Toggles: Toggle components for inline status changes (where applicable)
  6. Row Click Navigation: Clickable rows with hover effects and @click.stop for actions
  7. Entity Colors: Consistent color usage (e.g., green for contexts, teal for items)

DetailView

A comprehensive detail view component for viewing, editing, and creating resources.

Location: src/components/layout/detail/DetailView.vue

Props:

Events:

Slots:

Usage Example (ProjectDetail.vue):

<DetailView
  :store-loading="projectStore.loading"
  :resource="mode === 'create' ? null : project"
  :mode="mode"
  :save-disabled="!hasUnsavedChanges"
  :has-unsaved-changes="hasUnsavedChanges"
  :back-link="backLink"
  :status-cards="statusCardsConfig"
  :create-title="'New Project'"
  :create-subtitle="'(Creating)'"
  information-title="Project Information"
  :information-description="informationDescription"
  :fetch-data="fetchProject"
  @edit="enterEditMode"
  @save="saveProject"
  @cancel="cancelAction"
  @delete="deleteProject"
  @status-toggle="handleStatusToggle"
>
  <template #resource-icon>
    <ProjectIcon class="h-6 w-6 text-orange-600" />
  </template>
  
  <template #information>
    <DescriptionList>
      <DescriptionRow variant="gray">
        <DescriptionTerm>Internal Name</DescriptionTerm>
        <DescriptionDetail>
          <FormInput
            v-if="mode === 'edit' || mode === 'create'"
            v-model="editForm.internal_name"
            type="text"
          />
          <DisplayText v-else></DisplayText>
        </DescriptionDetail>
      </DescriptionRow>
      <!-- More fields... -->
    </DescriptionList>
  </template>
</DetailView>

<template #headers>

Name Status

</template>

<template #rows> <TableRow v-for=”project in projects” :key=”project.id”>

</TableRow> </template> </ListView>


### DetailView
A comprehensive detail view component for displaying and editing individual resources.

**Props:**
- `storeLoading?: boolean` - Store's internal loading state
- `resource: Resource | null` - The resource being displayed
- `isEditing: boolean` - Whether in edit mode
- `isCreating?: boolean` - Whether creating a new resource
- `hasUnsavedChanges?: boolean` - Whether there are unsaved changes
- `createTitle?: string` - Custom title for creation mode
- `createSubtitle?: string` - Custom subtitle for creation mode
- `backLink?: BackLinkConfig` - Back navigation configuration
- `statusControls?: StatusControlConfig[]` - Status control configurations
- `informationTitle: string` - Title for the information section
- `informationDescription: string` - Description for the information section
- `fetchData: () => Promise<void>` - Function to fetch resource data

**Events:**
- `edit: []` - Emitted when edit mode is requested
- `save: []` - Emitted when save is requested
- `cancel: []` - Emitted when cancel is requested
- `delete: []` - Emitted when delete is requested
- `statusToggle: [index: number]` - Emitted when a status card is toggled
- `unsavedChanges: [hasChanges: boolean]` - Emitted when unsaved changes state changes

**Slots:**
- `information` - Main information content with field change handler

**Usage:**
```vue
<DetailView
  :resource="project"
  :is-editing="isEditing"
  :is-creating="isNewProject"
  :has-unsaved-changes="hasChanges"
  :back-link="backLink"
  :status-controls="statusControls"
  information-title="Project Information"
  information-description="Detailed project information"
  :fetch-data="fetchProject"
  @edit="startEdit"
  @save="saveChanges"
  @cancel="cancelEdit"
  @delete="deleteProject"
  @status-toggle="handleStatusToggle"
>
  <template #information="{ onFieldChange }">
    <DescriptionList>
      <DescriptionRow variant="gray">
        <DescriptionTerm>Name</DescriptionTerm>
        <DescriptionDetail>
          <FormInput
            v-if="isEditing"
            v-model="editForm.name"
            @input="onFieldChange"
          />
          <DisplayText v-else></DisplayText>
        </DescriptionDetail>
      </DescriptionRow>
    </DescriptionList>
  </template>
</DetailView>

List Action Components

Located in src/components/layout/list/:

FilterButton

Displays filter options with active state and count indicators.

Props:

Usage:

<FilterButton
  label="All Projects"
  :is-active="filterMode === 'all'"
  :count="projects.length"
  variant="primary"
  @click="filterMode = 'all'"
/>

Action Buttons

All action buttons accept:

SearchControl

Search input component for filtering lists.

Props:

Events:

Detail Action Components

Located in src/components/layout/detail/:

Action Buttons

SystemProperties

Displays system fields like created_at, updated_at with proper formatting.

Props:

Layout Best Practices

Responsive Design

All layout components use Tailwind CSS with mobile-first approach:

<!-- Table columns with responsive visibility -->
<th class="hidden sm:table-cell">Desktop Only</th>
<th class="table-cell">Always Visible</th>

<!-- Responsive spacing -->
<div class="p-4 md:p-6 lg:p-8"></div>

Component Organization

Layout components follow this structure:

Consistent Styling

AddButton

Button for adding new items to a list.

Props:

Usage:

<AddButton to="/projects/new" label="New Project" color="blue" />

ViewButton

Button for viewing item details.

EditButton

Button for editing items.

DeleteButton

Button for deleting items.

FilterButton

Button for filtering list items.

Detail Action Components

EditButton (Detail)

Edit button specifically styled for detail views.

Events:

SaveButton

Save button for detail view forms.

Props:

Events:

CancelButton

Cancel button for detail view forms.

Events:

DeleteButton (Detail)

Delete button specifically styled for detail views.

Events:

Usage:

<div class="flex space-x-3">
  <SaveButton :disabled="!hasChanges" @click="save" />
  <CancelButton @click="cancel" />
</div>

System Components

SystemProperties

Displays system-level metadata like creation and modification timestamps.

Props:

Usage:

<SystemProperties
  :id="resource.id"
  :created-at="resource.created_at"
  :updated-at="resource.updated_at"
/>

Interface Definitions

Resource Interface

interface Resource {
  id: string;
  internal_name: string;
  backward_compatibility?: string | null;
  created_at: string | null;
  updated_at: string | null;
}

BackLinkConfig Interface

interface BackLinkConfig {
  title: string;
  route: string;
  icon: Component;
  color?: string;
}

StatusCardConfig Interface

interface StatusCardConfig {
  title: string;
  description: string;
  mainColor: string;
  statusText: string;
  toggleTitle: string;
  isActive: boolean;
  loading: boolean;
  disabled?: boolean;
  activeIconBackgroundClass: string;
  inactiveIconBackgroundClass: string;
  activeIconClass: string;
  inactiveIconClass: string;
  activeIconComponent: Component;
  inactiveIconComponent: Component;
}