Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8d3c13b
feat:support splitpane component
Jun 20, 2025
a846a8e
feat: output style add w/h-full
Triumph-light Jun 21, 2025
944fe24
feat: move parser select to outcontainer
Triumph-light Jun 22, 2025
d33d40e
feat: support multiple parser
Triumph-light Jun 22, 2025
3716ace
feat: props type
Triumph-light Jun 23, 2025
38da9b8
feat: type
Triumph-light Jun 23, 2025
0bfaa94
feat: basic operation of multiple parser
Triumph-light Jun 25, 2025
36ff6d9
Merge branch 'main' into feature-multiple-splitpane
Triumph-light Jun 28, 2025
44774be
feat: layout
Triumph-light Jun 28, 2025
200b1ec
feat: The development is basically complete.
Triumph-light Jun 28, 2025
f479607
feat: The development is basically complete.
Triumph-light Jun 28, 2025
fe10d17
fix: type fix
Triumph-light Jun 28, 2025
a750bc2
feat: support different parser's version and delete log and fix type
Triumph-light Jun 28, 2025
fdeaac1
feat: control sidebar's display
Triumph-light Jun 28, 2025
d612d8d
feat: revert vsc setting
Triumph-light Jun 29, 2025
b7406ca
fix: ts type fix, style bug fix
Triumph-light Jun 29, 2025
0964e6b
style: eslint fix
Triumph-light Jun 29, 2025
14b1932
feat: Supports saving of old options and optimizing parsing execution…
Triumph-light Jul 2, 2025
57a2eaf
Merge branch 'main' into feature-multiple-splitpane
Triumph-light Jul 2, 2025
58e13bc
feat:delete layout icon
Triumph-light Jul 2, 2025
38f9db5
feat: delete layout icon
Triumph-light Jul 2, 2025
1fb641e
style: lint fix
Triumph-light Jul 2, 2025
6d97d00
feat: merge main
Triumph-light Jul 6, 2025
437bb6e
fix: limit content style in 100vw
Triumph-light Jul 7, 2025
97cb6d3
feat: support print single container's ast value
Triumph-light Jul 7, 2025
e9c8eea
fix: add root div in order to resolve Runtime directive used on compo…
Triumph-light Jul 7, 2025
b896596
fix: parse loading
Triumph-light Jul 7, 2025
ee2f896
fix: ts module parser fail
Triumph-light Jul 7, 2025
872c370
fix: style fix
Triumph-light Jul 7, 2025
b965f3f
refactor: make parserModules clearly
Triumph-light Jul 12, 2025
bde5baa
feat: Support for auto focus is provided by each respective party
Triumph-light Jul 12, 2025
f9a7e04
feat: Support for hideLocationData is provided by each respective party
Triumph-light Jul 12, 2025
175cdb9
feat: Support for outputView is provided by each individual
Triumph-light Jul 12, 2025
b8a388e
refactor: Concentrate on changing the current container data
Triumph-light Jul 13, 2025
ce626ac
feat: Support hideKeys for respective containers
Triumph-light Jul 13, 2025
835408a
feat: Adjust the style
Triumph-light Jul 13, 2025
a2f3582
feat: Cache the parsing results of the same parser
Triumph-light Jul 13, 2025
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
17 changes: 5 additions & 12 deletions app.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<script setup lang="ts">
import { editorLayout } from '~/state/parser/parser'

