Something went wrong. Try again.
Monorepo for the nibling.run platform
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124/** The languages the key bar knows. Anything else gets the general set. */export type Language = "html" | "css" | "javascript" | "json" | "markdown" | "shell" | "text";
/** A key that types something: a symbol, a pair with the caret inside, or a short snippet. */export interface TypingKey { readonly label: string; /** The accessible name, when the label alone doesn't say it (pairs, snippets). */ readonly name?: string; readonly text: string; /** Where the caret lands inside `text`; default after it. */ readonly caret?: number;}
const EXTENSIONS: Record<string, Language> = { html: "html", htm: "html", svg: "html", xml: "html", vue: "html", svelte: "html", astro: "html", css: "css", scss: "css", less: "css", js: "javascript", mjs: "javascript", cjs: "javascript", jsx: "javascript", ts: "javascript", mts: "javascript", cts: "javascript", tsx: "javascript", json: "json", jsonc: "json", webmanifest: "json", md: "markdown", markdown: "markdown", mdx: "markdown", sh: "shell", bash: "shell", zsh: "shell",};
/** The language of a file, from its extension. */export function languageOf(path: string): Language { const name = path.slice(path.lastIndexOf("/") + 1); const dot = name.lastIndexOf("."); return (dot > 0 && EXTENSIONS[name.slice(dot + 1).toLowerCase()]) || "text";}
export const LANGUAGE_NAMES: Record<Language, string> = { html: "HTML", css: "CSS", javascript: "JavaScript", json: "JSON", markdown: "Markdown", shell: "Shell", text: "Coding",};
const pair = (open: string, close: string, name: string): TypingKey => ({ label: `${open} ${close}`, name, text: open + close, caret: open.length });const chars = (list: string): TypingKey[] => [...list].map((char) => ({ label: char, text: char }));
/** * The typing keys for each language, most reached-for first, since the row scrolls and the start * is what a thumb finds. These are the keys a phone keyboard buries behind its symbol pages. */const KEYS: Record<Language, readonly TypingKey[]> = { html: [ pair("<", ">", "Angle brackets"), ...chars("/="), pair('"', '"', "Double quotes"), { label: "<!--", name: "Comment", text: "<!-- -->", caret: 5 }, ...chars("!-&;#.:'"), pair("{", "}", "Braces"), pair("(", ")", "Parentheses"), ], css: [ pair("{", "}", "Braces"), ...chars(":;#.-"), pair("(", ")", "Parentheses"), ...chars("%!,>*~+@"), pair('"', '"', "Double quotes"), { label: "/*", name: "Comment", text: "/* */", caret: 3 }, ], javascript: [ pair("(", ")", "Parentheses"), pair("{", "}", "Braces"), pair("[", "]", "Brackets"), { label: "=>", name: "Arrow", text: " => " }, ...chars(";:=.,"), pair('"', '"', "Double quotes"), pair("'", "'", "Single quotes"), pair("`", "`", "Backticks"), ...chars("!?&|<>+-*/$_"), { label: "//", name: "Comment", text: "// " }, ], json: [ pair("{", "}", "Braces"), pair("[", "]", "Brackets"), pair('"', '"', "Double quotes"), ...chars(":,-."), ], markdown: [ ...chars("#*_`"), pair("[", "]", "Brackets"), pair("(", ")", "Parentheses"), ...chars("->!|~"), { label: "```", name: "Code fence", text: "```\n\n```", caret: 4 }, ], shell: [...chars("|>&;$~/-.*<"), pair('"', '"', "Double quotes"), pair("'", "'", "Single quotes"), ...chars("`=")], text: [ pair("(", ")", "Parentheses"), pair("{", "}", "Braces"), pair("[", "]", "Brackets"), pair("<", ">", "Angle brackets"), ...chars("\"'`;:=/\\|&!?_-+*#$%"), ],};
export function typingKeys(language: Language): readonly TypingKey[] { return KEYS[language];}