Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1418f04
Derive dashboard title from configured GitHub owner
BirgitPohl Jun 15, 2026
ab7fe75
Replace fetch caching with Pinia-backed stale-while-revalidate
BirgitPohl Jun 15, 2026
036ee4b
Drop "Dashboard" suffix from navigation heading and page titles
BirgitPohl Jun 15, 2026
5c52236
Remove unused Project Boards and Project Views features
BirgitPohl Jun 15, 2026
ed65d3a
Stream server fetch logs to a live bottom-right ticker
BirgitPohl Jun 15, 2026
1635769
Drop redundant RefreshIndicator now that the LogTicker shows activity
BirgitPohl Jun 15, 2026
1084cf8
Move per-page stats into a compact strip under the nav
BirgitPohl Jun 15, 2026
1ea8640
Add semantic color layer and refresh outdated README
BirgitPohl Jun 15, 2026
436618b
Allow BRAND_COLORS env var to override semantic color tokens
BirgitPohl Jun 15, 2026
e847fed
Compact repositories list, mobile nav height, nav reorder
BirgitPohl Jun 15, 2026
97f4cbf
Move per-page action buttons into the navigation substrip
BirgitPohl Jun 15, 2026
f325a7f
Mobile nav dropdown, primary-tint links, SSR-safe header actions
BirgitPohl Jun 15, 2026
02dd226
Show current page title next to burger on mobile
BirgitPohl Jun 15, 2026
ba4ad95
Harmonize palette and migrate every component to semantic tokens
BirgitPohl Jun 15, 2026
44a55bc
Scale UI for distance viewing; tighten layout; fix nav hover + runnin…
BirgitPohl Jun 15, 2026
0888467
Swap emoji glyphs for Lucide icons via @nuxt/icon
BirgitPohl Jun 15, 2026
bc6e099
Distinguish review-comment icon from comment-count and reorder
BirgitPohl Jun 15, 2026
6c064e1
Hide review "commented" bubble when no comments are unresolved
BirgitPohl Jun 15, 2026
55e0ef5
Align list columns across rows via CSS subgrid
BirgitPohl Jun 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 19 additions & 138 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,161 +1,42 @@
# GitHub Dashboard

A beautiful dashboard for monitoring GitHub workflows, repositories, and projects across your organization.
Dashboard for monitoring GitHub Actions workflows, repositories, and pull requests across an organization.

## ✨ Features

- **🔄 Workflows**: Monitor GitHub Actions workflows across all repositories
- **📁 Repositories**: Browse and categorize all organization repositories
- **📋 Projects**: View GitHub Projects (project boards) with item counts and status
- **🎨 Beautiful UI**: Clean, responsive design with status-based styling
- **🔍 Smart Categorization**: Automatic repository categorization and tech stack detection

## 🚀 Setup

### 1. Install Dependencies
## Setup

```bash
npm install
```

### 2. Environment Configuration

Create a `.env` file in the root directory:
Create a `.env` in the project root:

```env
GITHUB_TOKEN=your_github_token_here
GITHUB_OWNER=GithubOwner
GITHUB_OWNER=YourGithubOrgOrUser
```

### 3. GitHub Token Setup

Create a GitHub Personal Access Token with the following scopes:

**Required for Workflows & Repositories:**
- `repo` - Access to repositories
- `read:org` - Read organization data
The token needs the `repo` and `read:org` scopes — create one at <https://github.com/settings/tokens>.

**Additional for Projects:**
- `read:project` - Access to GitHub Projects (project boards)
Optional — override up to 10 brand colors with a JSON env var. Unset keys keep their defaults.

**How to create the token:**

