Update links data source

This commit is contained in:
2026-06-30 21:04:06 +00:00
parent 70cd01019d
commit 6cfce40e54
4 changed files with 165 additions and 122 deletions
+119 -82
View File
@@ -4,36 +4,66 @@ An Arch Linux terminal-themed portfolio website with Hyprland-style TUI componen
## Features ## Features
- 🖥️ **Hyprland-style TUI** - Terminal interface inspired by Textual Python TUI - Hyprland-style TUI - Terminal interface inspired by Textual Python TUI
- 🎨 **Theme Support** - Arch Linux and Catppuccin (Mocha/Latte) themes - Interactive command line - Type commands directly into the terminal to navigate and run actions
- 🌓 **Dark/Light Mode** - Toggle between dark and light modes - Theme Support - Arch Linux and Catppuccin (Mocha/Latte) themes
- ⌨️ **Keyboard Navigation** - Navigate with arrow keys or vim-style j/k - Dark/Light Mode - Toggle between dark and light modes
- 🎮 **3D Model Viewer** - Interactive Three.js viewer for .glb models - Keyboard Navigation - Navigate with arrow keys or vim-style j/k
- **Configurable Speed** - Per-page typing animation speed - 3D Model Viewer - Interactive Three.js viewer for .glb models
- 📱 **Responsive** - Works on desktop and mobile - QR Links Page - Generate a scannable QR code for any of your links
- 🎨 **Rich Text Formatting** - Colors, backgrounds, and text decorations - Configurable Speed - Per-page typing animation speed
- Responsive - Works on desktop and mobile
- Rich Text Formatting - Colors, backgrounds, and text decorations
## Pages ## Pages
- **Home** (`/`) - Neofetch-style intro with navigation - Home (`/`) - Neofetch-style intro with navigation
- **Portfolio** (`/portfolio`) - Skills, projects, and contact info - About (`/about`) - Background and details
- **Models** (`/models`) - 3D model gallery with interactive viewer - Portfolio (`/portfolio`) - Profile, experience, skills, and contact info
- **Hackathons** (`/hackathons`) - Hackathon projects and achievements - Projects (`/projects`) - Open source, packages, and hackathon projects
- **Components** (`/components`) - Showcase of all TUI components - Models (`/models`) - 3D model gallery with interactive viewer
- Components (`/components`) - Showcase of all TUI components
- Links (`/links`) - All links with on-demand QR codes
The navbar exposes Home, About, Portfolio, Projects, and Blog. The Models, Components, and Links pages are reachable directly by URL or with the terminal `cd` command (for example, `cd links`).
## Terminal Commands
Every terminal page has an interactive command line at the bottom. Click the terminal (or just start typing once focused), enter a command, and press Enter. Output is printed back into the terminal.
Use the Up/Down arrows to cycle through command history.
| Command | Aliases | Description |
|---------|---------|-------------|
| `help` | `h`, `?` | List all available commands |
| `clear` | `cls` | Clear the terminal |
| `whoami` | | Show a short bio |
| `neofetch` | `banner` | Display system info |
| `skills` | | List skills by category |
| `contact` | `socials` | Show social links as buttons |
| `email` | | Open a mail draft |
| `cd <page>` | `goto`, `open` | Navigate to a page |
| `ls` | | List the pages you can visit |
| `theme [name]` | | List or set the color theme |
| `mode [dark\|light]` | | Toggle or set dark/light mode |
| `echo <text>` | | Print text back |
| `date` | | Show the current date and time |
Command definitions live in `src/lib/components/tui/terminal-commands.ts`. Add a new entry to the `commands` list to extend the command set.
## Configuration ## Configuration
The site configuration is now **modular** split into focused files in `src/lib/config/` for easier maintenance. You can still import everything from `$lib/config` for backward compatibility. The site configuration is modular - split into focused files in `src/lib/config/` for easier maintenance. You can still import everything from `$lib/config` for backward compatibility.
### Config File Structure ### Config File Structure
``` ```
src/lib/config/ src/lib/config/
├── index.ts # Barrel export (re-exports all modules) ├── index.ts # Barrel export (re-exports all modules)
├── user.ts # User profile, socials, skills ├── user.ts # User profile, socials, links, skills
├── layout.ts # Layout dimensions, breakpoints, fonts, navbar, scrollbar ├── layout.ts # Layout dimensions, breakpoints, fonts, navbar, scrollbar
├── theme.ts # Colors, animations, effects, loading screen ├── theme.ts # Colors, animations, effects, loading screen
├── content.ts # Projects, 3D models, hackathon cards ├── content.ts # Projects, 3D models, experience, hackathon cards
├── terminal.ts # Terminal settings, TUI styling, speed presets, shortcuts ├── terminal.ts # Terminal settings, TUI styling, speed presets, shortcuts
└── navigation.ts # Navigation links, site metadata, page meta └── navigation.ts # Navigation links, site metadata, page meta
``` ```
@@ -45,9 +75,9 @@ src/lib/config/
import { user, colorPalette, projects } from '$lib/config'; import { user, colorPalette, projects } from '$lib/config';
// Direct imports (smaller bundles, faster builds) // Direct imports (smaller bundles, faster builds)
import { user, skills } from '$lib/config/user'; import { user, skills, links } from '$lib/config/user';
import { colorPalette, animations } from '$lib/config/theme'; import { colorPalette, animations } from '$lib/config/theme';
import { projects, models, cards } from '$lib/config/content'; import { openSourceProjects, cards, experience } from '$lib/config/content';
import { terminalSettings, keyboardShortcuts } from '$lib/config/terminal'; import { terminalSettings, keyboardShortcuts } from '$lib/config/terminal';
import { navigation, site, pageMeta } from '$lib/config/navigation'; import { navigation, site, pageMeta } from '$lib/config/navigation';
``` ```
@@ -56,14 +86,15 @@ import { navigation, site, pageMeta } from '$lib/config/navigation';
| File | Contents | | File | Contents |
|------|----------| |------|----------|
| `user.ts` | `user`, `skills` | | `user.ts` | `user`, `skills`, `links` |
| `layout.ts` | `layout`, `breakpoints`, `fonts`, `navbar`, `scrollbar` | | `layout.ts` | `layout`, `breakpoints`, `fonts`, `navbar`, `scrollbar` |
| `theme.ts` | `colorPalette`, `terminalButtons`, `loadingScreen`, `effects`, `animations` | | `theme.ts` | `colorPalette`, `terminalButtons`, `loadingScreen`, `effects`, `animations` |
| `content.ts` | `projects`, `models`, `cards`, `sortedCards` + types | | `content.ts` | `openSourceProjects`, `packageProjects`, `models`, `experience`, `cards`, `sortedCards` + types |
| `terminal.ts` | `terminalSettings`, `tuiStyle`, `tuiText`, `pageSpeedSettings`, `pageAutoscrollSettings`, `speedPresets`, `modelViewer`, `particles`, `keyboardShortcuts` | | `terminal.ts` | `terminalSettings`, `tuiStyle`, `tuiText`, `pageSpeedSettings`, `pageAutoscrollSettings`, `speedPresets`, `modelViewer`, `particles`, `keyboardShortcuts` |
| `navigation.ts` | `navigation`, `site`, `pageMeta` | | `navigation.ts` | `navigation`, `site`, `pageMeta` |
### Example: Key config snippets ### Example: Key config snippets
```typescript ```typescript
// Toggle theme keys and other shortcuts // Toggle theme keys and other shortcuts
export const keyboardShortcuts = { export const keyboardShortcuts = {
@@ -83,7 +114,6 @@ export const terminalSettings = {
lineDelay: 100, lineDelay: 100,
showCursor: true, showCursor: true,
promptStyle: 'full', promptStyle: 'full',
icon: '🐧',
scrollMargin: 80, scrollMargin: 80,
}; };
@@ -100,21 +130,12 @@ export const colorPalette = {
error: '#f38ba8', error: '#f38ba8',
success: '#a6e3a1', success: '#a6e3a1',
}; };
// TUI styling example
export const tuiStyle = {
borderRadius: 8,
borderWidth: 2,
width: '95%',
bodyPadding: '1rem 1.25rem 2rem 1.25rem',
buttonPadding: '0.5rem 0.75rem',
};
``` ```
### How to Customize ### How to Customize
- Edit `config/user.ts` to update your profile, socials, and skills - Edit `config/user.ts` to update your profile, socials, links, and skills
- Edit `config/content.ts` to add projects, models, or hackathon entries - Edit `config/content.ts` to add projects, models, experience, or hackathon entries
- Edit `config/theme.ts` to change colors, animations, or loading screen - Edit `config/theme.ts` to change colors, animations, or loading screen
- Edit `config/terminal.ts` to adjust typing speed, TUI styling, or shortcuts - Edit `config/terminal.ts` to adjust typing speed, TUI styling, or shortcuts
- Edit `config/layout.ts` to change dimensions, breakpoints, or navbar settings - Edit `config/layout.ts` to change dimensions, breakpoints, or navbar settings
@@ -124,11 +145,28 @@ Changes take effect on next reload. Some values (fonts, CSS variables) may also
### Where to Look for Types & Utilities ### Where to Look for Types & Utilities
- `src/lib/config/` All configuration modules - `src/lib/config/` - All configuration modules
- `src/lib/components/tui/types.ts` TerminalLine types - `src/lib/components/tui/types.ts` - TerminalLine types
- `src/lib/components/tui/utils.ts` Parsing utilities and style helpers - `src/lib/components/tui/utils.ts` - Parsing utilities and style helpers
- `src/lib/stores/theme.ts` — Theme store & `toggleMode()` - `src/lib/components/tui/terminal-commands.ts` - Interactive command definitions
- `src/lib/index.ts` — Helper functions (barrel export) - `src/lib/stores/theme.ts` - Theme store & `toggleMode()`
- `src/lib/index.ts` - Helper functions (barrel export)
## Links Page
The `/links` page lists everything in the `links` array (a dedicated list, separate from `user.socials`) and renders a scannable QR code for whichever link is selected, plus a clickable button to open it.
Add or remove entries in `src/lib/config/user.ts`:
```typescript
export const links: LinkItem[] = [
{ name: 'GitHub', icon: 'mdi:github', link: 'https://github.com/SirBlobby' },
{ name: 'Email', icon: 'mdi:email', link: `mailto:${user.email}` },
// Add page-only links here without touching user.socials
];
```
QR codes are generated with the `svelte-qrcode` package, loaded on the client.
## Speed Presets ## Speed Presets
@@ -214,10 +252,10 @@ Combine multiple styles with commas:
const lines: TerminalLine[] = [ const lines: TerminalLine[] = [
{ type: 'command', content: 'ls -la' }, // With prompt prefix { type: 'command', content: 'ls -la' }, // With prompt prefix
{ type: 'output', content: 'File listing...' }, // Muted text { type: 'output', content: 'File listing...' }, // Muted text
{ type: 'error', content: 'Error message' }, // Red with prefix { type: 'error', content: 'Error message' }, // Red with prefix
{ type: 'success', content: 'Success!' }, // Green with prefix { type: 'success', content: 'Success!' }, // Green with prefix
{ type: 'info', content: 'Information' }, // Primary with prefix { type: 'info', content: 'Information' }, // Primary with prefix
{ type: 'header', content: 'Section Title' }, // Bold with # icon { type: 'header', content: 'Section Title' }, // Bold heading
{ type: 'blank', content: '' }, // Empty line { type: 'blank', content: '' }, // Empty line
{ type: 'divider', content: 'SECTION', id: 'section' }, // Horizontal divider with anchor ID { type: 'divider', content: 'SECTION', id: 'section' }, // Horizontal divider with anchor ID
]; ];
@@ -381,7 +419,6 @@ Groups allow you to arrange multiple elements together with custom layout:
groupDirection: 'row', // row | column (default: row) groupDirection: 'row', // row | column (default: row)
groupAlign: 'start', // start | center | end groupAlign: 'start', // start | center | end
groupGap: '1rem', // CSS gap value groupGap: '1rem', // CSS gap value
groupGap: '1rem', // CSS gap value
groupExpand: true, // Expand children to fill width (default: false) groupExpand: true, // Expand children to fill width (default: false)
inline: true, // Render inline with other elements inline: true, // Render inline with other elements
children: [ children: [
@@ -407,6 +444,7 @@ Main terminal component:
interactive={true} interactive={true}
speed="normal" speed="normal"
autoscroll={true} autoscroll={true}
enableCommands={true}
onComplete={() => console.log('Done!')} onComplete={() => console.log('Done!')}
/> />
``` ```
@@ -417,6 +455,7 @@ Props:
- `interactive` - Enable keyboard navigation - `interactive` - Enable keyboard navigation
- `speed` - Typing speed preset or multiplier - `speed` - Typing speed preset or multiplier
- `autoscroll` - Auto-scroll as content types (default: true) - `autoscroll` - Auto-scroll as content types (default: true)
- `enableCommands` - Show the interactive command input (default: true)
- `onComplete` - Callback when typing animation finishes - `onComplete` - Callback when typing animation finishes
### Anchor Scrolling ### Anchor Scrolling
@@ -439,9 +478,10 @@ src/lib/components/
├── utils.ts # Parsing & styling utilities ├── utils.ts # Parsing & styling utilities
├── terminal-api.ts # Terminal API factory for reactive control ├── terminal-api.ts # Terminal API factory for reactive control
├── terminal-typing.ts # Typing animation engine ├── terminal-typing.ts # Typing animation engine
├── terminal-keyboard.ts# Keyboard navigation handler ├── terminal-keyboard.ts # Keyboard navigation handler
├── terminal-commands.ts # Interactive command definitions
├── TuiHeader.svelte # Top status bar ├── TuiHeader.svelte # Top status bar
├── TuiBody.svelte # Scrollable content area (uses TuiLine) ├── TuiBody.svelte # Scrollable content area + command input
├── TuiFooter.svelte # Bottom status bar ├── TuiFooter.svelte # Bottom status bar
├── TuiLine.svelte # Unified line renderer for all types ├── TuiLine.svelte # Unified line renderer for all types
├── TuiGroup.svelte # Container for grouped elements ├── TuiGroup.svelte # Container for grouped elements
@@ -540,7 +580,6 @@ The `TerminalTUI` component exposes a reactive API for programmatic control via
]); ]);
async function runProcess() { async function runProcess() {
// Update existing line
terminal?.updateById('status', { terminal?.updateById('status', {
type: 'info', type: 'info',
content: 'Processing...' content: 'Processing...'
@@ -548,7 +587,6 @@ The `TerminalTUI` component exposes a reactive API for programmatic control via
await delay(1000); await delay(1000);
// Add progress
terminal?.write({ terminal?.write({
type: 'progress', type: 'progress',
content: '', content: '',
@@ -558,7 +596,6 @@ The `TerminalTUI` component exposes a reactive API for programmatic control via
await delay(1000); await delay(1000);
// Complete
terminal?.updateById('status', { terminal?.updateById('status', {
type: 'success', type: 'success',
content: 'Complete!' content: 'Complete!'
@@ -575,13 +612,14 @@ The `TerminalTUI` component exposes a reactive API for programmatic control via
The `ModelViewer` component provides an interactive Three.js viewer for `.glb` models. The `ModelViewer` component provides an interactive Three.js viewer for `.glb` models.
### Features ### Features
- **Mouse Controls**: Drag to rotate, scroll to zoom - Mouse Controls: Drag to rotate, scroll to zoom
- **Arrow Key Controls**: Use arrow keys to orbit the camera (click viewer to focus first) - Arrow Key Controls: Use arrow keys to orbit the camera (click viewer to focus first)
- **Auto-rotate**: Toggle automatic rotation - Auto-rotate: Toggle automatic rotation
- **Wireframe Mode**: View model wireframe - Wireframe Mode: View model wireframe
- **Adjustable Lighting**: Increase/decrease scene brightness - Adjustable Lighting: Increase/decrease scene brightness
- **Fullscreen Mode**: Expand to full viewport (press `Escape` to exit) - Fullscreen Mode: Expand to full viewport (press Escape to exit)
- **Ground Plane**: Optional shadow-receiving ground - Ground Plane: Optional shadow-receiving ground
- Graceful Fallback: Shows an error message when WebGL is unavailable instead of crashing
### Usage ### Usage
@@ -596,11 +634,13 @@ Place `.glb` files in `/static/models/` and they'll be accessible at `/models/fi
## Tech Stack ## Tech Stack
- **Framework**: SvelteKit 2.x with Svelte 5 runes - Framework: SvelteKit 2.x with Svelte 5 runes
- **Styling**: Tailwind CSS 4.x - Styling: Tailwind CSS 4.x
- **3D**: Three.js with GLTFLoader - 3D: Three.js with GLTFLoader
- **Icons**: @iconify/svelte - QR codes: svelte-qrcode
- **Font**: JetBrains Mono - Icons: @iconify/svelte
- Font: JetBrains Mono
- Runtime: Bun
## Development ## Development
@@ -614,29 +654,31 @@ bun run dev
# Build for production # Build for production
bun run build bun run build
# Preview production build # Type-check
bun run preview bun run check
``` ```
## Keyboard Shortcuts ## Keyboard Shortcuts
| Key | Action | | Key | Action |
|-----|--------| |-----|--------|
| `↑` / `k` | Navigate up | | Up / k | Navigate up |
| `↓` / `j` | Navigate down | | Down / j | Navigate down |
| `Enter` | Activate button | | Enter | Activate button |
| `Y` | Skip typing animation | | Y | Skip typing animation |
| `T` | Toggle dark/light mode | | T | Toggle dark/light mode |
When the command input is focused, these keys type normally instead of triggering navigation.
### 3D Model Viewer ### 3D Model Viewer
| Key | Action | | Key | Action |
|-----|--------| |-----|--------|
| `←` | Rotate camera left | | Left | Rotate camera left |
| `→` | Rotate camera right | | Right | Rotate camera right |
| `↑` | Rotate camera up | | Up | Rotate camera up |
| `↓` | Rotate camera down | | Down | Rotate camera down |
| `Escape` | Exit fullscreen | | Escape | Exit fullscreen |
## Theme System ## Theme System
@@ -647,7 +689,7 @@ Themes are defined as JSON files in `src/lib/assets/themes/`. Each theme contain
```json ```json
{ {
"name": "Theme Name", "name": "Theme Name",
"icon": "🎨", "icon": "arch",
"dark": { "dark": {
"colors": { "colors": {
"primary": "#89b4fa", "primary": "#89b4fa",
@@ -673,8 +715,8 @@ Themes are defined as JSON files in `src/lib/assets/themes/`. Each theme contain
} }
}, },
"light": { "light": {
"colors": { /* light mode colors */ }, "colors": { },
"colorMap": { /* light mode color map */ } "colorMap": { }
} }
} }
``` ```
@@ -696,10 +738,6 @@ Themes are defined as JSON files in `src/lib/assets/themes/`. Each theme contain
``` ```
4. Update the `ColorTheme` type to include your theme name 4. Update the `ColorTheme` type to include your theme name
### Available Themes
- **Arch Linux** (`arch`) - Classic terminal colors with Arch blue
- **Catppuccin** (`catppuccin`) - Soft, pastel Mocha/Latte colors
### Theme-Specific Colors ### Theme-Specific Colors
Beyond the basic colors, themes include: Beyond the basic colors, themes include:
@@ -716,7 +754,6 @@ Beyond the basic colors, themes include:
## Mobile Considerations ## Mobile Considerations
- **Viewport height**: Uses `100dvh` (dynamic viewport height) to properly handle mobile browser chrome - Viewport height: Uses `100dvh` (dynamic viewport height) to properly handle mobile browser chrome
- **Background color**: A fallback dark background (`#1e1e2e`) is set on `html` and `body` to prevent white bars when the page content doesn't fill the viewport - Background color: A fallback dark background (`#1e1e2e`) is set on `html` and `body` to prevent white bars when the page content doesn't fill the viewport
- **Overflow handling**: Hidden horizontal scrollbar to prevent accidental horizontal scroll on mobile - Overflow handling: Hidden horizontal scrollbar to prevent accidental horizontal scroll on mobile
+2 -1
View File
@@ -11,7 +11,8 @@
// ============================================================================ // ============================================================================
// User profile and skills // User profile and skills
export { user, skills } from './user'; export type { LinkItem } from './user';
export { user, skills, links } from './user';
// Layout, breakpoints, fonts, navbar, scrollbar // Layout, breakpoints, fonts, navbar, scrollbar
export { layout, breakpoints, fonts, navbar, scrollbar } from './layout'; export { layout, breakpoints, fonts, navbar, scrollbar } from './layout';
+19
View File
@@ -26,6 +26,25 @@ export const user = {
] ]
}; };
// ============================================================================
// LINKS PAGE
// ============================================================================
export interface LinkItem {
name: string;
icon: string;
link: string;
}
export const links: LinkItem[] = [
{ name: 'GitHub', icon: 'mdi:github', link: 'https://github.com/SirBlobby' },
{ name: 'LinkedIn', icon: 'mdi:linkedin', link: 'https://www.linkedin.com/in/gmanjunatha/' },
{ name: 'Devpost', icon: 'simple-icons:devpost', link: 'https://devpost.com/Sir_Blob_' },
{ name: 'Discord', icon: 'ic:baseline-discord', link: 'https://discord.com/users/sir_blob_' },
{ name: 'Email', icon: 'mdi:email', link: `mailto:${user.email}` },
// { name: 'Blog', icon: 'mdi:rss', link: 'https://blog.sirblob.co' }
];
// ============================================================================ // ============================================================================
// SKILLS // SKILLS
// ============================================================================ // ============================================================================
+1 -15
View File
@@ -1,27 +1,13 @@
<script lang="ts"> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte";
import Icon from "@iconify/svelte"; import Icon from "@iconify/svelte";
import { user, navigation, pageMeta } from "$lib/config"; import { user, links, pageMeta, type LinkItem } from "$lib/config";
import { themeColors } from "$lib/stores/theme"; import { themeColors } from "$lib/stores/theme";
import TuiHeader from "$lib/components/tui/TuiHeader.svelte"; import TuiHeader from "$lib/components/tui/TuiHeader.svelte";
import TuiFooter from "$lib/components/tui/TuiFooter.svelte"; import TuiFooter from "$lib/components/tui/TuiFooter.svelte";
import "$lib/assets/css/terminal-tui.css"; import "$lib/assets/css/terminal-tui.css";
import "$lib/assets/css/tui-body.css"; import "$lib/assets/css/tui-body.css";
interface LinkItem {
name: string;
icon: string;
link: string;
}
const blogLink = navigation.find((item) => item.name === "blog")?.path;
const links: LinkItem[] = [
...user.socials,
{ name: "Email", icon: "mdi:email", link: `mailto:${user.email}` },
...(blogLink ? [{ name: "Blog", icon: "mdi:rss", link: blogLink }] : []),
];
let selected = $state<LinkItem | null>(null); let selected = $state<LinkItem | null>(null);
let QrCode = $state<any>(null); let QrCode = $state<any>(null);
let detailEl = $state<HTMLDivElement>(); let detailEl = $state<HTMLDivElement>();