feat: completely localize command palette actions, categories, and hooks
All checks were successful
Deploy Portfolio to VPS / deploy (push) Successful in 28s

This commit is contained in:
Chneemann 2026-08-07 15:47:23 +02:00
parent ad4d4b4387
commit d52f1c088b
No known key found for this signature in database
4 changed files with 60 additions and 22 deletions

View file

@ -1,20 +1,23 @@
"use client";
import { useState, useEffect, useRef } from "react";
import { useTranslations } from "next-intl";
import { getCommands } from "../lib/paletteCommands";
/**
* Interactive Cmd+K modal for quick navigation, actions, and social links
*/
export default function CommandPalette() {
const tCommands = useTranslations("Commands");
const [isOpen, setIsOpen] = useState(false);
const [search, setSearch] = useState("");
const [selectedIndex, setSelectedIndex] = useState(0);
const [copied, setCopied] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
// Load action definitions from lib helper
const commands = getCommands(copied, setCopied);
// Load action definitions from lib helper safely inside the component
const commands = getCommands(copied, setCopied, tCommands);
// Filter commands dynamically by search query or category
const filteredCommands = commands.filter(
@ -104,7 +107,7 @@ export default function CommandPalette() {
<input
ref={inputRef}
type="text"
placeholder="Type a command or action..."
placeholder={tCommands("searchPlaceholder")}
value={search}
onChange={(e) => {
setSearch(e.target.value);
@ -122,7 +125,7 @@ export default function CommandPalette() {
<div className="max-h-100 overflow-y-auto p-2 space-y-1">
{filteredCommands.length === 0 ? (
<p className="p-4 text-center text-xs font-mono text-slate-500">
No matching commands found.
{tCommands("noResults")}
</p>
) : (
filteredCommands.map((cmd, index) => {
@ -167,14 +170,14 @@ export default function CommandPalette() {
{/* Footer Hint */}
<div className="px-4 py-2.5 border-t border-slate-800/60 bg-slate-950/60 flex items-center justify-between text-[11px] font-mono text-slate-500">
<span>
Use{" "}
{tCommands("navHint1")}{" "}
<kbd className="text-slate-400 bg-slate-900 px-1 rounded border border-slate-800">
</kbd>{" "}
<kbd className="text-slate-400 bg-slate-900 px-1 rounded border border-slate-800">
</kbd>{" "}
to navigate
{tCommands("navHint2")}
</span>
<span>
<kbd className="text-slate-400 bg-slate-900 px-1 rounded border border-slate-800">

View file

@ -95,6 +95,23 @@
"timeMinutesAgo": "vor {minutes}m",
"timeHoursAgo": "vor {hours}h"
},
"Commands": {
"catQuickActions": "Schnellzugriff",
"catSocial": "Soziale Medien / Links",
"catSystem": "System & Info",
"copyEmail": "E-Mail kopieren (dev@andre-kempf.com)",
"emailCopied": "E-Mail kopiert!",
"downloadCV": "Lebenslauf herunterladen (PDF)",
"openTerminal": "Statistik-Terminal öffnen",
"viewForgejo": "Git-Profil (Self-Hosted) ansehen",
"viewGitHub": "GitHub-Profil (Legacy) ansehen",
"viewLinkedIn": "LinkedIn-Profil ansehen",
"viewSource": "Quellcode ansehen (Self-Hosted Git)",
"searchPlaceholder": "Befehl oder Aktion eingeben...",
"noResults": "Keine passenden Befehle gefunden.",
"navHint1": "Mit",
"navHint2": "navigieren"
},
"Imprint": {
"backHome": "Zurück zur Startseite",
"section1Title": "Angaben gemäß § 5 DDG",

View file

@ -96,6 +96,23 @@
"timeMinutesAgo": "{minutes}m ago",
"timeHoursAgo": "{hours}h ago"
},
"Commands": {
"catQuickActions": "Quick Actions",
"catSocial": "Social / Links",
"catSystem": "System & Info",
"copyEmail": "Copy Email (dev@andre-kempf.com)",
"emailCopied": "Email Copied!",
"downloadCV": "Download CV (PDF)",
"openTerminal": "Open Analytics Terminal",
"viewForgejo": "View Self-Hosted Git Profile",
"viewGitHub": "View GitHub (Legacy) Profile",
"viewLinkedIn": "View LinkedIn Profile",
"viewSource": "View Site Source Code (Self-Hosted Git)",
"searchPlaceholder": "Type a command or action...",
"noResults": "No matching commands found.",
"navHint1": "Use",
"navHint2": "to navigate"
},
"Imprint": {
"section1Title": "Information Pursuant to § 5 DDG",
"section1Sub": "Also responsible for content pursuant to § 18 Abs. 2 MStV.",

View file

@ -6,7 +6,7 @@ import { playSudoEasterEgg } from "./playSudoEasterEgg";
export type CommandItem = {
id: string;
label: string;
category: "Quick Actions" | "System & Info" | "Social / Links";
category: string;
icon?: string;
action: () => void;
};
@ -17,11 +17,12 @@ export type CommandItem = {
export const getCommands = (
copied: boolean,
setCopied: (value: boolean) => void,
tCommands: (key: string) => string,
): CommandItem[] => [
{
id: "copy-email",
label: copied ? "Email Copied!" : "Copy Email (dev@andre-kempf.com)",
category: "Quick Actions",
label: copied ? tCommands("emailCopied") : tCommands("copyEmail"),
category: tCommands("catQuickActions"),
icon: copied ? "✓" : "✉️",
action: () => {
navigator.clipboard.writeText("dev@andre-kempf.com");
@ -31,8 +32,8 @@ export const getCommands = (
},
{
id: "download-cv",
label: "Download CV (PDF)",
category: "Quick Actions",
label: tCommands("downloadCV"),
category: tCommands("catQuickActions"),
icon: "📄",
action: () => {
window.open(
@ -44,8 +45,8 @@ export const getCommands = (
},
{
id: "terminal",
label: "Open Analytics Terminal",
category: "Quick Actions",
label: tCommands("openTerminal"),
category: tCommands("catQuickActions"),
icon: "⚡",
action: () => {
window.dispatchEvent(new CustomEvent("open-analytics"));
@ -53,8 +54,8 @@ export const getCommands = (
},
{
id: "forgejo",
label: "View Self-Hosted Git Profile",
category: "Social / Links",
label: tCommands("viewForgejo"),
category: tCommands("catSocial"),
icon: "🔨",
action: () => {
window.open(
@ -66,8 +67,8 @@ export const getCommands = (
},
{
id: "github",
label: "View GitHub (Legacy) Profile",
category: "Social / Links",
label: tCommands("viewGitHub"),
category: tCommands("catSocial"),
icon: "🐙",
action: () => {
window.open(
@ -79,8 +80,8 @@ export const getCommands = (
},
{
id: "linkedin",
label: "View LinkedIn Profile",
category: "Social / Links",
label: tCommands("viewLinkedIn"),
category: tCommands("catSocial"),
icon: "💼",
action: () => {
window.open(
@ -92,8 +93,8 @@ export const getCommands = (
},
{
id: "source-code",
label: "View Site Source Code (Self-Hosted Git)",
category: "Social / Links",
label: tCommands("viewSource"),
category: tCommands("catSocial"),
icon: "💻",
action: () => {
window.open(
@ -106,7 +107,7 @@ export const getCommands = (
{
id: "sudo-egg",
label: "sudo rm -rf --no-preserve-root /",
category: "System & Info",
category: tCommands("catSystem"),
icon: "💀",
action: playSudoEasterEgg,
},