Skip to content

Commit

Permalink
feat: add monaco editor (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
eryue0220 authored Jun 7, 2024
1 parent 7080083 commit c8a2d0b
Show file tree
Hide file tree
Showing 27 changed files with 640 additions and 364 deletions.
2 changes: 1 addition & 1 deletion components.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
"framework": "vite",
"aliases": {
"components": "src/ui",
"components": "src/",
"utils": "src/utils/index"
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"url": "git+https://github.com/oxc-project/playground.git"
},
"devDependencies": {
"@oxc/oxc_wasm": "link:../oxc/npm/oxc-wasm",
"@types/node": "^20.12.12",
"@vitejs/plugin-vue": "^5.0.4",
"autoprefixer": "^10.4.19",
Expand All @@ -31,8 +32,7 @@
"tailwindcss": "^3.4.3",
"ts-node": "^10.9.2",
"typescript": "^5.4.5",
"vite": "^5.2.11",
"@oxc/oxc_wasm": "link:../oxc/npm/oxc-wasm"
"vite": "^5.2.11"
},
"dependencies": {
"@radix-icons/vue": "^1.0.0",
Expand Down
484 changes: 240 additions & 244 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
<script setup lang="ts">
import Header from "./components/Header/Header.vue";
import Sidebar from "./components/Sidebar/Sidebar.vue";
import { useSyntaxOptionState } from "src/composable/useSyntaxOptions";
import Editor from "src/components/Editor/Editor.vue";
import Header from "src/components/Header/Header.vue";
import Sidebar from "src/components/Sidebar/Sidebar.vue";
const syntaxState = useSyntaxOptionState();
</script>

<template>
<Suspense>
<main class="flex w-screen h-screen bg-white dark:bg-[#1b1b1f]">
<Sidebar />
<div class="flex w-screen">
<Sidebar :syntaxState="syntaxState" />
<div class="flex flex-col w-screen">
<Header />
<div>
<!-- Todo: Editor Component -->
<div class="flex w-full h-full">
<Editor :syntaxState="syntaxState" />
</div>
</div>
</main>
Expand Down
21 changes: 21 additions & 0 deletions src/components/Editor/Code.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup lang="ts">
import { ref } from "vue";
import { useElementSize } from "@vueuse/core";
import MonacoEditor from "./Monaco.vue";
defineProps(["language"]);
const editorContainer = ref(null);
const { width, height } = useElementSize(editorContainer);
</script>

<template>
<div class="w-1/2 h-full py-2">
<MonacoEditor
ref="editorContainer"
:language="language"
:width="width"
:height="height"
/>
</div>
</template>
14 changes: 14 additions & 0 deletions src/components/Editor/Editor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script setup lang="ts">
import Code from "./Code.vue";
import Output from "./Output.vue";
defineProps(["syntaxState"]);
</script>

<template>
<Code :language="syntaxState.language" />
<div class="w-px h-full border-b bg-[#e2e2e3] dark:bg-[#2e2e32]" />
<div class="w-1/2 h-full">
<Output />
</div>
</template>
82 changes: 82 additions & 0 deletions src/components/Editor/Monaco.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<script lang="ts">
import {
type PropType,
defineComponent,
onBeforeUnmount,
onMounted,
ref,
} from "vue";
import { useDark } from "@vueuse/core";
import * as monaco from "monaco-editor";
import "src/composable/useEditorWorker";
export default defineComponent({
name: "MonacoEditor",
props: {
width: {
type: [String, Number],
default: "100%",
},
height: {
type: [String, Number],
default: "100%",
},
original: String,
value: String,
language: { type: String },
theme: { type: String },
options: {
type: Object as PropType<monaco.editor.IStandaloneEditorConstructionOptions>,
default: () => ({}),
},
},
emits: ["editorWillMount", "editorDidMount", "change", "update:modelValue"],
setup(props, { emit }) {
const container: any = ref(null);
let instance: monaco.editor.IStandaloneCodeEditor | any = null;
const isDark = useDark({
onChanged(isDark) {
if (!instance) return;
monaco.editor.setTheme(isDark ? "vs-dark" : "vs");
},
});
const initMonaco = () => {
const editorProps = {
minimap: { enabled: false },
fontSize: 14,
scrollBeyondLastLine: true,
fontFamily: `ui-monospace, Menlo, Monaco, "Cascadia Code", "Cascadia Mono", "Segoe UI Mono", "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro","Fira Mono", "Droid Sans Mono", "Courier New", monospace`,
locale: "en",
...props,
theme: props.theme || (isDark.value ? "vs-dark" : "vs"),
};
instance = monaco.editor.create(container.value, editorProps);
instance.onDidChangeModelContent(() => {
const value = instance.getValue();
emit("update:modelValue", value);
});
};
onMounted(() => {
initMonaco();
});
onBeforeUnmount(() => {
if (instance) {
instance.dispose();
}
});
return {
container,
};
},
});
</script>

<template>
<div class="w-full h-full" ref="container" />
</template>
37 changes: 37 additions & 0 deletions src/components/Editor/Output.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<script setup lang="ts">
import { Label } from "src/ui/label";
import { RadioGroup, RadioGroupItem } from "src/ui/radio-group";
const radios = [
{ value: "ast", label: "Ast" },
{ value: "codegen", label: "Codegen" },
{ value: "ir", label: "IR" },
{ value: "prettier", label: "Prettier" },
{ value: "format", label: "Format(Prettier)" },
{ value: "scope", label: "Scope" },
{ value: "symbol", label: "Symbol" },
];
</script>

<template>
<div
class="flex relative items-center px-2 py-3 before:content-[''] before:absolute before:bottom-0 before:left-0 before:w-full before:h-px before:bg-no-repeat before:bg-[#e2e2e3] dark:before:bg-[#2e2e32]"
>
<RadioGroup class="flex" default-value="ast">
<div v-for="radio in radios">
<RadioGroupItem
:id="radio.value"
:value="radio.value"
class="peer w-0 h-0 border-0"
style="clip: rect(0, 0, 0, 0)"
/>
<Label
:for="radio.value"
class="px-3 py-2 bg-white dark:bg-[#2e2e32] border-2 rounded-md text-sm hover:border-[#3451b2] dark:hover:border-[#a8b1ff] peer-data-[state=checked]:bg-[#3451b2] dark:peer-data-[state=checked]:bg-[#a8b1ff] peer-data-[state=checked]:border-[#3451b2] dark:peer-data-[state=checked]:border-[#a8b1ff] peer-data-[state=checked]:text-white"
>
{{ radio.label }}
</Label>
</div>
</RadioGroup>
</div>
</template>
2 changes: 1 addition & 1 deletion src/components/Header/Switch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const toggleDark = useToggle(isDark);
<SwitchThumb
:class="
cn(
'pointer-events-none block h-5 w-5 rounded-full bg-white dark:bg-black shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0',
'pointer-events-none block h-5 w-5 rounded-full bg-white dark:bg-[#1b1b1f] shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0',
)
"
/>
Expand Down
16 changes: 14 additions & 2 deletions src/components/Sidebar/Lint.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
<script setup lang="ts">
import Checkbox from "../ui/Checkbox.vue";
const props = defineProps(["syntaxState"]);
const emit = defineEmits(["update:syntaxState"]);
function checkedLint(checked: boolean) {
props.syntaxState.linted = checked;
}
</script>

<template>
<div class="pt-3">
<p class="text-lg text-[#3c3c43] dark:text-[#fffff5]/[.86]">Lint</p>
<Checkbox id="lint-enable" title="Lint Enabled" />
<p class="text-lg text-[#3c3c43] dark:text-[#fffff5]/[.86]">Lint Options</p>
<Checkbox
id="lint-enable"
title="Lint Enabled"
:checked="syntaxState.linted"
:onChange="checkedLint"
/>
</div>
</template>
7 changes: 5 additions & 2 deletions src/components/Sidebar/Sidebar.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
<script setup lang="ts">
import { type SyntaxOptions } from "src/composable/useSyntaxOptions";
import Logo from "../Logo/Logo.vue";
import Lint from "./Lint.vue";
import Syntax from "./Syntax.vue";
defineProps<{ syntaxState: SyntaxOptions }>();
</script>

<template>
<div
class="hidden pc:block w-52 h-screen px-8 box-content bg-[#f6f6f7] dark:bg-[#161618]"
>
<Logo />
<Syntax />
<Lint />
<Syntax :syntaxState="syntaxState" />
<Lint :syntaxState="syntaxState" />
</div>
</template>
53 changes: 49 additions & 4 deletions src/components/Sidebar/Syntax.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,78 @@
import { capitalize } from "vue";
import Checkbox from "../ui/Checkbox.vue";
import Select from "../ui/Select.vue";
const props = defineProps(["syntaxState"]);
const emit = defineEmits(["update:syntaxState"]);
function changeSourceType(sourceType: string) {
props.syntaxState.sourceType = sourceType;
}
function changeLanguage(language: string) {
props.syntaxState.language = language;
}
function checkedJSX(checked: boolean) {
props.syntaxState.jsx = checked;
}
function checkedTSX(checked: boolean) {
props.syntaxState.tsx = checked;
}
function checkedDTS(checked: boolean) {
props.syntaxState.dts = checked;
}
</script>

<template>
<div>
<p
class="pt-4 text-xl font-medium text-[#3c3c43] dark:text-[#fffff5]/[.86]"
>
Options
Syntax Options
</p>

<Select
:initValue="syntaxState.sourceType"
:title="capitalize('source')"
:onChange="changeSourceType"
:options="[
{ value: 'module', label: 'module' },
{ value: 'script', label: 'script' },
]"
/>
<Select
:initValue="syntaxState.language"
:title="capitalize('language')"
:onChange="changeLanguage"
:options="[
{ value: 'typescript', label: 'typescript' },
{ value: 'javascript', label: 'javascript' },
]"
/>

