Skip to content

feat: improve dashboard layout, add chat quick-start templates, and s… - #2

Merged
ivancidev merged 1 commit into
mainfrom
feat/dashboard-chat-usability
Jul 20, 2026
Merged

feat: improve dashboard layout, add chat quick-start templates, and s…#2
ivancidev merged 1 commit into
mainfrom
feat/dashboard-chat-usability

Conversation

@ivancidev

Copy link
Copy Markdown
Owner

…ecure API key controls

📌 Descripción

Describa los cambios principales introducidos en este Pull Request y qué problema resuelven.

🧪 Pruebas realizadas

Detalle los pasos para verificar los cambios localmente:

  • ¿Se ejecutó bun run lint exitosamente?
  • ¿Se ejecutó bun run build exitosamente?
  • Pasos de pruebas manuales realizados:

📸 Capturas de pantalla o grabaciones (si aplica)

Adjunte capturas o grabaciones para cambios de interfaz de usuario.

📋 Lista de verificación

  • Mi código sigue el estilo y arquitectura del proyecto (AGENTS.md).
  • He actualizado la documentación correspondiente si aplica.
  • No he expuesto claves API ni información sensible en código o commits.

@ivancidev ivancidev self-assigned this Jul 20, 2026
Copilot AI review requested due to automatic review settings July 20, 2026 02:35
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
skillstudio Ready Ready Preview, Comment Jul 20, 2026 2:36am

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ivancidev
ivancidev merged commit 20fee78 into main Jul 20, 2026
2 of 4 checks passed
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Improve dashboard filters, add chat templates, and enhance API key UX

✨ Enhancement 🕐 40+ Minutes

Grey Divider

AI Description

• Add dashboard metrics plus search, platform filters, and sorting by date/name.
• Add chat quick-start templates and richer skill file preview with in-app inspector.
• Improve local API key UX (status badge, reveal/clear) and refresh landing/sidebar UI.
Diagram

graph TD
  LP["Landing page"] --> DP["Dashboard page"]
  LP --> CI["Generate chat"]
  DP --> LS[("LocalStorage")]
  DP --> EX["/api/export"]
  CI --> LS
  CI --> SP["Skill preview"]
  CI --> CM["Chat templates"] --> CI
  CI --> EX
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Centralize localStorage access behind a storage module/context
  • ➕ Avoids duplicated key names/counting logic across pages
  • ➕ Enables a single source of truth for skills + API key state
  • ➕ Easier to add tests/mocks for persistence behavior
  • ➖ More abstraction and wiring (context/provider) for an MVP
  • ➖ Requires refactors to adopt consistently across the app
2. Persist dashboard filter/sort state in URL query params
  • ➕ Shareable links and better refresh/back-button behavior
  • ➕ Makes state restoration explicit and debuggable
  • ➖ More router plumbing and edge cases (invalid params)
  • ➖ Not always desirable for purely local UI preferences
3. Move quick-start templates to a JSON/config file (or server-driven)
  • ➕ Easier to extend, localize, and A/B test templates
  • ➕ Keeps UI components smaller and more focused
  • ➖ Adds indirection/loading concerns if server-driven
  • ➖ Still needs product decisions around versioning and ownership

Recommendation: Current approach is appropriate for a client-side MVP (simple, fast iteration). If API key/skill persistence and related UI expands beyond the current pages, prioritize a small typed storage wrapper (and optionally a context) to prevent drift in localStorage keys and derived metrics.

Files changed (7) +615 / -121

Enhancement (7) +615 / -121
page.tsxAdd dashboard metrics, search/filter/sort, and API key status counter +159/-16

Add dashboard metrics, search/filter/sort, and API key status counter

• Introduces dashboard-level metrics (skills count, active platforms, key configuration count) and an interactive control bar for searching, filtering by platform, and sorting by date/name. Updates empty state messaging and drives the grid from the filtered/sorted list sourced from localStorage with mock fallback.

app/(app)/dashboard/page.tsx

page.tsxRedesign landing page with stronger CTA navigation and product showcase +212/-51

