feat: completely localize command palette actions, categories, and hooks
All checks were successful
Deploy Portfolio to VPS / deploy (push) Successful in 28s
All checks were successful
Deploy Portfolio to VPS / deploy (push) Successful in 28s
This commit is contained in:
parent
ad4d4b4387
commit
d52f1c088b
4 changed files with 60 additions and 22 deletions
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue