Skip to content

Commit

Permalink
chore: add editor demo
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 committed Mar 12, 2021
1 parent 59b87c5 commit 9892b69
Show file tree
Hide file tree
Showing 9 changed files with 591 additions and 3 deletions.
106 changes: 106 additions & 0 deletions demo/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<template>
<Suspense>
<div class="container">
<FileTree @open="openTab" />
<div class="main">
<div class="tabs">
<div v-for="tab in state.tabs" :key="tab.path" class="tab" :class="{active: state.path === tab.path }">
<span @click="openTab(tab.path)">{{ tab.name }} </span><span @click="closeTab(tab.path)">(x)</span>
</div>
</div>
<Editor class="editor" :value="state.source" :language="state.language" />
</div>
</div>
</Suspense>
</template>

<script>
import { defineComponent, reactive, inject } from 'vue'
import Editor from './Editor.vue'
import FileTree from './FileTree.vue'
export default defineComponent({
components: {
Editor,
FileTree
},
setup () {
const storage = inject('storage')
const state = reactive({
tabs: [],
path: undefined,
source: '',
language: 'javascript'
})
const openTab = async (path) => {
const tab = state.tabs.find(tab => tab.path === path)
if (!tab) {
state.tabs.push({
name: path.split(':').pop(),
path
})
}
const source = await storage.getItem(path)
state.language = path.split(':').pop().split('.').pop() || 'javascript'
state.path = path
state.source = source
}
const closeTab = (path) => {
state.tabs = state.tabs.filter(t => t.path !== path)
}
return {
state,
openTab,
closeTab
}
}
})
</script>

<style>
body, html, #app {
margin: 0;
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: white;
background: #2c3e50;
overflow: hidden;
}
.container {
display: flex;
min-height: 100vh;
max-height: 100vh;
}
.main {
display: flex;
flex-direction: column;
flex: 1;
}
.editor {
flex: 1;
}
.tabs {
display: flex;
min-height: 2em;
}
.tab {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 2em;
cursor: pointer;
}
.tab.active {
background: blue;
}
</style>
41 changes: 41 additions & 0 deletions demo/Editor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<template>
<div ref="editor" class="editor" />
</template>

<script>
import { defineComponent } from 'vue'
import * as monaco from 'monaco-editor'
export default defineComponent({
props: {
value: {
type: String,
required: true
},
language: {
type: String,
default: 'auto'
}
},
watch: {
value (newValue) {
this.editor.setValue(newValue)
},
language (newValue) {
this.editor.setModelLanguage(this.editor.getModule(), newValue)
}
},
mounted () {
this.editor = monaco.editor.create(this.$refs.editor, {
value: this.value,
language: this.language
})
}
})
</script>

<style scoped>
.editor {
flex: 1;
}
</style>
57 changes: 57 additions & 0 deletions demo/FileTree.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<template>
<div class="filetree">
<file-tree-node
:item="tree"
@open="path => $emit('open', path)"
/>
</div>
</template>

<script>
import { defineComponent, inject, ref } from 'vue'
import FileTreeNode from './FileTreeNode.vue'
function unflattenArray (items, toplevelKey = 'root') {
const res = { name: toplevelKey, path: '', children: [] }
for (const item of items) {
const split = item.split(':')
let target = res
for (const name of split) {
let child = target.children.find(c => c.name === name)
if (!child) {
child = {
name,
path: target.path + ':' + name,
children: []
}
target.children.push(child)
target.children = target.children.sort((c1, c2) => c1.name.localeCompare(c2.name))
}
target = child
}
target.path = item
}
return res
}
export default defineComponent({
components: { FileTreeNode },
async setup () {
const storage = inject('storage')
const tree = ref([])
await storage.getKeys().then((_keys) => {
tree.value = unflattenArray(_keys, 'workspace')
})
return {
tree
}
}
})
</script>

<style scoped>
.filetree {
min-width: 300px;
overflow-y: scroll;
}
</style>
53 changes: 53 additions & 0 deletions demo/FileTreeNode.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<li class="filetree-node">
<div @click="onOpen">
{{ item.name }} <span v-if="isDirectory">[{{ isOpen ? '-' : '+' }}]</span>
</div>
<ul v-if="isOpen && item.children.length">
<file-tree-node
v-for="child of item.children"
:key="child.name"
:item="child"
@open="path => $emit('open', path)"
/>
</ul>
</li>
</template>

<script>
import { defineComponent, ref } from 'vue'
export default defineComponent({
props: {
item: {
type: Object,
required: true
}
},
setup (props) {
return {
isOpen: ref((props.item.path || '').split(':').length < 3)
}
},
computed: {
isDirectory () {
return this.item.children.length
}
},
methods: {
onOpen () {
if (this.isDirectory) {
this.isOpen = !this.isOpen
} else {
this.$emit('open', this.item.path)
}
}
}
})
</script>

<style scoped>
.filetree-node {
cursor: pointer;
}
</style>
13 changes: 13 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/main.js"></script>
</body>
</html>
16 changes: 16 additions & 0 deletions demo/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createApp } from 'vue'
import { createStorage } from '../src'
import httpDriver from '../src/drivers/http'
import App from './App.vue'

async function main () {
const storage = createStorage()
await storage.mount('/', httpDriver({
base: location.origin + '/storage'
}))
const app = createApp(App)
app.provide('storage', storage)
app.mount('#app')
}

main()
27 changes: 27 additions & 0 deletions demo/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createStorage } from '../src'
import { createStorageServer } from '../src/server'
import fsdriver from '../src/drivers/fs'

// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
'node-fetch': 'node-fetch/browser'
}
},
plugins: [
vue(),
{
name: 'app',
async configureServer (server) {
const storage = createStorage()
const storageServer = createStorageServer(storage)
await storage.mount('/src', fsdriver({ base: resolve(__dirname, '..') }))
server.middlewares.use('/storage', storageServer.handle)
}
}
]
})
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"scripts": {
"build": "siroc build && mkdist --src src/drivers --dist drivers --format cjs",
"dev": "jest --watch",
"demo": "vite demo",
"lint": "eslint --ext .ts .",
"prepublishOnly": "yarn build",
"release": "yarn test && standard-version && git push --follow-tags && npm publish",
Expand All @@ -51,17 +52,21 @@
"@types/mri": "^1.1.0",
"@types/node": "latest",
"@types/ws": "^7.4.0",
"@vitejs/plugin-vue": "^1.1.5",
"@vue/compiler-sfc": "^3.0.5",
"destr": "^1.1.0",
"doctoc": "^2.0.0",
"eslint": "latest",
"jest": "latest",
"jiti": "latest",
"jsdom": "^16.4.0",
"mkdist": "^0.1.2",
"monaco-editor": "^0.23.0",
"siroc": "latest",
"standard-version": "latest",
"ts-jest": "latest",
"typescript": "latest",
"vite": "^2.0.5"
"vite": "^2.0.5",
"vue": "^3.0.5"
}
}
Loading

0 comments on commit 9892b69

Please sign in to comment.