Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding an easily accessible cheat sheet UI #23

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
22 changes: 18 additions & 4 deletions editor/src/components/ui/CompileButton.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
<template>
<button title="Compile the program [Alt + Enter]" @click="compile" class="w-16 h-16 rounded-full absolute top-12 -right-16 transform -translate-x-1/2 z-20 inline-flex justify-center items-center border-4 border-solid border-gray-900 focus:outline-none cursor-pointer text-gray-900 bg-cyan-300 transition hover:(bg-cyan-400 scale-110 -translate-x-[50%] shadow-lg)">
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="currentColor" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<button
title="Compile the program [Alt + Enter]"
@click="compile"
class="w-16 h-16 rounded-full absolute top-12 -right-16 transform -translate-x-1/2 z-20 inline-flex justify-center items-center border-4 border-solid border-gray-900 focus:outline-none cursor-pointer text-gray-900 bg-cyan-300 transition hover:(bg-cyan-400 scale-110 -translate-x-[50%] shadow-lg)"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="30"
height="30"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M7 4v16l13 -8z" />
</svg>
</button>
Expand All @@ -12,7 +26,7 @@ import { ComputedRef, inject, onMounted, onUnmounted } from 'vue';
import { Playground } from '../../store/code';

const emit = defineEmits<{
(e: 'triggeredCompile'): void
(e: 'triggeredCompile'): void;
}>();

const store = inject('store') as ComputedRef<Playground>;
Expand Down
59 changes: 59 additions & 0 deletions editor/src/components/ui/SyntaxGuideModel.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<template>
<div class="font-fira fixed inset-0 bg-black flex justify-center z-50 h-0">
<div
class="h-100 relative bg-black p-6 rounded-lg shadow-xl max-w-md w-full"
v-draggable
>
<button
@click="$emit('close')"
class="absolute top-0 right-0 my-4 mx-2 px-2 py-1 bg-black text-white rounded"
>
<svg
class="svg-icon"
style="
width: 2em;
height: 2em;
vertical-align: middle;
fill: currentColor;
overflow: hidden;
"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M512 806.764618C349.188606 806.764618 217.235382 674.811394 217.235382 512s131.953223-294.764618 294.764618-294.764618 294.764618 131.953223 294.764618 294.764618-131.953223 294.764618-294.764618 294.764618z m0-39.301949c141.087856 0 255.462669-114.374813 255.462669-255.462669S653.087856 256.537331 512 256.537331 256.537331 370.912144 256.537331 512s114.374813 255.462669 255.462669 255.462669zM549.152624 512l99.329535 99.252774-37.152624 37.152623L512 549.152624 412.747226 648.405397l-37.152623-37.152623L474.847376 512 374.443178 411.595802l37.152624-37.152624L512 474.847376l100.404198-100.404198 37.152624 37.152624L549.152624 512z m0 0"
/>
</svg>
</button>
<h2 class="font-merri text-cyan-500 text-2xl font-bold mb-4">
Syntax Cheat-sheet
</h2>
<div class="grid gap-2">
<div
v-for="(rule, index) in syntaxRules"
:key="index"
class="grid grid-cols-2 gap-2"
>
<span class="font-medium text-white">{{ rule.name }}</span>
<span class="text-cyan-500">{{ rule.syntax }}</span>
</div>
</div>
</div>
</div>
</template>

<script lang="ts" setup>
const syntaxRules = [
{ name: 'Start symbol', syntax: 'S' },
{ name: 'Follow (->)', syntax: '->' },
{ name: 'ε or λ', syntax: 'ε or λ or #' },
{ name: 'Or (|)', syntax: '|' },
{ name: 'End each rule', syntax: '.' },
{ name: 'Comments', syntax: '// comment' },
{ name: 'Non-terminals', syntax: 'start with uppercase character' },
{ name: 'Terminals', syntax: 'start with any other character' },
];

defineEmits(['close']);
</script>
73 changes: 73 additions & 0 deletions editor/src/components/ui/SyntaxSheet.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<template>
<button
title="Show Syntax Guide [Alt + S]"
@click="showSyntaxGuide"
class="w-16 h-16 rounded-full absolute top-12 -right-16 transform -translate-x-1/2 z-20 inline-flex justify-center items-center border-4 border-solid border-gray-900 focus:outline-none cursor-pointer text-gray-900 bg-cyan-300 transition hover:(bg-cyan-400 scale-110 -translate-x-[50%] shadow-lg)"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="30"
height="30"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
<path d="M3 19a9 9 0 0 1 9 0a9 9 0 0 1 9 0" />
<path d="M3 6a9 9 0 0 1 9 0a9 9 0 0 1 9 0" />
<path d="M3 6l0 13" />
<path d="M12 6l0 13" />
<path d="M21 6l0 13" />
</svg>
</button>
<Teleport to="body">
<Transition name="fade">
<SyntaxGuideModal v-if="isSyntaxGuideVisible" @close="closeSyntaxGuide" />
</Transition>
</Teleport>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import SyntaxGuideModal from './SyntaxGuideModel.vue';