Redesign landing page with stronger CTA navigation and product showcase

• Replaces the minimal hero layout with a richer marketing page including app navigation links, updated hero copy, a workspace mockup, feature cards, and a supported tools section. Aligns styling with the app’s newer visual system (colors, typography, shadows).

app/(marketing)/page.tsx

chat-interface.tsxImprove API key controls and wire template selection into chat send flow +53/-14

Improve API key controls and wire template selection into chat send flow

• Adds connection-status badges for local vs fallback mode, improves key input affordances (show/hide with tooltip), and adds a one-click local key clear action. Passes an onSelectTemplate callback into ChatMessages so template clicks send a user prompt automatically.

components/chat/chat-interface.tsx

chat-messages.tsxAdd quick-start template cards for empty chat state +52/-4

Add quick-start template cards for empty chat state

• Defines a small set of starter templates (title/description/prompt) and renders them when there are no messages. Extends props to optionally accept an onSelectTemplate handler to trigger prompt injection.

components/chat/chat-messages.tsx

skill-preview.tsxAdd file selection and in-tab code inspector with copy/close actions +69/-16

Add file selection and in-tab code inspector with copy/close actions

• Upgrades the Files tab to support selecting SKILL.md or an extra file and viewing its contents in an embedded inspector panel. Adds per-file copy-to-clipboard feedback and a close control while keeping existing markdown/install flows intact.

components/chat/skill-preview.tsx

sidebar.tsxAdd local sandbox profile/sync widget and sign-in CTA +35/-2

Add local sandbox profile/sync widget and sign-in CTA

• Enhances the desktop sidebar footer with an offline/local sandbox status indicator, a demo profile block, and a ‘Sign In to Sync’ secondary button. Minor styling tweaks to align with updated typography and color tokens.

components/dashboard/sidebar.tsx

skill-card.tsxShow skill metadata (line count, generated date) and refine card visuals +35/-18

Show skill metadata (line count, generated date) and refine card visuals

• Extends the Skill type with an optional createdAt and displays derived metadata (instruction line count, formatted date/draft label). Refines badges and controls for a denser, more informative skill card presentation.

components/dashboard/skill-card.tsx

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (2) 📜 Skill insights (0)

Grey Divider


Action required

1. setSortBy uses as any 📘 Rule violation ⚙ Maintainability
Description
The new sort dropdown casts e.target.value to any without documenting why any is unavoidable,
which erases type safety and makes future refactors riskier. This violates the strict TypeScript
requirement to avoid any unless explicitly justified with an explanatory comment.
Code

app/(app)/dashboard/page.tsx[255]

+              onChange={(e) => setSortBy(e.target.value as any)}
Evidence
PR Compliance ID 2 forbids any unless it is unavoidable and documented. The new code uses an any
cast in the sort dropdown without any explanatory comment.

AGENTS.md: Strict TypeScript: Avoid any Unless Documented as Unavoidable
app/(app)/dashboard/page.tsx[253-256]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`setSortBy(e.target.value as any)` introduces an undocumented `any` cast, violating strict typing requirements.

## Issue Context
`sortBy` is already a finite union (`'newest' | 'oldest' | 'name'`). The event value can be safely narrowed to that union (optionally with a runtime guard) without using `any`.

## Fix Focus Areas
- app/(app)/dashboard/page.tsx[253-261]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Non-brand accent colors used 📘 Rule violation ≡ Correctness
Description
The marketing page introduces decorative Tailwind accent colors (rose, amber, emerald) and
emerald-styled status chips, which conflicts with the design-system requirement to use #6366F1 as
the single visual accent and restrict green to positive indicators. This can cause brand
inconsistency and fail UI compliance checks.
Code

app/(marketing)/page.tsx[R72-74]

+              <span className="w-2.5 h-2.5 rounded-full bg-rose-500/85" />
+              <span className="w-2.5 h-2.5 rounded-full bg-amber-500/85" />
+              <span className="w-2.5 h-2.5 rounded-full bg-emerald-500/85" />
Evidence
PR Compliance ID 5 restricts accent usage to #6366F1 and limits green usage. The new UI introduces
decorative red/yellow/green dots and emerald-tinted UI elements that are outside the allowed accent
palette.