1. Go to [GitHub Token Settings](https://github.com/settings/tokens)
2. Click "Generate new token (classic)"
3. Give it a descriptive name (e.g., "GitHub Dashboard")
4. Select the required scopes listed above
5. Click "Generate token"
6. Copy the token and add it to your `.env` file

### 4. Development Server

Start the development server on `http://localhost:3000`:

```bash
npm run dev
```env
BRAND_COLORS={"primary":"#0066cc","primaryBright":"#cce0ff","success":"#00aa44"}
```

## 📱 Pages

### Workflows (`/`)
- Shows GitHub Actions workflow runs from all repositories
- Color-coded status indicators (success, failure, pending)
- Repository context and branch information
- Sorted by most recent runs

### Repositories (`/repositories`)
- Lists all organization repositories
- Automatic categorization (Web App, API/Service, Library, etc.)
- Tech stack detection from languages and topics
- Statistics: stars, forks, issues, last updated
- Repository size and creation date

### Projects (`/projects`)
- GitHub Projects (project boards) overview
- Active vs closed project status
- Item counts per project
- Direct links to project boards

**Note:** Projects page requires the `read:project` scope. Without it, you'll see a helpful error message with setup instructions.

## 🔧 Configuration

### Environment Variables

| Variable | Description | Required |
|----------|-------------|----------|
| `GITHUB_TOKEN` | Personal Access Token | ✅ Yes |
| `GITHUB_OWNER` | Organization/User name | ✅ Yes |

### Token Scopes

| Scope | Purpose | Required For |
|-------|---------|--------------|
| `repo` | Repository access | Workflows, Repositories |
| `read:org` | Organization data | All features |
| `read:project` | GitHub Projects | Projects page |

## 🏗️ Production
Allowed keys: `primary`, `primaryBright`, `primaryDark`, `secondary`, `secondaryBright`, `secondaryDark`, `tertiary`, `tertiaryBright`, `tertiaryDark`, `neutral`, `neutralBright`, `neutralDark`, `success`, `successBright`, `successDark`, `warning`, `warningBright`, `warningDark`, `error`, `errorBright`, `errorDark`, `info`, `infoBright`, `infoDark`. Values must be hex (`#abc` or `#aabbcc`).

Build the application for production:
## Run

```bash
npm run build
npm run dev # http://localhost:3000
npm run build # production build
npm run preview # preview production build
```

Preview the production build:

```bash
npm run preview
```

## 🎨 Architecture

- **Nuxt 3** - Vue.js framework with SSR
- **TypeScript** - Type safety throughout
- **GitHub API** - REST API for workflows/repos, GraphQL for projects
- **Responsive Design** - Mobile-friendly interface
- **Error Handling** - Graceful fallbacks and helpful error messages

## 🔍 API Endpoints

- `/api/workflows` - Fetch workflow runs from all repositories
- `/api/repositories` - Get categorized repository information
- `/api/projects` - GitHub Projects with GraphQL API

## 🤝 Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Test thoroughly
5. Submit a pull request

## 📝 License

This project is for use for everyone.

# yarn
yarn build

# bun
bun run build
```

Locally preview production build:

```bash
# npm
npm run preview

# pnpm
pnpm preview

# yarn
yarn preview

# bun
bun run preview
```
## Pages

Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
| Route | Description |
| ----------------- | -------------------------------------------- |
| `/` | Workflow runs across all repos |
| `/repositories` | Categorized repositories with tech stacks |
| `/pull-requests` | PRs filtered by state, repo, or search |
5 changes: 5 additions & 0 deletions app.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<script setup>
// Import design tokens globally
import '~/assets/styles/design-tokens.css'

const brandThemeCss = useBrandThemeCss()
if (brandThemeCss) {
useHead({ style: [{ children: brandThemeCss }] })
}
</script>

<template>
Expand Down
66 changes: 66 additions & 0 deletions assets/styles/design-tokens.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@
* All components should reference these CSS variables instead of hardcoded values
*/

/* Root font-size sets the rem unit for every token below — bump this to
* scale text AND spacing for distance-viewed dashboards. Browser default
* is 16px; 20px (1.25×) makes a wall-mounted Game-Boy-panel readable
* from across the room without changing any individual component. */
html {
font-size: 26px;
}

:root {
/* ========================================
COLORS
Expand Down Expand Up @@ -82,6 +90,64 @@
--color-border-hover: var(--color-gray-300);
--color-border-focus: var(--color-primary-600);

/* ========================================
SEMANTIC COLOR LAYER
========================================
Components MUST reference these named roles instead of raw scale tokens
or hex literals. The scale tokens above are palette primitives; the
names below assign roles. Retheme the app by editing this section. */

/* Identity — harmonized 10-color palette (teal/cream/amber/red) */
--color-primary: #0a9396; /* Dark Cyan */
--color-primary-bright: #94d2bd; /* Pearl Aqua */
--color-primary-dark: #005f73; /* Dark Teal */
--color-on-primary: #ffffff;

--color-secondary: #001219; /* Ink Black */
--color-secondary-bright: #e9d8a6; /* Wheat */
--color-secondary-dark: #001219; /* Ink Black */
--color-on-secondary: #ffffff;

--color-tertiary: #ca6702; /* Burnt Caramel — merged / done */
--color-tertiary-bright: #e9d8a6; /* Wheat */
--color-tertiary-dark: #bb3e03; /* Rusty Spice */
--color-on-tertiary: #ffffff;

/* Neutral — grey scale (palette has no true grey; kept separate) */
--color-neutral: var(--color-gray-500);
--color-neutral-bright: var(--color-gray-100);
--color-neutral-dark: var(--color-gray-800);
--color-on-neutral: #ffffff;

/* Status */
--color-success: #94d2bd; /* Pearl Aqua */
--color-success-bright: #e9d8a6; /* Wheat */
--color-success-dark: #005f73; /* Dark Teal */
--color-on-success: #001219; /* Pearl Aqua needs dark text */

--color-warning: #ee9b00; /* Golden Orange */
--color-warning-bright: #e9d8a6; /* Wheat */
--color-warning-dark: #ca6702; /* Burnt Caramel */
--color-on-warning: #001219; /* Golden Orange — dark text */

--color-error: #ae2012; /* Oxidized Iron */
--color-error-bright: #e9d8a6; /* Wheat */
--color-error-dark: #9b2226; /* Brown Red */
--color-on-error: #ffffff;

--color-info: #005f73; /* Dark Teal */
--color-info-bright: #94d2bd; /* Pearl Aqua */
--color-info-dark: #001219; /* Ink Black */
--color-on-info: #ffffff;

/* Surface / text roles for inverse (dark glass) surfaces */
--color-surface-inverse: rgba(15, 23, 42, 0.88);
--color-on-surface-inverse: #f8fafc;

/* Text-on-color helpers for dynamically computed contrast */
--color-text-on-light: #000000;
--color-text-on-dark: #ffffff;

/* ========================================
TYPOGRAPHY
======================================== */
Expand Down
65 changes: 65 additions & 0 deletions composables/useBrandTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const MAX_OVERRIDES = 10

/**
* Semantic color roles that may be overridden via the BRAND_COLORS env var.
* Keys in the JSON are camelCase; CSS variables are kebab-case.
*/
const ALLOWED_ROLES: Record<string, string> = {
primary: '--color-primary',
primaryBright: '--color-primary-bright',
primaryDark: '--color-primary-dark',
secondary: '--color-secondary',
secondaryBright: '--color-secondary-bright',
secondaryDark: '--color-secondary-dark',
tertiary: '--color-tertiary',
tertiaryBright: '--color-tertiary-bright',
tertiaryDark: '--color-tertiary-dark',
neutral: '--color-neutral',
neutralBright: '--color-neutral-bright',
neutralDark: '--color-neutral-dark',
success: '--color-success',
successBright: '--color-success-bright',
successDark: '--color-success-dark',
warning: '--color-warning',
warningBright: '--color-warning-bright',
warningDark: '--color-warning-dark',
error: '--color-error',
errorBright: '--color-error-bright',
errorDark: '--color-error-dark',
info: '--color-info',
infoBright: '--color-info-bright',
infoDark: '--color-info-dark',
}

const HEX_RE = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/

/**
* Reads BRAND_COLORS from runtime config (a JSON string), validates each entry
* against the allowlist and a hex-color regex, and returns a `:root { ... }`
* CSS snippet that overrides the design-token defaults. At most 10 overrides
* are honored. Unknown keys, malformed values, and parse errors are ignored.
*/
export function useBrandThemeCss(): string {
const { public: { brandColors } } = useRuntimeConfig()
const raw = (brandColors as string | undefined)?.trim()
if (!raw) return ''

let parsed: unknown
try {
parsed = JSON.parse(raw)
} catch {
return ''
}
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return ''

const declarations: string[] = []
for (const [key, value] of Object.entries(parsed as Record<string, unknown>)) {
if (declarations.length >= MAX_OVERRIDES) break
const cssVar = ALLOWED_ROLES[key]
if (!cssVar) continue
if (typeof value !== 'string' || !HEX_RE.test(value)) continue
declarations.push(`${cssVar}: ${value};`)
}
if (declarations.length === 0) return ''
return `:root { ${declarations.join(' ')} }`
}
Loading