Complete new Design and Structure
This commit is contained in:
147
AGENTS.md
Normal file
147
AGENTS.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# AGENTS.md — AI Agent Handoff Guide
|
||||
|
||||
This file is for the **next AI agent** working on this project. Read this before making any changes.
|
||||
|
||||
## What Is This Project?
|
||||
|
||||
**malxte.de** is a single-page personal website for **Malxte** (aka ByteMalte) — a Rust programmer, Nostr enthusiast, and content creator. The site introduces who he is, links to his social profiles, and showcases his projects.
|
||||
|
||||
- **Live at**: [malxte.de](https://malxte.de)
|
||||
- **Stack**: SvelteKit 2 + Svelte 5 + TypeScript + Vite + pnpm
|
||||
- **Type**: Static personal about page (no backend, no database, no API)
|
||||
|
||||
## Critical Files
|
||||
|
||||
| File | What It Does | Edit When |
|
||||
|------|-------------|-----------|
|
||||
| `src/routes/+page.svelte` | ALL page content — hero, about, connect, projects | Adding/changing content, links, styling |
|
||||
| `src/routes/+layout.svelte` | Global shell — header, nav, footer, global CSS | Changing navigation, layout structure, global styles |
|
||||
| `src/app.html` | HTML shell — font loading | Adding fonts, meta tags, scripts |
|
||||
| `BYTEMALTE.md` | Design system spec (colors, typography, components) | Updating design tokens |
|
||||
| `package.json` | Dependencies and scripts | Adding/removing packages |
|
||||
|
||||
## Design System
|
||||
|
||||
**Always follow the BYTEMALTE Design System** (see `BYTEMALTE.md`).
|
||||
|
||||
### Current Color Tokens (v1.1)
|
||||
|
||||
| Token | Hex | Used For |
|
||||
|-------|-----|----------|
|
||||
| Primary | `#8888FF` | Buttons, links, brand accents, hover states |
|
||||
| Secondary | `#3DDC84` | Tags, success indicators |
|
||||
| Background | `#0F172A` | Page background |
|
||||
| Surface | `#1E293B` | Cards, sections, modals |
|
||||
| Text High | `#F8FAFC` | Headings, primary text |
|
||||
| Text Muted | `#B0BDD0` | Descriptions, footer, secondary text |
|
||||
| Error | `#EF4444` | Destructive actions |
|
||||
|
||||
### When using these colors in CSS:
|
||||
|
||||
- **Primary**: `#8888ff` (hex) or `rgba(136, 136, 255, X)` (for transparency)
|
||||
- **Primary hover**: `#9a9aff`
|
||||
- **Secondary**: `#3ddc84` or `rgba(61, 220, 132, X)`
|
||||
- **Muted text**: `#b0bdd0`
|
||||
|
||||
### Border Radii
|
||||
|
||||
- Buttons: `8px`
|
||||
- Cards/Containers: `16px`
|
||||
- Profile images: `50%` (circle)
|
||||
|
||||
### Typography
|
||||
|
||||
- Font: `Inter, system-ui, sans-serif`
|
||||
- h1: `2.5rem`, weight 700
|
||||
- h2: `1.8rem`, weight 600
|
||||
- h3: `1.2rem`, weight 500
|
||||
- Body: `1rem`, weight 400, line-height 1.6
|
||||
|
||||
## How Content Is Organized
|
||||
|
||||
All page content lives in `src/routes/+page.svelte`. Data is defined as static arrays:
|
||||
|
||||
```typescript
|
||||
// Social links — add/remove/edit entries here
|
||||
const connectLinks = [
|
||||
{ title: '...', description: '...', icon: '<svg>...</svg>', href: '...', cta: '...' },
|
||||
];
|
||||
|
||||
// Projects — add/remove/edit entries here
|
||||
const projects = [
|
||||
{ title: '...', description: '...', tags: ['...'], link: '...' | null },
|
||||
];
|
||||
```
|
||||
|
||||
SVG icons are inline strings (not components). Copy from [Lucide](https://lucide.dev/) or similar.
|
||||
|
||||
## Nostr Identity
|
||||
|
||||
The site displays Malxte's Nostr credentials in the hero section:
|
||||
|
||||
- **NIP-05**: `_@bytemalte.de`
|
||||
- **npub**: `npub1guff8dkdz7k47zh0mx26y0mmx5l6np57jjkvmhnyrak0n50r5hxqjdnsra`
|
||||
|
||||
Both have copy-to-clipboard buttons. State is managed via:
|
||||
|
||||
```typescript
|
||||
let copiedField = $state('');
|
||||
function copyToClipboard(text: string, field: string) { ... }
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Adding a new social link
|
||||
|
||||
1. Open `src/routes/+page.svelte`
|
||||
2. Add an entry to the `connectLinks` array
|
||||
3. For the icon, use an inline SVG string (24x24 viewBox, stroke-based)
|
||||
|
||||
### Adding a new project
|
||||
|
||||
1. Open `src/routes/+page.svelte`
|
||||
2. Add an entry to the `projects` array
|
||||
3. Use `link: null` if there's no external URL
|
||||
|
||||
### Changing colors
|
||||
|
||||
1. Update `BYTEMALTE.md` with the new values
|
||||
2. Find-and-replace in `src/routes/+layout.svelte` and `src/routes/+page.svelte`
|
||||
3. Don't forget `rgba()` variants (e.g., `rgba(136, 136, 255, 0.1)`)
|
||||
|
||||
### Adding a new page
|
||||
|
||||
1. Create `src/routes/new-page/+page.svelte`
|
||||
2. It will automatically be available at `/new-page`
|
||||
3. Add a nav link in `src/routes/+layout.svelte`
|
||||
|
||||
### Updating the footer links
|
||||
|
||||
Edit the footer section in `src/routes/+layout.svelte` (around line 189-196).
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
After making changes, always run:
|
||||
|
||||
```bash
|
||||
pnpm check # 0 errors, 0 warnings expected
|
||||
pnpm build # Must succeed
|
||||
```
|
||||
|
||||
## Svelte 5 Patterns Used
|
||||
|
||||
- **`$state()`** — Reactive state declaration
|
||||
- **`$props()`** — Component props (layout uses `let { children } = $props()`)
|
||||
- **`{@render children()}`** — Slot rendering (replaces `<slot />`)
|
||||
- **`{#each}` / `{#if}`** — Control flow blocks
|
||||
- **Scoped `<style>`** — Component CSS
|
||||
|
||||
## Things to NOT Do
|
||||
|
||||
- Don't use Svelte 4 patterns (`$:`, `<slot>`, `export let`)
|
||||
- Don't add CSS frameworks (Tailwind, Bootstrap, etc.)
|
||||
- Don't add runtime dependencies (everything should stay devDependencies)
|
||||
- Don't break WCAG AA contrast ratios
|
||||
- Don't remove `rel="noopener noreferrer"` from `target="_blank"` links
|
||||
- Don't hardcode the year in the footer (it uses `new Date().getFullYear()`)
|
||||
- Don't commit `.env` files or secrets
|
||||
160
ARCHITECTURE.md
Normal file
160
ARCHITECTURE.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# Architecture
|
||||
|
||||
This document describes the technical architecture of **malxte.de**.
|
||||
|
||||
## Overview
|
||||
|
||||
malxte.de is a static single-page personal website built as a **SvelteKit** application. It uses server-side rendering (SSR) with SvelteKit's adapter system for deployment flexibility. There is no backend, database, or API — all content is hardcoded in Svelte components.
|
||||
|
||||
## Directory Layout
|
||||
|
||||
```
|
||||
.
|
||||
├── src/ # Application source
|
||||
│ ├── app.d.ts # Global TypeScript type declarations
|
||||
│ ├── app.html # HTML shell template
|
||||
│ ├── lib/ # Shared library code
|
||||
│ │ ├── index.ts # Library barrel export (currently empty)
|
||||
│ │ └── assets/
|
||||
│ │ └── favicon.svg # Favicon (Svelte logo placeholder)
|
||||
│ └── routes/ # SvelteKit file-based routing
|
||||
│ ├── +layout.svelte # Root layout (wraps all pages)
|
||||
│ └── +page.svelte # Home page (index route /)
|
||||
├── static/ # Static assets (served as-is)
|
||||
│ └── robots.txt # Search engine crawl rules
|
||||
├── BYTEMALTE.md # Design system specification
|
||||
├── ARCHITECTURE.md # This file
|
||||
├── AGENTS.md # AI agent handoff documentation
|
||||
├── package.json # Project manifest and scripts
|
||||
├── pnpm-lock.yaml # Lockfile
|
||||
├── pnpm-workspace.yaml # pnpm workspace config
|
||||
├── svelte.config.js # SvelteKit configuration
|
||||
├── tsconfig.json # TypeScript configuration
|
||||
├── vite.config.ts # Vite configuration
|
||||
└── .npmrc # pnpm settings (engine-strict)
|
||||
```
|
||||
|
||||
## Routing
|
||||
|
||||
SvelteKit uses file-based routing. This project has a single route:
|
||||
|
||||
| File | Route | Purpose |
|
||||
|------|-------|---------|
|
||||
| `src/routes/+layout.svelte` | All pages | Global shell: header, nav, footer |
|
||||
| `src/routes/+page.svelte` | `/` | Home page content |
|
||||
|
||||
The `+layout.svelte` file wraps `+page.svelte` using Svelte 5's `{@render children()}` pattern.
|
||||
|
||||
## Component Architecture
|
||||
|
||||
### `+layout.svelte` — Root Layout
|
||||
|
||||
Responsibilities:
|
||||
- **Global CSS reset** — `box-sizing: border-box`, margin/padding zero
|
||||
- **Global styles** — Body background (`#0F172A`), font family (Inter), link colors
|
||||
- **Sticky header** — Glassmorphism effect (`backdrop-filter: blur(12px)`)
|
||||
- **Navigation** — Smooth scroll anchors (`#about`, `#connect`, `#projects`)
|
||||
- **Footer** — Social links + copyright
|
||||
|
||||
Key patterns:
|
||||
- Uses `:global()` selectors for body-level styles
|
||||
- Children rendered via Svelte 5 `{@render children()}` slot syntax
|
||||
- Responsive breakpoint at `640px`
|
||||
|
||||
### `+page.svelte` — Home Page
|
||||
|
||||
Responsibilities:
|
||||
- All page content in a single component
|
||||
- Data-driven rendering via `connectLinks` and `projects` arrays
|
||||
- Interactive copy-to-clipboard for Nostr credentials
|
||||
|
||||
Structure (top to bottom):
|
||||
1. **Script block** — State (`$state`), functions, data arrays
|
||||
2. **Hero section** — Badge, heading, subtitle, CTA buttons, Nostr identity card
|
||||
3. **About section** — Three icon cards in CSS Grid
|
||||
4. **Connect section** — Social link cards with SVG icons
|
||||
5. **Projects section** — Project cards with tags
|
||||
6. **Style block** — All scoped CSS
|
||||
|
||||
## State Management
|
||||
|
||||
The application uses minimal client-side state:
|
||||
|
||||
```typescript
|
||||
let copiedField = $state('');
|
||||
```
|
||||
|
||||
This single reactive variable tracks which Nostr credential was recently copied (for showing the checkmark feedback). There is no global state management — no stores, context, or external state libraries.
|
||||
|
||||
## Data Model
|
||||
|
||||
All content is defined as static arrays in `+page.svelte`:
|
||||
|
||||
```typescript
|
||||
connectLinks: Array<{
|
||||
title: string;
|
||||
description: string;
|
||||
icon: string; // Inline SVG markup
|
||||
href: string; // External URL
|
||||
cta: string; // Call-to-action label (unused in UI currently)
|
||||
}>
|
||||
|
||||
projects: Array<{
|
||||
title: string;
|
||||
description: string;
|
||||
tags: string[]; // Displayed as green badges
|
||||
link: string | null; // Optional external link
|
||||
}>
|
||||
```
|
||||
|
||||
To add or remove social links or projects, edit these arrays directly.
|
||||
|
||||
## Styling Strategy
|
||||
|
||||
- **Scoped CSS** — Each `.svelte` file has a `<style>` block with component-scoped rules
|
||||
- **No CSS framework** — All styles are hand-written vanilla CSS
|
||||
- **No CSS variables** — Colors are hardcoded hex values (per BYTEMALTE.md spec)
|
||||
- **Responsive design** — `@media (max-width: 768px)` breakpoints in `+page.svelte`, `640px` in `+layout.svelte`
|
||||
- **CSS Grid** — Used for all card layouts (`auto-fit`, `minmax`)
|
||||
- **Transitions** — CSS `transition` for hover effects on cards, buttons, links
|
||||
|
||||
## Build Pipeline
|
||||
|
||||
```
|
||||
pnpm dev → Vite dev server (HMR)
|
||||
pnpm check → svelte-kit sync → svelte-check (TypeScript)
|
||||
pnpm build → Vite build → SvelteKit SSR + client → adapter-auto
|
||||
pnpm preview → Preview production build locally
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
All dependencies are devDependencies (no runtime deps):
|
||||
|
||||
| Package | Purpose |
|
||||
|---------|---------|
|
||||
| `@sveltejs/adapter-auto` | Deployment adapter |
|
||||
| `@sveltejs/kit` | SvelteKit framework |
|
||||
| `@sveltejs/vite-plugin-svelte` | Vite-Svelte integration |
|
||||
| `svelte` | Svelte 5 compiler |
|
||||
| `svelte-check` | TypeScript checking for Svelte |
|
||||
| `typescript` | TypeScript compiler |
|
||||
| `vite` | Build tool and dev server |
|
||||
|
||||
## External Services
|
||||
|
||||
None. The site is fully static with no API calls, no analytics, no third-party scripts.
|
||||
|
||||
## SEO & Meta
|
||||
|
||||
- `<title>` set in `+layout.svelte` via `<svelte:head>`
|
||||
- `<meta name="description">` set in `+layout.svelte`
|
||||
- `robots.txt` allows all crawlers
|
||||
- No sitemap (single page, not needed)
|
||||
|
||||
## Accessibility
|
||||
|
||||
- Semantic HTML (`<header>`, `<main>`, `<footer>`, `<section>`, `<nav>`)
|
||||
- `aria-label` on icon-only buttons and links
|
||||
- All colors meet WCAG AA contrast ratios (see BYTEMALTE.md)
|
||||
- `rel="noopener noreferrer"` on all external links with `target="_blank"`
|
||||
59
BYTEMALTE.md
Normal file
59
BYTEMALTE.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# 🎨 BYTEMALTE Design System v1.1
|
||||
|
||||
Dieses Dokument definiert die visuelle Identität für alle Projekte von **ByteMalte**. Konsistenz vor Komplexität.
|
||||
|
||||
---
|
||||
|
||||
## 🌈 Farbpalette (Hex)
|
||||
|
||||
| Rolle | Hex-Code | Kontrast (auf `#0F172A`) | Einsatzbereich |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Primary** | `#8888FF` | 5.7:1 | Buttons, Links, Brand-Elemente |
|
||||
| **Secondary** | `#3DDC84` | 7.0:1 | Success-Meldungen, Akzente, Tags |
|
||||
| **Background** | `#0F172A` | — | Haupt-Hintergrund (Dark Mode bevorzugt) |
|
||||
| **Surface** | `#1E293B` | — | Karten, Sektionen, Modals |
|
||||
| **Text (High)** | `#F8FAFC` | 15.4:1 | Überschriften, Fließtext |
|
||||
| **Text (Muted)** | `#B0BDD0` | 7.2:1 | Beschreibungen, Footer, sekundärer Text |
|
||||
| **Accent/Error** | `#EF4444` | 4.5:1 | Fehler, Löschen-Buttons |
|
||||
|
||||
> Alle Farben erfüllen WCAG AA (mindestens 4.5:1 für normalen Text, 3:1 für großen Text).
|
||||
|
||||
---
|
||||
|
||||
## 📐 Layout & Abrundungen (Borders)
|
||||
|
||||
Wir nutzen ein weiches, modernes Design mit großzügigen Radien.
|
||||
|
||||
* **Buttons:** `8px` (Medium Round)
|
||||
* **Cards / Container:** `16px` (Large Round)
|
||||
* **Inputs / Formulare:** `8px`
|
||||
* **Profilbilder:** `50%` (Circle)
|
||||
|
||||
---
|
||||
|
||||
## 🖋️ Typografie
|
||||
|
||||
* **Font Family:** `Inter, system-ui, sans-serif` (Clean & Programmierer-Vibe)
|
||||
* **Headline Scale:**
|
||||
* **h1:** `2.5rem` | Bold (700)
|
||||
* **h2:** `1.8rem` | Semi-Bold (600)
|
||||
* **h3:** `1.2rem` | Medium (500)
|
||||
* **Body:** `1rem` | Regular (400) | Line-height: `1.6`
|
||||
|
||||
---
|
||||
|
||||
## ⚡ UI-Komponenten Spezifikationen
|
||||
|
||||
### Buttons
|
||||
* **Default:** Primary Background, White Text, keine Border.
|
||||
* **Hover:** Helligkeit +10%, leichter Box-Shadow (`0 4px 6px -1px rgb(0 0 0 / 0.1)`).
|
||||
* **Active:** Skalierung auf `0.98` (Click-Effekt).
|
||||
|
||||
### Karten (Cards)
|
||||
* **Background:** `Surface` (`#1E293B`)
|
||||
* **Border:** `1px solid #334155`
|
||||
* **Padding:** `24px`
|
||||
|
||||
---
|
||||
|
||||
> **Pro-Tipp für die KI:** Kopiere dieses File in den Prompt und sage: "Erstelle die UI basierend auf dem BYTEMALTE Design System."
|
||||
115
README.md
115
README.md
@@ -1,42 +1,107 @@
|
||||
# sv
|
||||
# malxte.de
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
|
||||
Personal about page for **Malxte** (ByteMalte) — a Rust developer, Nostr enthusiast, and content creator. Live at [malxte.de](https://malxte.de).
|
||||
|
||||
## Creating a project
|
||||
Built with [SvelteKit](https://svelte.dev/kit) and following the [BYTEMALTE Design System](./BYTEMALTE.md).
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
## Tech Stack
|
||||
|
||||
```sh
|
||||
# create a new project
|
||||
npx sv create my-app
|
||||
| Layer | Technology |
|
||||
|-------|-----------|
|
||||
| Framework | SvelteKit 2 / Svelte 5 |
|
||||
| Language | TypeScript |
|
||||
| Build Tool | Vite 7 |
|
||||
| Package Manager | pnpm |
|
||||
| Styling | Scoped CSS (component-level) |
|
||||
| Font | Inter (Google Fonts) |
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js 18+
|
||||
- pnpm (enforced via `engine-strict`)
|
||||
|
||||
### Install dependencies
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
To recreate this project with the same configuration:
|
||||
### Development server
|
||||
|
||||
```sh
|
||||
# recreate this project
|
||||
pnpm dlx sv create --template minimal --types ts --install pnpm malxte_de
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Developing
|
||||
Opens at [http://localhost:5173](http://localhost:5173).
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
### Type checking
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```bash
|
||||
pnpm check
|
||||
```
|
||||
|
||||
## Building
|
||||
### Production build
|
||||
|
||||
To create a production version of your app:
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
Output goes to `.svelte-kit/` (adapter-dependent for deployment).
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
|
||||
### Preview production build
|
||||
|
||||
```bash
|
||||
pnpm preview
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── app.html # HTML shell (loads Inter font)
|
||||
├── app.d.ts # SvelteKit type declarations
|
||||
├── lib/
|
||||
│ ├── index.ts # Library entry point
|
||||
│ └── assets/
|
||||
│ └── favicon.svg # Site favicon
|
||||
└── routes/
|
||||
├── +layout.svelte # Global layout (header, nav, footer)
|
||||
└── +page.svelte # Home page (hero, about, connect, projects)
|
||||
static/
|
||||
└── robots.txt # Crawl permissions
|
||||
```
|
||||
|
||||
## Sections
|
||||
|
||||
The single-page site contains four sections:
|
||||
|
||||
1. **Hero** — Name, tagline, CTA buttons, and Nostr identity card (NIP-05 + npub with copy-to-clipboard)
|
||||
2. **About Me** — Three cards covering Rust development, community building, and Nostr advocacy
|
||||
3. **Connect** — Links to ByteMalte.de, YouTube, X/Twitter, Gitea, and Reddit
|
||||
4. **Projects** — Showcases example projects (ByteMalte.de, Maltemedia)
|
||||
|
||||
## Design
|
||||
|
||||
All colors, typography, and component specs follow the [BYTEMALTE Design System v1.1](./BYTEMALTE.md). Key tokens:
|
||||
|
||||
- **Primary**: `#8888FF`
|
||||
- **Secondary**: `#3DDC84`
|
||||
- **Background**: `#0F172A`
|
||||
- **Surface**: `#1E293B`
|
||||
|
||||
All colors meet WCAG AA contrast requirements (4.5:1 minimum for normal text).
|
||||
|
||||
## Deployment
|
||||
|
||||
Uses `@sveltejs/adapter-auto` which auto-detects the deployment target. For specific platforms:
|
||||
|
||||
- **Vercel**: Works out of the box
|
||||
- **Netlify**: Works out of the box
|
||||
- **Cloudflare Pages**: Works out of the box
|
||||
- **Node.js**: Switch to `@sveltejs/adapter-node`
|
||||
|
||||
## License
|
||||
|
||||
Private — All rights reserved.
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
|
||||
<svelte:head>
|
||||
<link rel="icon" href={favicon} />
|
||||
<title>Developer | Creator | Tech Enthusiast</title>
|
||||
<title>Malxte | Developer & Creator</title>
|
||||
<meta name="description" content="Rust programmer, Nostr enthusiast, and creator. Discover my projects and connect with me." />
|
||||
</svelte:head>
|
||||
|
||||
<style>
|
||||
@@ -16,69 +17,169 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:global(html) {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
:global(body) {
|
||||
background-color: #0f172a;
|
||||
color: #e2e8f0;
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
color: #f8fafc;
|
||||
font-family: 'Inter', system-ui, sans-serif;
|
||||
line-height: 1.6;
|
||||
min-height: 100vh;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
:global(a) {
|
||||
color: #60a5fa;
|
||||
color: #8888ff;
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
:global(a:hover) {
|
||||
color: #93c5fd;
|
||||
color: #a0a0ff;
|
||||
}
|
||||
|
||||
:global(::selection) {
|
||||
background: #8888ff;
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.page-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 0 1.5rem;
|
||||
padding: 0 2rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 2rem 0;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #1e293b;
|
||||
margin-bottom: 3rem;
|
||||
padding: 1.5rem 0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
background: rgba(15, 23, 42, 0.85);
|
||||
backdrop-filter: blur(12px);
|
||||
border-bottom: 1px solid rgba(51, 65, 85, 0.5);
|
||||
}
|
||||
|
||||
header .container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 2.5rem;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
background: linear-gradient(135deg, #60a5fa, #3b82f6);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
color: #f8fafc;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
color: #94a3b8;
|
||||
font-size: 1.1rem;
|
||||
margin-top: 0.5rem;
|
||||
.logo span {
|
||||
color: #8888ff;
|
||||
}
|
||||
|
||||
nav {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav a {
|
||||
color: #b0bdd0;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
nav a:hover {
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
nav a::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -4px;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 2px;
|
||||
background: #8888ff;
|
||||
border-radius: 1px;
|
||||
transition: width 0.2s ease;
|
||||
}
|
||||
|
||||
nav a:hover::after {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
main {
|
||||
min-height: 70vh;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
footer {
|
||||
text-align: center;
|
||||
padding: 2rem 0;
|
||||
color: #94a3b8;
|
||||
padding: 3rem 0;
|
||||
color: #b0bdd0;
|
||||
border-top: 1px solid #1e293b;
|
||||
margin-top: 4rem;
|
||||
font-size: 0.9rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
footer .footer-links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
footer .footer-links a {
|
||||
color: #b0bdd0;
|
||||
font-size: 0.875rem;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
footer .footer-links a:hover {
|
||||
color: #8888ff;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
nav {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
nav a {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
footer .footer-links {
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<div class="page-wrapper">
|
||||
<header>
|
||||
<div class="tagline">Developer | Creator | Tech Enthusiast</div>
|
||||
<div class="container">
|
||||
<a href="/" class="logo"><span>byte</span>malte</a>
|
||||
<nav>
|
||||
<a href="#about">About</a>
|
||||
<a href="#connect">Connect</a>
|
||||
<a href="#projects">Projects</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
@@ -86,6 +187,14 @@
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<p>© {new Date().getFullYear()} Malxte. Built with Svelte 5 & Nostr ❤️</p>
|
||||
<div class="container">
|
||||
<div class="footer-links">
|
||||
<a href="https://github.com/bytemalte" target="_blank" rel="noopener noreferrer">GitHub</a>
|
||||
<a href="https://x.com/@malxte" target="_blank" rel="noopener noreferrer">X</a>
|
||||
<a href="https://youtube.com/@bytemalte" target="_blank" rel="noopener noreferrer">YouTube</a>
|
||||
<a href="https://bytemalte.de" target="_blank" rel="noopener noreferrer">ByteMalte.de</a>
|
||||
</div>
|
||||
<p>© {new Date().getFullYear()} Malxte. Built with Svelte 5 & Nostr</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -1,252 +1,686 @@
|
||||
<script lang="ts">
|
||||
let copiedField = $state('');
|
||||
|
||||
function copyToClipboard(text: string, field: string) {
|
||||
navigator.clipboard.writeText(text);
|
||||
copiedField = field;
|
||||
setTimeout(() => {
|
||||
if (copiedField === field) copiedField = '';
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
const connectLinks = [
|
||||
{
|
||||
title: 'ByteMalte.de',
|
||||
description: 'Community, Tutorials & Blog',
|
||||
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg>`,
|
||||
href: 'https://bytemalte.de',
|
||||
cta: 'Visit'
|
||||
},
|
||||
{
|
||||
title: 'YouTube',
|
||||
description: 'Tutorials & Dev Content',
|
||||
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22.54 6.42a2.78 2.78 0 0 0-1.94-2C18.88 4 12 4 12 4s-6.88 0-8.6.46a2.78 2.78 0 0 0-1.94 2A29 29 0 0 0 1 11.75a29 29 0 0 0 .46 5.33A2.78 2.78 0 0 0 3.4 19.1c1.72.46 8.6.46 8.6.46s6.88 0 8.6-.46a2.78 2.78 0 0 0 1.94-2 29 29 0 0 0 .46-5.25 29 29 0 0 0-.46-5.33z"/><polygon points="9.75 15.02 15.5 11.75 9.75 8.48 9.75 15.02"/></svg>`,
|
||||
href: 'https://youtube.com/@bytemalte',
|
||||
cta: 'Watch'
|
||||
},
|
||||
{
|
||||
title: 'X (Twitter)',
|
||||
description: 'Thoughts & Updates',
|
||||
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4l11.733 16h4.267l-11.733 -16z"/><path d="M4 20l6.768 -6.768m2.46 -2.46l6.772 -6.772"/></svg>`,
|
||||
href: 'https://x.com/@malxte',
|
||||
cta: 'Follow'
|
||||
},
|
||||
{
|
||||
title: 'Gitea',
|
||||
description: 'Open Source Code',
|
||||
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="18" cy="18" r="3"/><circle cx="6" cy="6" r="3"/><path d="M6 21V9a9 9 0 0 0 9 9"/></svg>`,
|
||||
href: 'https://gitea.malxte.de',
|
||||
cta: 'Browse'
|
||||
},
|
||||
{
|
||||
title: 'Reddit',
|
||||
description: 'Community & Discussion',
|
||||
icon: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M16 12a4 4 0 0 0-8 0"/><circle cx="9" cy="9" r="0.5" fill="currentColor"/><circle cx="15" cy="9" r="0.5" fill="currentColor"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/></svg>`,
|
||||
href: 'https://www.reddit.com/user/Bytemalte/',
|
||||
cta: 'Join'
|
||||
}
|
||||
];
|
||||
|
||||
const projects = [
|
||||
{
|
||||
title: 'ByteMalte.de',
|
||||
description: 'A community hub for developers — sharing insights, tutorials, and building connections in the dev space.',
|
||||
tags: ['Community', 'Web'],
|
||||
link: 'https://bytemalte.de'
|
||||
},
|
||||
{
|
||||
title: 'Maltemedia',
|
||||
description: 'A privacy-first social media platform. Rust backend, Svelte frontend. User control at its core.',
|
||||
tags: ['Rust', 'Svelte', 'Social'],
|
||||
link: null
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<!-- Hero Section -->
|
||||
<section class="hero">
|
||||
<div class="container">
|
||||
<div class="hero-badge">Developer · Creator · Tech Enthusiast</div>
|
||||
<h1>Hi, I'm <span class="highlight">Malxte</span></h1>
|
||||
<p class="hero-subtitle">
|
||||
A young, highly motivated <strong>Rust</strong> programmer and <strong>Nostr</strong> enthusiast.
|
||||
I share my projects, tech news, and tips with the community.
|
||||
</p>
|
||||
<div class="hero-actions">
|
||||
<a href="#connect" class="btn btn-primary">Get in Touch</a>
|
||||
<a href="#projects" class="btn btn-secondary">View Projects</a>
|
||||
</div>
|
||||
|
||||
<div class="nostr-identity">
|
||||
<div class="nostr-badge">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
|
||||
<span>Nostr</span>
|
||||
</div>
|
||||
<div class="nostr-details">
|
||||
<div class="nostr-row">
|
||||
<span class="nostr-label">NIP-05</span>
|
||||
<div class="nostr-value-wrap">
|
||||
<code class="nostr-value">_@bytemalte.de</code>
|
||||
<button
|
||||
class="copy-btn"
|
||||
onclick={() => copyToClipboard('_@bytemalte.de', 'nip05')}
|
||||
aria-label="Copy NIP-05"
|
||||
>
|
||||
{#if copiedField === 'nip05'}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
{:else}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nostr-row">
|
||||
<span class="nostr-label">npub</span>
|
||||
<div class="nostr-value-wrap">
|
||||
<code class="nostr-value nostr-npub">npub1guff8dkdz7k47zh0mx26y0mmx5l6np57jjkvmhnyrak0n50r5hxqjdnsra</code>
|
||||
<button
|
||||
class="copy-btn"
|
||||
onclick={() => copyToClipboard('npub1guff8dkdz7k47zh0mx26y0mmx5l6np57jjkvmhnyrak0n50r5hxqjdnsra', 'npub')}
|
||||
aria-label="Copy npub"
|
||||
>
|
||||
{#if copiedField === 'npub'}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
|
||||
{:else}
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- About Section -->
|
||||
<section id="about" class="section">
|
||||
<div class="container">
|
||||
<h2 class="section-title">About Me</h2>
|
||||
<div class="about-grid">
|
||||
<div class="about-card">
|
||||
<div class="about-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
|
||||
</div>
|
||||
<h3>Rust Developer</h3>
|
||||
<p>Passionate about building fast, safe, and reliable systems. Rust is my language of choice for performance-critical applications.</p>
|
||||
</div>
|
||||
<div class="about-card">
|
||||
<div class="about-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
|
||||
</div>
|
||||
<h3>Community Builder</h3>
|
||||
<p>I believe in open collaboration and sharing knowledge. Building communities where developers can learn and grow together.</p>
|
||||
</div>
|
||||
<div class="about-card">
|
||||
<div class="about-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
|
||||
</div>
|
||||
<h3>Nostr Advocate</h3>
|
||||
<p>Firm believer in decentralized communication. Nostr is the future of censorship-resistant social networking.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Connect Section -->
|
||||
<section id="connect" class="section section-alt">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Connect</h2>
|
||||
<p class="section-description">Find me across the web — let's build something together.</p>
|
||||
<div class="connect-grid">
|
||||
{#each connectLinks as link}
|
||||
<a
|
||||
href={link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="connect-card"
|
||||
>
|
||||
<div class="connect-icon">
|
||||
{@html link.icon}
|
||||
</div>
|
||||
<div class="connect-info">
|
||||
<h3>{link.title}</h3>
|
||||
<p>{link.description}</p>
|
||||
</div>
|
||||
<div class="connect-arrow">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Projects Section -->
|
||||
<section id="projects" class="section">
|
||||
<div class="container">
|
||||
<h2 class="section-title">Projects</h2>
|
||||
<p class="section-description">
|
||||
Things I'm building and working on. All my projects are available at
|
||||
<a href="https://bytemalte.de" target="_blank" rel="noopener noreferrer">bytemalte.de</a>
|
||||
— the following are just examples.
|
||||
</p>
|
||||
<div class="projects-grid">
|
||||
{#each projects as project}
|
||||
<div class="project-card">
|
||||
<div class="project-header">
|
||||
<h3>{project.title}</h3>
|
||||
{#if project.link}
|
||||
<a href={project.link} target="_blank" rel="noopener noreferrer" class="project-link" aria-label="Open {project.title}">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
<p>{project.description}</p>
|
||||
<div class="project-tags">
|
||||
{#each project.tags as tag}
|
||||
<span class="tag">{tag}</span>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
/* Hero */
|
||||
.hero {
|
||||
padding: 6rem 0 5rem;
|
||||
text-align: center;
|
||||
padding: 4rem 0;
|
||||
margin-bottom: 3rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hero::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -200px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
background: radial-gradient(circle, rgba(136, 136, 255, 0.12) 0%, transparent 70%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.hero-badge {
|
||||
display: inline-block;
|
||||
padding: 0.5rem 1.25rem;
|
||||
background: rgba(136, 136, 255, 0.1);
|
||||
border: 1px solid rgba(136, 136, 255, 0.25);
|
||||
border-radius: 999px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
color: #b0bdd0;
|
||||
letter-spacing: 0.03em;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 3.5rem;
|
||||
font-weight: 800;
|
||||
background: linear-gradient(135deg, #60a5fa, #3b82f6);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 700;
|
||||
color: #f8fafc;
|
||||
line-height: 1.15;
|
||||
margin-bottom: 1.5rem;
|
||||
letter-spacing: -0.03em;
|
||||
}
|
||||
|
||||
.hero .subtitle {
|
||||
font-size: 1.5rem;
|
||||
color: #94a3b8;
|
||||
max-width: 600px;
|
||||
margin: 0 auto 2rem;
|
||||
.highlight {
|
||||
color: #8888ff;
|
||||
}
|
||||
|
||||
.hero-subtitle {
|
||||
font-size: 1.2rem;
|
||||
color: #b0bdd0;
|
||||
max-width: 560px;
|
||||
margin: 0 auto 2.5rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.hero-subtitle strong {
|
||||
color: #f8fafc;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hero-actions {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.nostr-identity {
|
||||
margin-top: 3rem;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.5rem 2rem;
|
||||
background: rgba(30, 41, 59, 0.7);
|
||||
border: 1px solid #334155;
|
||||
border-radius: 16px;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.nostr-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.4rem 1rem;
|
||||
background: rgba(136, 136, 255, 0.1);
|
||||
border: 1px solid rgba(136, 136, 255, 0.25);
|
||||
border-radius: 999px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: #8888ff;
|
||||
}
|
||||
|
||||
.nostr-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nostr-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.nostr-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: #b0bdd0;
|
||||
min-width: 50px;
|
||||
}
|
||||
|
||||
.nostr-value-wrap {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.nostr-value {
|
||||
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
||||
font-size: 0.85rem;
|
||||
color: #f8fafc;
|
||||
background: rgba(15, 23, 42, 0.6);
|
||||
padding: 0.35rem 0.75rem;
|
||||
padding-right: 2.25rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #334155;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
background: rgba(136, 136, 255, 0.15);
|
||||
color: #b0bdd0;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease;
|
||||
}
|
||||
|
||||
.nostr-value-wrap:hover .copy-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.copy-btn:hover {
|
||||
background: rgba(136, 136, 255, 0.3);
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.nostr-npub {
|
||||
font-size: 0.75rem;
|
||||
color: #b0bdd0;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.8rem 1.75rem;
|
||||
border-radius: 8px;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #8888ff;
|
||||
color: #f8fafc;
|
||||
box-shadow: 0 1px 3px rgba(136, 136, 255, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #9a9aff;
|
||||
box-shadow: 0 4px 12px rgba(136, 136, 255, 0.35);
|
||||
transform: translateY(-1px);
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: rgba(136, 136, 255, 0.08);
|
||||
color: #b0bdd0;
|
||||
border: 1px solid #334155;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: rgba(136, 136, 255, 0.15);
|
||||
border-color: #8888ff;
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
/* Sections */
|
||||
.section {
|
||||
margin-bottom: 4rem;
|
||||
padding: 5rem 0;
|
||||
}
|
||||
|
||||
.section-alt {
|
||||
background: #1e293b;
|
||||
border-top: 1px solid #334155;
|
||||
border-bottom: 1px solid #334155;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 2rem;
|
||||
font-weight: 700;
|
||||
color: #f8fafc;
|
||||
margin-bottom: 1.5rem;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-bottom: 0.75rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.section-title::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -8px;
|
||||
left: 0;
|
||||
width: 60px;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, #60a5fa, #3b82f6);
|
||||
border-radius: 2px;
|
||||
.section-description {
|
||||
color: #b0bdd0;
|
||||
font-size: 1.05rem;
|
||||
margin-bottom: 2.5rem;
|
||||
}
|
||||
|
||||
.about-content {
|
||||
background: #1e293b;
|
||||
border-radius: 12px;
|
||||
padding: 2.5rem;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.about-text {
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.8;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
|
||||
.about-text strong {
|
||||
color: #60a5fa;
|
||||
}
|
||||
|
||||
.connect-grid {
|
||||
/* About Cards */
|
||||
.about-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.connect-card {
|
||||
.about-card {
|
||||
background: #1e293b;
|
||||
border-radius: 12px;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
border: 1px solid #334155;
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
|
||||
}
|
||||
|
||||
.about-card:hover {
|
||||
transform: translateY(-4px);
|
||||
border-color: rgba(136, 136, 255, 0.4);
|
||||
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.about-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
border-radius: 12px;
|
||||
background: rgba(136, 136, 255, 0.1);
|
||||
color: #8888ff;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.about-card h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
color: #f8fafc;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.about-card p {
|
||||
color: #b0bdd0;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
/* Connect Grid */
|
||||
.connect-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.connect-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 1.25rem 1.5rem;
|
||||
background: #0f172a;
|
||||
border: 1px solid #334155;
|
||||
border-radius: 16px;
|
||||
transition: all 0.2s ease;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.connect-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
|
||||
border-color: #60a5fa;
|
||||
border-color: #8888ff;
|
||||
background: rgba(136, 136, 255, 0.04);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
.connect-icon {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border-radius: 50%;
|
||||
background: rgba(96, 165, 250, 0.1);
|
||||
margin: 0 auto 1rem;
|
||||
justify-content: center;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
min-width: 44px;
|
||||
border-radius: 12px;
|
||||
background: rgba(136, 136, 255, 0.1);
|
||||
color: #8888ff;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 1.5rem;
|
||||
.connect-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.connect-info h3 {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #f8fafc;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-bottom: 0.15rem;
|
||||
}
|
||||
|
||||
.card-description {
|
||||
color: #94a3b8;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: 0.95rem;
|
||||
.connect-info p {
|
||||
font-size: 0.85rem;
|
||||
color: #b0bdd0;
|
||||
}
|
||||
|
||||
.card-link {
|
||||
display: inline-block;
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: linear-gradient(135deg, #60a5fa, #3b82f6);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.2s ease;
|
||||
.connect-arrow {
|
||||
color: #b0bdd0;
|
||||
transition: transform 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
|
||||
.card-link:hover {
|
||||
opacity: 0.9;
|
||||
.connect-card:hover .connect-arrow {
|
||||
transform: translateX(3px);
|
||||
color: #8888ff;
|
||||
}
|
||||
|
||||
/* Projects */
|
||||
.projects-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
margin-top: 2rem;
|
||||
grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.project-card {
|
||||
background: #1e293b;
|
||||
border-radius: 12px;
|
||||
padding: 2rem;
|
||||
border: 1px solid #334155;
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
|
||||
}
|
||||
|
||||
.project-title {
|
||||
font-size: 1.5rem;
|
||||
.project-card:hover {
|
||||
transform: translateY(-4px);
|
||||
border-color: rgba(136, 136, 255, 0.4);
|
||||
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.project-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.project-header h3 {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
color: #f8fafc;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.project-description {
|
||||
color: #cbd5e1;
|
||||
line-height: 1.7;
|
||||
.project-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 8px;
|
||||
background: rgba(136, 136, 255, 0.1);
|
||||
color: #8888ff;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.project-link:hover {
|
||||
background: rgba(136, 136, 255, 0.2);
|
||||
transform: translateY(-1px);
|
||||
color: #8888ff;
|
||||
}
|
||||
|
||||
.project-card p {
|
||||
color: #b0bdd0;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.65;
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.project-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.tag {
|
||||
display: inline-block;
|
||||
padding: 0.3rem 0.75rem;
|
||||
background: rgba(61, 220, 132, 0.08);
|
||||
border: 1px solid rgba(61, 220, 132, 0.2);
|
||||
border-radius: 8px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
color: #3ddc84;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.hero {
|
||||
padding: 4rem 0 3rem;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.hero .subtitle {
|
||||
font-size: 1.2rem;
|
||||
.hero-subtitle {
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.section {
|
||||
padding: 3.5rem 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.75rem;
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.about-content {
|
||||
padding: 1.5rem;
|
||||
.container {
|
||||
padding: 0 1.25rem;
|
||||
}
|
||||
|
||||
.connect-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.connect-grid,
|
||||
.projects-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.about-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="hero">
|
||||
<h1>Malxte</h1>
|
||||
<p class="subtitle">Rust 🦀 programmer & Nostr Lover ❤️</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2 class="section-title">About me</h2>
|
||||
<div class="about-content">
|
||||
<p class="about-text">
|
||||
Hi, I am a young highly motivated <strong>Rust 🦀 programmer</strong> and <strong>Nostr Lover ❤️</strong>.
|
||||
I like to share my Projects, Tech News and Tips.
|
||||
</p>
|
||||
<p class="about-text">
|
||||
When I'm not coding, I create content or work on my own projects, such as
|
||||
<strong>bytemalte.de</strong> a community website or my social media app <strong>maltemedia</strong>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2 class="section-title">Connect</h2>
|
||||
<div class="connect-grid">
|
||||
<div class="connect-card">
|
||||
<div class="card-icon">🌐</div>
|
||||
<h3 class="card-title">ByteMalte.de</h3>
|
||||
<p class="card-description">Meine Website</p>
|
||||
<a href="https://bytemalte.de" target="_blank" class="card-link">Visit</a>
|
||||
</div>
|
||||
<div class="connect-card">
|
||||
<div class="card-icon">▶️</div>
|
||||
<h3 class="card-title">YouTube</h3>
|
||||
<p class="card-description">Tutorials & Content</p>
|
||||
<a href="https://youtube.com/@bytemalte" target="_blank" class="card-link">Watch</a>
|
||||
</div>
|
||||
<div class="connect-card">
|
||||
<div class="card-icon">✖️</div>
|
||||
<h3 class="card-title">X (Twitter)</h3>
|
||||
<p class="card-description">Gedanken & Updates</p>
|
||||
<a href="https://x.com/@malxte" target="_blank" class="card-link">Follow</a>
|
||||
</div>
|
||||
<div class="connect-card">
|
||||
<div class="card-icon">💻</div>
|
||||
<h3 class="card-title">My Gitea</h3>
|
||||
<p class="card-description">Mein Code</p>
|
||||
<a href="https://gitea.malxte.de" target="_blank" class="card-link">Browse</a>
|
||||
</div>
|
||||
<div class="connect-card">
|
||||
<div class="card-icon">💬</div>
|
||||
<h3 class="card-title">Reddit</h3>
|
||||
<p class="card-description">Community Posts & Updates</p>
|
||||
<a href="https://www.reddit.com/user/Bytemalte/" target="_blank" class="card-link">Join</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2 class="section-title">Projects</h2>
|
||||
<div class="projects-grid">
|
||||
<div class="project-card">
|
||||
<h3 class="project-title">ByteMalte.de</h3>
|
||||
<p class="project-description">
|
||||
A community website where I share insights, tutorials, and connect with other developers.
|
||||
Built with modern web technologies and a focus on performance.
|
||||
</p>
|
||||
</div>
|
||||
<div class="project-card">
|
||||
<h3 class="project-title">Maltemedia</h3>
|
||||
<p class="project-description">
|
||||
A social media app that prioritizes privacy and user control. Currently in development
|
||||
with Rust backend and Svelte frontend.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user