<Checkbox id="jsx" title="JSX" />
<Checkbox id="Tsx" title="TSX" />
<Checkbox id="d.ts" title="D.TS" />
<Checkbox
:checked="syntaxState.language === 'javascript' && syntaxState.jsx"
:onChange="checkedJSX"
:disabled="syntaxState.language === 'typescript'"
id="jsx"
title="JSX"
/>
<Checkbox
:checked="syntaxState.language === 'typescript' && syntaxState.tsx"
:onChange="checkedTSX"
:disabled="syntaxState.language === 'javascript'"
id="Tsx"
title="TSX"
/>
<Checkbox
:checked="syntaxState.language === 'typescript' && syntaxState.dts"
:onChange="checkedDTS"
:disabled="syntaxState.language === 'javascript'"
id="d.ts"
title="D.TS"
/>
</div>
</template>
5 changes: 5 additions & 0 deletions src/components/ui/Checkbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { Checkbox } from "src/ui/checkbox";
defineProps<{
id: string;
title: string;
checked?: boolean;
disabled?: boolean;
onChange?: (value: boolean) => void;
}>();
</script>

Expand All @@ -13,6 +15,9 @@ defineProps<{
<Checkbox
class="mr-2 bg-white dark:bg-[#1b1b1f] data-[state=checked]:bg-[#3451b2] dark:data-[state=checked]:bg-[#a8b1ff] data-[state=checked]:text-white dark:data-[state=checked]:text-[#2e2e32]"
:id="id"
:defaultChecked="checked"
:disabled="disabled"
:onUpdate:checked="onChange"
/>
<label class="text-[#3c3c43] dark:text-[#fffff5]/[.86]" :for="id">
{{ title }}
Expand Down
Loading

0 comments on commit c8a2d0b

Please sign in to comment.