AGENTS.md: Design System Compliance: Colors, Typography, and No Gradients
app/(marketing)/page.tsx[72-74]
app/(marketing)/page.tsx[120-120]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The landing page uses non-design-system accent colors (`bg-rose-500`, `bg-amber-500`, `bg-emerald-500` and related emerald styling) which violates the "single accent" requirement.

## Issue Context
Per the design system, `#6366F1` is the only visual accent color; gradients are disallowed; and green should be reserved for positive/ready indicators (and should not be used decoratively).

## Fix Focus Areas
- app/(marketing)/page.tsx[70-75]
- app/(marketing)/page.tsx[118-121]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Unused icon imports 🐞 Bug ≡ Correctness
Description
app/(marketing)/page.tsx imports ShieldCheck and ArrowRight from lucide-react but never uses
them, which is likely to be reported by the repo’s ESLint run (npm script: lint is eslint). This
can break CI if no-unused-vars/unused imports are treated as errors (common with
eslint-config-next/typescript).
Code

app/(marketing)/page.tsx[R4-15]

+import { 
+  ShieldCheck, 
+  Cpu, 
+  Folder, 
+  FileText, 
+  Database, 
+  Palette, 
+  GitCommit, 
+  Code2, 
+  ArrowRight,
+  Terminal
+} from 'lucide-react'
Evidence
The landing page imports ShieldCheck and ArrowRight but the rest of the file does not reference
those identifiers anywhere, making them unused. The repo’s lint script is eslint, so unused
imports are likely to be caught during CI/local checks.

app/(marketing)/page.tsx[1-15]
app/(marketing)/page.tsx[17-250]
package.json[5-10]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`ShieldCheck` and `ArrowRight` are imported but unused in `app/(marketing)/page.tsx`, which will likely be flagged during `bun run lint`.

### Issue Context
The repo’s lint script runs plain `eslint` (see `package.json`). Keeping unused imports risks lint failure depending on configured rule severity.

### Fix Focus Areas
- app/(marketing)/page.tsx[4-15]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Missing GPT filter tab 🐞 Bug ⚙ Maintainability
Description
DashboardPage supports filtering by 'gpt' (state type and metrics) but the rendered platform tab
list omits 'gpt', so users can’t select GPT via the new filter UI. This makes the filtering
feature inconsistent with the supported Skill.platform values shown on the page.
Code

app/(app)/dashboard/page.tsx[R233-248]

+          {/* Platform Tabs */}
+          <div className="flex items-center bg-slate-50 border border-slate-200 rounded-lg p-0.5 gap-0.5">
+            {(['all', 'cursor', 'claude', 'windsurf'] as const).map((p) => (
+              <button
+                key={p}
+                onClick={() => setPlatformFilter(p)}
+                className={`font-mono text-[10px] uppercase tracking-wider font-bold px-2.5 py-1.5 rounded-md transition-colors cursor-pointer select-none ${
+                  platformFilter === p
+                    ? 'bg-white text-brand-indigo shadow-sm border border-slate-200/60'
+                    : 'text-slate-500 hover:text-slate-850 hover:bg-slate-100/50'
+                }`}
+              >
+                {p}
+              </button>
+            ))}
+          </div>
Evidence
The filter state explicitly includes 'gpt', but the platform tab array doesn’t include it, so
setPlatformFilter('gpt') can’t be reached via the tab UI despite GPT being tracked elsewhere on
the page.

app/(app)/dashboard/page.tsx[52-57]
app/(app)/dashboard/page.tsx[122-128]
app/(app)/dashboard/page.tsx[233-248]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The dashboard filter state supports `'gpt'`, and the dashboard metrics compute `gptCount`, but the platform tabs only render `all/cursor/claude/windsurf`. This prevents users from filtering GPT skills using the UI.

### Issue Context
`Skill.platform` includes `gpt`, and the page already counts GPT skills in metrics.