const isSyntaxGuideVisible = ref(false);

const showSyntaxGuide = () => {
isSyntaxGuideVisible.value = true;
};

const closeSyntaxGuide = () => {
isSyntaxGuideVisible.value = false;
};

const handleSyntaxGuideKeybind = (e: KeyboardEvent) => {
if (e.altKey && e.code === 'KeyS') {
e.preventDefault();
showSyntaxGuide();
}
};

onMounted(() => {
window.addEventListener('keydown', handleSyntaxGuideKeybind);
});

onUnmounted(() => {
window.removeEventListener('keydown', handleSyntaxGuideKeybind);
});
</script>

<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
38 changes: 38 additions & 0 deletions editor/src/directives/draggable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// directives/draggable.ts
import { DirectiveBinding } from 'vue';

const draggable = {
mounted(el: HTMLElement) {
el.style.position = 'absolute';
el.style.cursor = 'move';

el.onmousedown = function (event) {
event.preventDefault();

const shiftX = event.clientX - el.getBoundingClientRect().left;
const shiftY = event.clientY - el.getBoundingClientRect().top;

const moveAt = (pageX: number, pageY: number) => {
el.style.left = pageX - shiftX + 'px';
el.style.top = pageY - shiftY + 'px';
};

const onMouseMove = (event: MouseEvent) => {
moveAt(event.pageX, event.pageY);
};

document.addEventListener('mousemove', onMouseMove);

el.onmouseup = function () {
document.removeEventListener('mousemove', onMouseMove);
el.onmouseup = null;
};
};

el.ondragstart = function () {
return false;
};
},
};

export default draggable;
3 changes: 2 additions & 1 deletion editor/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import GrowSlideTransition from './components/transitions/GrowSlideTransition.vu

import 'splitpanes/dist/splitpanes.css';
import 'virtual:windi.css';

import draggable from './directives/draggable';
const app = createApp(App);

app.directive('life', {
Expand All @@ -19,5 +19,6 @@ app.directive('life', {
app.component('FadeTransition', FadeTransition);
app.component('GrowSlideTransition', GrowSlideTransition);

app.directive('draggable', draggable);
app.use(router);
app.mount('#app');
39 changes: 22 additions & 17 deletions editor/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,6 @@ const sampleProgram = `
S -> 0 1 S | 1 0 S | A.
A -> 0 1 A | 1 0 A | #.

// Type your grammar here...

// Syntax cheat-sheet:
// * Start symbol S
// * Follow (->): ->
// * ε or λ: ε or λ or #
// * Or (|): |
// * End each rule: .
// * Comments: // comment
// * Non-terminals: start with uppercase character
// * Terminals: start with any other character
`;

const router = createRouter({
Expand All @@ -35,20 +24,34 @@ const router = createRouter({
component: Playground,
beforeEnter(to, _, next) {
try {
playgrounds.push(newPlayground('Program 1', (to.params.type as string).toUpperCase() as PlaygroundType, sampleProgram));
return next({ name: 'Playground', params: { id: 0 }, query: to.query });
} catch(err) {
playgrounds.push(
newPlayground(
'Program 1',
(to.params.type as string).toUpperCase() as PlaygroundType,
sampleProgram
)
);
return next({
name: 'Playground',
params: { id: 0 },
query: to.query,
});
} catch (err) {
return next({ name: '404' });
}
}
},
},
{
name: 'Playground',
path: '/tab/:id?',
component: Playground,
beforeEnter(to, _, next) {
if (!to.params.id || Number(to.params.id) >= playgrounds.length) {
return next({ name: 'NewPlayground', params: { type: 'RG' }, query: to.query });
return next({
name: 'NewPlayground',
params: { type: 'RG' },
query: to.query,
});
} else {
return next();
}
Expand All @@ -67,7 +70,9 @@ router.afterEach((to) => {

// Update page title to new tab's name
if (to.name === 'Playground') {
document.title = `${playgrounds[Number(to.params.id)].name} | Vyaakaran Playground`;
document.title = `${
playgrounds[Number(to.params.id)].name
} | Vyaakaran Playground`;
}
});

Expand Down
Loading