Herrington Darkholme 9a5bdb15df
chore(playground): support unicode in sfc playground (#3662)
atob/btoa only supports ASCII string which makes playground fails
to save unicode source. This patch add unicode support by combining
escape/encodeURIComponent. `escape` is chosen for backward
compatibility.
2021-06-08 10:12:15 -04:00

112 lines
2.2 KiB
TypeScript

import { reactive, watchEffect } from 'vue'
import { compileFile, MAIN_FILE } from './sfcCompiler'
import { utoa, atou } from './utils'
const welcomeCode = `
<template>
<h1>{{ msg }}</h1>
</template>
<script setup>
const msg = 'Hello World!'
</script>
`.trim()
export class File {
filename: string
code: string
compiled = {
js: '',
css: '',
ssr: ''
}
constructor(filename: string, code = '') {
this.filename = filename
this.code = code
}
}
interface Store {
files: Record<string, File>
activeFilename: string
readonly activeFile: File
readonly importMap: string | undefined
errors: (string | Error)[]
}
let files: Store['files'] = {}
const savedFiles = location.hash.slice(1)
if (savedFiles) {
const saved = JSON.parse(atou(savedFiles))
for (const filename in saved) {
files[filename] = new File(filename, saved[filename])
}
} else {
files = {
'App.vue': new File(MAIN_FILE, welcomeCode)
}
}
export const store: Store = reactive({
files,
activeFilename: MAIN_FILE,
get activeFile() {
return store.files[store.activeFilename]
},
get importMap() {
const file = store.files['import-map.json']
return file && file.code
},
errors: []
})
watchEffect(() => compileFile(store.activeFile))
for (const file in store.files) {
if (file !== MAIN_FILE) {
compileFile(store.files[file])
}
}
watchEffect(() => {
history.replaceState({}, '', '#' + utoa(JSON.stringify(exportFiles())))
})
export function exportFiles() {
const exported: Record<string, string> = {}
for (const filename in store.files) {
exported[filename] = store.files[filename].code
}
return exported
}
export function setActive(filename: string) {
store.activeFilename = filename
}
export function addFile(filename: string) {
const file = (store.files[filename] = new File(filename))
if (filename === 'import-map.json') {
file.code = `
{
"imports": {
}
}`.trim()
}
setActive(filename)
}
export function deleteFile(filename: string) {
if (confirm(`Are you sure you want to delete ${filename}?`)) {
if (store.activeFilename === filename) {
store.activeFilename = MAIN_FILE
}
delete store.files[filename]
}
}