const title = 'AST Explorer'
const desc = 'A web tool to explore the ASTs generated by parsers.'
const url = 'https://ast-explorer.dev/'
Expand Down Expand Up @@ -35,8 +37,8 @@ useHeadSafe({
<template>
<ClientOnly>
<Suspense>
<main flex="~ col" lg:h-screen>
<Navbar border-b />
<main flex="~ col" lg:h-screen lg:w-screen>
<Navbar v-model:layout="editorLayout" border-b />

<div min-h-0 flex flex-1 flex-col gap2 lg:flex-row>
<AppSideBar
Expand All @@ -47,16 +49,7 @@ useHeadSafe({
lg:flex-none
/>

<div min-w-0 flex flex-col gap2 lg:flex-1 lg:flex-row>
<InputContainer v-show="showInputEditor" min-w-0 flex-1 py1 />
<div
v-show="showInputEditor && showOutput"
border-t
lg:border-l
lg:border-t-none
/>
<OutputContainer v-show="showOutput" min-w-0 flex-1 py1 />
</div>
<Layout min-w-0 />
</div>
</main>

Expand Down
1 change: 1 addition & 0 deletions components/CodeEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const props = defineProps<{
language: MonacoLanguage
input?: boolean
}>()

const code = defineModel<string>()

const container = shallowRef<{
Expand Down
15 changes: 10 additions & 5 deletions components/InputContainer.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
<script setup lang="ts">
import { code } from '#imports'
import { parserOptions } from '~/state/parser/options'
import { currentParser } from '~/state/parser/parser'
import { parsersOptions } from '~/state/parser/options'
import { currentParsers } from '~/state/parser/parser'
import { activeTab } from '~/state/ui'

const language = computed(() => {
if (typeof currentParser.value.editorLanguage === 'string') {
return currentParser.value.editorLanguage
const currentParser = currentParsers.value.find(
(parser) => parser.id === activeTab.value,
)!

if (typeof currentParser.editorLanguage === 'string') {
return currentParser.editorLanguage
}
return currentParser.value.editorLanguage(parserOptions.value)
return currentParser.editorLanguage(parsersOptions.value[currentParser.id])
})

function showSettings() {
Expand Down
88 changes: 88 additions & 0 deletions components/Layout.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<script setup lang="ts">
import { editorLayout } from '~/state/parser/parser'
</script>

<template>
<div style="height: calc(100vh - 50px)">
<div v-if="editorLayout === 'left-right' && !showInputEditor" h-full w-full>
<OutputContainer
v-show="showOutput"
:index="0"
h-full
min-w-0
w-full
py1
/>
</div>

<div v-else-if="!showOutput && showInputEditor" h-full w-full>
<InputContainer h-full min-w-0 w-full py1 />
</div>

<SplitPane
v-else-if="editorLayout === 'left-right' && showInputEditor && showOutput"
>
<template #left>
<InputContainer h-full min-w-0 w-full py1 />
</template>
<template #right>
<OutputContainer
v-show="showOutput"
:index="0"
h-full
min-w-0
w-full
py1
/>
</template>
</SplitPane>

<SplitPane
v-else-if="
editorLayout === 'top-bottom-split' && !showInputEditor && showOutput
"
>
<template #left>
<OutputContainer
v-show="showOutput"
:index="0"
h-full
min-w-0
w-full
py1
/>
</template>
<template #right>
<OutputContainer
v-show="showOutput"
:index="1"
h-full
min-w-0
w-full
py1
/>
</template>
</SplitPane>

<SplitPane
v-else-if="
editorLayout === 'top-bottom-split' && showInputEditor && showOutput
"
layout="vertical"
>
<template #left>
<InputContainer h-full min-w-0 w-full py1 />
</template>
<template #right>
<SplitPane>
<template #left>
<OutputContainer v-show="showOutput" :index="0" h-full w-full py1 />
</template>
<template #right>
<OutputContainer v-show="showOutput" :index="1" h-full w-full py1 />
</template>
</SplitPane>
</template>
</SplitPane>
</div>
</template>
161 changes: 161 additions & 0 deletions components/SplitPane.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
<script setup lang="ts">
import { computed, reactive, useTemplateRef } from 'vue'

const props = withDefaults(
defineProps<{ layout?: 'horizontal' | 'vertical' }>(),
{
layout: 'horizontal',
},
)
const isVertical = computed(() => props.layout === 'vertical')

const containerRef = useTemplateRef('container')
const state = reactive({
dragging: false,
split: 50,
viewHeight: 0,
viewWidth: 0,
})

const boundSplit = computed(() => {
const { split } = state
return split < 10 ? 10 : Math.min(split, 90)
})

let startPosition = 0
let startSplit = 0

function dragStart(e: MouseEvent) {
state.dragging = true
startPosition = isVertical.value ? e.pageY : e.pageX
startSplit = boundSplit.value
}

function dragMove(e: MouseEvent) {
if (containerRef.value && state.dragging) {
const position = isVertical.value ? e.pageY : e.pageX
const totalSize = isVertical.value
? containerRef.value.offsetHeight
: containerRef.value.offsetWidth
const dp = position - startPosition
state.split = startSplit + +((dp / totalSize) * 100).toFixed(2)
}
}

function dragEnd() {
state.dragging = false
}
</script>

<template>
<div
ref="container"
class="split-pane"
:class="{
dragging: state.dragging,
[isVertical ? 'vertical' : 'horizontal']: true,
}"
@mousemove="dragMove"
@mouseup="dragEnd"
@mouseleave="dragEnd"
>
<div
class="left"
:style="{ [isVertical ? 'height' : 'width']: `${boundSplit}%` }"
>
<slot name="left" />
<div class="dragger" @mousedown.prevent="dragStart" />
</div>
<div
class="right"
:style="{ [isVertical ? 'height' : 'width']: `${100 - boundSplit}%` }"
>
<slot name="right" />
</div>
</div>
</template>

<style scoped>
.split-pane {
display: flex;
width: 100%;
height: 100%;
position: relative;
}

.split-pane.dragging {
cursor: ew-resize;
}

.dragging .left,
.dragging .right {
pointer-events: none;
}

.horizontal > .left,
.horizontal > .right {
position: relative;
}

.horizontal > .left {
border-right: 1px solid var(--c-border);
}

.horizontal > .left > .dragger {
position: absolute;
z-index: 3;
top: 0;
bottom: 0;
right: -5px;
width: 10px;
cursor: ew-resize;
}

.toggler {
display: none;
z-index: 3;
color: var(--c-text-base);
position: absolute;
left: 50%;
bottom: 20px;
background-color: var(--c-bg-base);
padding: 8px 12px;
border-radius: 8px;
transform: translateX(-50%);
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.25);
}

.dark .toggler {
background-color: var(--c-bg-base);
}

.split-pane.vertical {
display: block;
}

.split-pane.vertical.dragging {
cursor: ns-resize;
}

.vertical > .left > .dragger {
position: absolute;
top: auto;
height: 10px;
width: 100%;
left: 0;
right: 0;
bottom: 0;
cursor: ns-resize;
}

.vertical > .left,
.vertical > .right {
position: relative;
width: 100%;
}

.vertical > .left {
border-right: none;
border-bottom: 1px solid var(--c-border);
}
</style>
64 changes: 49 additions & 15 deletions components/app/SideBar.vue
Original file line number Diff line number Diff line change
@@ -1,23 +1,57 @@
<script setup lang="ts">
import {
currentParser,
currentParserGui as ParserGui,
} from '~/state/parser/parser'
import { currentParsers, currentParsersGuis } from '~/state/parser/parser'
import { activeTab } from '~/state/ui'

const tabs = computed(() => {
const tabIds = new Set(currentParsers.value.map((p) => p.id))
return Array.from(tabIds).map((id) => ({ label: id, value: id }))
})

watch(
tabs,
() => {
activeTab.value = tabs.value[0]!.value
},
{
immediate: true,
},
)
</script>

<template>
<div flex="~ y-center col" gap2 px3 py2>
<div>
<IconPreview :value="currentParser.icon" size="5em" />
</div>
<h2 flex="~ center" gap2 text-lg font-bold>
Parser Options
<ParserOptions v-if="currentParser.options.configurable" nav-button />
</h2>
<Suspense :timeout="0">
<ParserGui v-if="ParserGui" w-full class="sidebar-gui" />
<template #fallback><Loading /></template>
</Suspense>
<TabsTab v-show="sideBarAvailable" v-model="activeTab" :tabs="tabs">
<TabsTabPane
v-for="(tab, idx) in tabs"
:key="tab.label"
:label="tab.label"
:value="tab.value"
>
<div flex items-center justify-center>
<IconPreview :value="currentParsers[idx]!.icon" size="5em" />
</div>
<h2 flex="~ center" gap2 text-lg font-bold>
Parser Options
<ParserOptions
v-if="currentParsers[idx]!.options.configurable"
:parser-id="currentParsers[idx]!.id"
:index="idx"
nav-button
/>
</h2>
<Suspense :timeout="0">
<Component
:is="currentParsersGuis[idx]"
v-if="currentParsersGuis[idx]"
w-full
class="sidebar-gui"
/>
<template #fallback>
<Loading />
</template>
</Suspense>
</TabsTabPane>
</TabsTab>
</div>
</template>

Expand Down
Loading