# Skill: Polish Loading States

Add skeleton loaders, loading indicators, timeout warnings, and empty states to all async views. No view should ever show a blank screen.

## Skeleton Loader Component

Create or use a `SkeletonLoader.vue` component with the glassmorphism style:
- Background: `bg-white/5` with shimmer animation
- Rounded corners matching the card it replaces
- Animate with CSS `@keyframes shimmer` (translate gradient left to right)
- Must use global classes from style.css, not inline Tailwind

## Views to Fix

For EACH view in `neode-ui/src/views/`, verify these states exist:

### 1. Loading State
- Show skeleton placeholders immediately on mount
- Pattern:
  ```vue
  <template>
    <div v-if="isLoading">
      <!-- Skeleton matching the layout -->
    </div>
    <div v-else>
      <!-- Real content -->
    </div>
  </template>
  ```

### 2. Empty State
- When data loads but is empty (zero items)
- Show helpful message with CTA
- Pattern:
  ```vue
  <div v-if="!isLoading && items.length === 0" class="glass-card text-center py-12">
    <p class="text-white/60">No apps installed yet</p>
    <router-link to="/marketplace" class="glass-button mt-4">Browse Marketplace</router-link>
  </div>
  ```

### 3. Timeout Warning
- After 15 seconds of loading, show "Taking longer than expected..."
- After 30 seconds, show troubleshooting options
- Pattern:
  ```typescript
  const loadingTooLong = ref(false)
  let timeout: ReturnType<typeof setTimeout>

  onMounted(() => {
    timeout = setTimeout(() => { loadingTooLong.value = true }, 15000)
  })

  watch(isLoading, (val) => { if (!val) clearTimeout(timeout) })
  ```

## Priority Views (must have all 3 states)

1. **Apps.vue** — app grid skeleton, "No apps installed" empty state
2. **AppDetails.vue** — detail card skeleton, loading indicator
3. **Marketplace.vue** — app card grid skeleton, "Loading apps..." with timeout
4. **Dashboard.vue** — metric card skeletons
5. **Cloud.vue** — file list skeleton, "No files" empty state
6. **Settings.vue** — settings section skeleton
7. **Server.vue** — server info skeleton

## Verification

For each view, confirm:
- [ ] `isLoading` ref exists and is set properly
- [ ] Template has `v-if="isLoading"` skeleton section
- [ ] Template has empty state for zero-data case
- [ ] Loading timeout warning after 15s
- [ ] Skeleton uses global classes, not inline Tailwind

## Deploy After Fixes

Always deploy and verify on live server:
```bash
./scripts/deploy-to-target.sh --live
```

Test by throttling network in browser DevTools to observe loading states.
