imnya.ng/src/app/flake.nix/page.tsx

128 lines
No EOL
3.7 KiB
TypeScript

"use client";
import { useEffect, useRef, useCallback } from "react";
import hljs from "highlight.js/lib/core";
import nix from "highlight.js/lib/languages/nix";
import "highlight.js/styles/github-dark.css";
hljs.registerLanguage("nix", nix);
declare global {
interface Window {
showSaveFilePicker?: (options?: {
suggestedName?: string;
types?: Array<{
description?: string;
accept: Record<string, string[]>;
}>;
}) => Promise<FileSystemFileHandle>;
}
}
const code = `{
description = "My personal website";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
}
outputs = { self, nixpkgs }: {
let
system = "x86_64-linux";
pkgs = import nixpkgs { inherit system; };
in {
// install pakages
nix.settings = {
sandbox = false;
experimental-features = [ "flakes" ];
};
time.timeZone = "Asia/Seoul";
}
}`;
const customTheme = `
.hljs {
background: #191017 !important;
color: #fcf8f9 !important;
}
.hljs-attr { color: #f38ba8; }
.hljs-string { color: #a6e3a1; }
.hljs-number { color: #f9e2af; }
.hljs-literal { color: #89b4fa; }
.hljs-type { color: #f5c2e7; }
.hljs-title { color: #94e2d5; }
`;
export default function FlakeNix() {
const codeRef = useRef<HTMLElement>(null);
const downloadFile = useCallback(async () => {
if (window.showSaveFilePicker) {
try {
const handle = await window.showSaveFilePicker({
suggestedName: "flake.nix",
types: [
{
description: "Nix Files",
accept: { "text/plain": [".nix"] },
},
],
});
const writable = await handle.createWritable();
await writable.write(code);
await writable.close();
} catch (e) {
// 사용자가 취소한 경우
if ((e as Error).name !== "AbortError") {
console.error(e);
}
}
} else {
// fallback: showSaveFilePicker를 지원하지 않는 브라우저
const blob = new Blob([code], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "flake.nix";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
}, []);
useEffect(() => {
const style = document.createElement("style");
style.textContent = customTheme;
document.head.appendChild(style);
if (codeRef.current) {
hljs.highlightElement(codeRef.current);
}
const handleKeyDown = (e: KeyboardEvent) => {
if ((e.ctrlKey || e.metaKey) && e.key === "s") {
e.preventDefault();
downloadFile();
}
};
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [downloadFile]);
return (
<main className="flex h-screen items-center justify-center">
<div className="max-w-3xl w-full mx-auto px-6 rounded-2xl overflow-auto">
<pre>
<code ref={codeRef} className="language-nix">
{code}
</code>
</pre>
</div>
</main>
);
}