### Fix Focus Areas
- app/(app)/dashboard/page.tsx[54-56]
- app/(app)/dashboard/page.tsx[233-248]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

<ArrowUpDown className="w-3.5 h-3.5 text-slate-400" />
<select
value={sortBy}
onChange={(e) => setSortBy(e.target.value as any)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. setsortby uses as any 📘 Rule violation ⚙ Maintainability

The new sort dropdown casts e.target.value to any without documenting why any is unavoidable,
which erases type safety and makes future refactors riskier. This violates the strict TypeScript
requirement to avoid any unless explicitly justified with an explanatory comment.
Agent Prompt
## Issue description
`setSortBy(e.target.value as any)` introduces an undocumented `any` cast, violating strict typing requirements.

## Issue Context
`sortBy` is already a finite union (`'newest' | 'oldest' | 'name'`). The event value can be safely narrowed to that union (optionally with a runtime guard) without using `any`.

## Fix Focus Areas
- app/(app)/dashboard/page.tsx[253-261]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread app/(marketing)/page.tsx
{/* Header of Mockup */}
<div className="flex items-center justify-between border-b border-slate-800/60 pb-3 mb-4 select-none">
<div className="flex items-center gap-2">
<span className="w-2.5 h-2.5 rounded-full bg-rose-500/85" />

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Non-brand accent colors used 📘 Rule violation ≡ Correctness

The marketing page introduces decorative Tailwind accent colors (rose, amber, emerald) and
emerald-styled status chips, which conflicts with the design-system requirement to use #6366F1 as
the single visual accent and restrict green to positive indicators. This can cause brand
inconsistency and fail UI compliance checks.
Agent Prompt
## Issue description
The landing page uses non-design-system accent colors (`bg-rose-500`, `bg-amber-500`, `bg-emerald-500` and related emerald styling) which violates the "single accent" requirement.

## Issue Context
Per the design system, `#6366F1` is the only visual accent color; gradients are disallowed; and green should be reserved for positive/ready indicators (and should not be used decoratively).

## Fix Focus Areas
- app/(marketing)/page.tsx[70-75]
- app/(marketing)/page.tsx[118-121]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread app/(marketing)/page.tsx
import { Logo } from '@/components/ui/logo'
import { Button } from '@/components/ui/button'
import Link from 'next/link'
import {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Unused icon imports 🐞 Bug ≡ Correctness

app/(marketing)/page.tsx imports ShieldCheck and ArrowRight from lucide-react but never uses
them, which is likely to be reported by the repo’s ESLint run (npm script: lint is eslint). This
can break CI if no-unused-vars/unused imports are treated as errors (common with
eslint-config-next/typescript).
Agent Prompt
### Issue description
`ShieldCheck` and `ArrowRight` are imported but unused in `app/(marketing)/page.tsx`, which will likely be flagged during `bun run lint`.

### Issue Context
The repo’s lint script runs plain `eslint` (see `package.json`). Keeping unused imports risks lint failure depending on configured rule severity.

### Fix Focus Areas
- app/(marketing)/page.tsx[4-15]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


{/* Filters and Sort */}
<div className="flex flex-wrap items-center gap-3.5">
{/* Platform Tabs */}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

4. Missing gpt filter tab 🐞 Bug ⚙ Maintainability

DashboardPage supports filtering by 'gpt' (state type and metrics) but the rendered platform tab
list omits 'gpt', so users can’t select GPT via the new filter UI. This makes the filtering
feature inconsistent with the supported Skill.platform values shown on the page.
Agent Prompt
### Issue description
The dashboard filter state supports `'gpt'`, and the dashboard metrics compute `gptCount`, but the platform tabs only render `all/cursor/claude/windsurf`. This prevents users from filtering GPT skills using the UI.

### Issue Context
`Skill.platform` includes `gpt`, and the page already counts GPT skills in metrics.

### Fix Focus Areas
- app/(app)/dashboard/page.tsx[54-56]
- app/(app)/dashboard/page.tsx[233-248]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants