Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ function App() {
onLoadSample={() => handleLoadSample(false)}
onChangeName={(name) => name.length > 0 && setName(name)}
onChangeColor={() => setHue(generateHue())}
editor={editor}
/>
<ReadCodeConfirm
isOpen={readCodeConfirmOpen}
Expand Down
53 changes: 52 additions & 1 deletion src/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import {
Text,
useToast,
} from "@chakra-ui/react";
import { VscRepo } from "react-icons/vsc";
import { VscRepo, VscDesktopDownload } from "react-icons/vsc";

import type * as monaco from "monaco-editor";
import ConnectionStatus from "./ConnectionStatus";
import User from "./User";
import languages from "./languages.json";
import languages_extensions from "./languages_extensions.json";
import type { UserInfo } from "./rustpad";

export type SidebarProps = {
Expand All @@ -27,6 +29,7 @@ export type SidebarProps = {
language: string;
currentUser: UserInfo;
users: Record<number, UserInfo>;
editor?: monaco.editor.IStandaloneCodeEditor;
onDarkModeChange: () => void;
onLanguageChange: (language: string) => void;
onLoadSample: () => void;
Expand All @@ -46,6 +49,7 @@ function Sidebar({
onLoadSample,
onChangeName,
onChangeColor,
editor,
}: SidebarProps) {
const toast = useToast();

Expand Down Expand Up @@ -139,6 +143,22 @@ function Sidebar({
))}
</Stack>

<Button
size="sm"
colorScheme={darkMode ? "whiteAlpha" : "blackAlpha"}
borderColor={darkMode ? "purple.400" : "purple.600"}
color={darkMode ? "purple.400" : "purple.600"}
variant="outline"
leftIcon={<VscDesktopDownload/>}
mt={1}
onClick={() => {
if (!editor) return;
downloadEditorContent(editor);
}}
>
Download content
</Button>

<Heading mt={4} mb={1.5} size="sm">
About
</Heading>
Expand Down Expand Up @@ -179,4 +199,35 @@ function Sidebar({
);
}

// Save the current content from the Monaco editor to a local file.
function downloadEditorContent(editor: monaco.editor.IStandaloneCodeEditor | null) {
if (!editor) return;
const model = editor.getModel();
if (!model) return;

const content = model.getValue();
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
const url = URL.createObjectURL(blob);

const a = document.createElement("a");
a.href = url;

const language = model.getLanguageId();
const ext = getExtensionFromLanguage(language);
const filename = `rustpad.${ext}`;

a.download = filename;

a.click();

URL.revokeObjectURL(url);
}

const LANGUAGE_EXTENSIONS: Record<string, string> = languages_extensions;

// Determine the file extension for the given language, using "txt" as a fallback.
function getExtensionFromLanguage(language: string): string {
return LANGUAGE_EXTENSIONS[language] ?? "txt";
}

export default Sidebar;
82 changes: 82 additions & 0 deletions src/languages_extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"abap": "abap",
"aes": "aes",
"apex": "apex",
"azcli": "azcli",
"bat": "bat",
"bicep": "bicep",
"c": "c",
"cameligo": "mligo",
"clojure": "clj",
"coffeescript": "coffee",
"cpp": "cpp",
"csharp": "cs",
"csp": "csp",
"css": "css",
"dart": "dart",
"dockerfile": "dockerfile",
"ecl": "ecl",
"elixir": "ex",
"flow9": "flow",
"fsharp": "fs",
"go": "go",
"graphql": "graphql",
"handlebars": "hbs",
"hcl": "hcl",
"html": "html",
"ini": "ini",
"java": "java",
"javascript": "js",
"json": "json",
"julia": "jl",
"kotlin": "kt",
"less": "less",
"lexon": "lexon",
"liquid": "liquid",
"lua": "lua",
"m3": "m3",
"markdown": "md",
"mips": "s",
"msdax": "dax",
"mysql": "sql",
"objective-c": "m",
"pascal": "pas",
"pascaligo": "ligo",
"perl": "pl",
"pgsql": "pgsql",
"php": "php",
"pla": "pla",
"plaintext": "txt",
"postiats": "ats",
"powerquery": "pq",
"powershell": "ps1",
"proto": "proto",
"pug": "pug",
"python": "py",
"qsharp": "qs",
"r": "r",
"razor": "cshtml",
"redis": "rdb",
"redshift": "sql",
"restructuredtext": "rst",
"ruby": "rb",
"rust": "rs",
"sb": "sb",
"scala": "scala",
"scheme": "scm",
"scss": "scss",
"shell": "sh",
"sol": "sol",
"sparql": "rq",
"sql": "sql",
"st": "st",
"swift": "swift",
"systemverilog": "sv",
"tcl": "tcl",
"twig": "twig",
"typescript": "ts",
"vb": "vb",
"verilog": "v",
"xml": "xml",
"yaml": "yaml"
}
Loading