128 lines
No EOL
3.7 KiB
TypeScript
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>
|
|
);
|
|
} |