Skip to content

Commit

Permalink
feat(admin): preview routing (#482)
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu authored Jun 22, 2021
1 parent 15505ea commit e4c33d1
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 60 deletions.
27 changes: 5 additions & 22 deletions src/admin/app/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,19 @@
</KeepAlive>
</RouterView>

<iframe ref="iframe" :src="previewUrl" class="h-full flex-1" />
<Preview />
</main>
</template>

<script lang="ts">
import { defineComponent, provide, ref, onBeforeMount } from 'vue3'
import { defineComponent } from 'vue3'
import AppHeader from './components/AppHeader.vue'
import { useApi } from './plugins/api'
import Preview from './components/Preview.vue'
export default defineComponent({
components: {
AppHeader
},
setup() {
const api = useApi()
const previewUrl = ref('http://localhost:4000')
onBeforeMount(async () => {
const { url } = (await api.get('/preview')) as any
previewUrl.value = url
})
provide('previewUrl', previewUrl)
return {
previewUrl
}
AppHeader,
Preview
}
})
</script>
16 changes: 10 additions & 6 deletions src/admin/app/components/Editor.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<template>
<textarea v-model="frontmatter" class="h-24 w-full" />
<textarea v-model="content" class="w-full h-full" />
<textarea
v-model="frontmatter"
class="h-24 w-full font-mono px-4 py-2 d-border-primary border-b outline-none text-sm"
/>
<textarea v-model="content" class="w-full h-full font-mono px-4 py-2 outline-none text-sm" />
</template>

<script lang="ts">
import YAML from 'js-yaml'
import { GrayMatterFile } from 'gray-matter'
import { defineComponent, computed, ref, watch, PropType } from 'vue3'
import { useApi } from '../plugins/api'
Expand Down Expand Up @@ -36,14 +40,14 @@ export default defineComponent({
// Stringified reference for frontmatter text-area
const frontmatter = computed({
get() {
return JSON.stringify(data.value, null, 2)
return YAML.dump(data.value, null, 2)
},
set(value: string) {
try {
data.value = JSON.parse(value)
data.value = YAML.parse(value)
} catch (e) {
// New value is not a valid JSON string.
// Do nothing and wait for the next valid JSON input.
// New value is not a valid YAML string.
// Do nothing and wait for the next valid YAML input.
}
}
})
Expand Down
2 changes: 1 addition & 1 deletion src/admin/app/components/FilesTreeIcon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>

<span v-else-if="!isRoot || hasOneDir(files)" class="mr-1 inline-block h-4 w-4" />
<span v-else class="mr-1 inline-block h-4 w-4" />

<svg
v-if="isDir(file)"
Expand Down
36 changes: 36 additions & 0 deletions src/admin/app/components/Preview.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script setup lang="ts">
import { onBeforeMount, ref, watch } from 'vue3'
import { fetchPreviewOrigin, previewUrl, previewPath } from '../composables/preview'
const iframe = ref<HTMLIFrameElement>()
onBeforeMount(() => fetchPreviewOrigin())
watch(
[previewUrl, iframe],
() => {
if (!iframe.value) return
try {
iframe.value.contentWindow.$nuxt.$router.push(previewPath.value)
} catch (e) {
// fallback to hard refresh when working with cross-origin
iframe.value.src = previewUrl.value
}
},
{ flush: 'post' }
)
function refresh() {
iframe.value.src += ''
}
</script>

<template>
<div class="h-full flex-1 grid grid-rows-[min-content,1fr]">
<div class="p-2 flex d-border-primary border-b">
<div class="flex-auto my-auto px-2">{{ previewUrl }}</div>
<button class="border d-border-primary rounded px-2 py-1" @click="refresh">Refresh</button>
</div>
<iframe ref="iframe" :src="previewOrigin" class="w-full h-full" />
</div>
</template>
1 change: 1 addition & 0 deletions src/admin/app/composables/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './preview'
21 changes: 21 additions & 0 deletions src/admin/app/composables/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ref, computed } from 'vue3'
import { useApi } from '../plugins/api'

export const previewOrigin = ref('http://localhost:4000')
export const previewPath = ref('/')
export const previewUrl = computed(() => previewOrigin.value + previewPath.value)

const api = useApi()

export async function fetchPreviewOrigin() {
const { url } = (await api.get('/preview')) as any

previewOrigin.value = url
}

export function navigateToFile(filepath: string) {
previewPath.value = filepath
.replace(/\/\d+\./g, '/')
.replace(/\.md$/, '')
.replace(/\/index$/, '/')
}
6 changes: 5 additions & 1 deletion src/admin/app/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { reactive, defineComponent, onMounted, toRefs } from 'vue3'
import FilesTree from '../components/FilesTree.vue'
import Editor from '../components/Editor.vue'
import { useApi } from '../plugins/api'
import { navigateToFile } from '../composables/preview'
export default defineComponent({
components: {
Expand All @@ -30,7 +31,10 @@ export default defineComponent({
currentFile: null
})
const openFile = async file => (state.currentFile = await api.get(`/pages${file.path}`))
const openFile = async file => {
navigateToFile(file.path)
state.currentFile = await api.get(`/pages${file.path}`)
}
onMounted(async () => (state.files = await api.get('/pages')))
Expand Down
45 changes: 15 additions & 30 deletions src/admin/app/pages/static.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,42 +27,27 @@
</div>
</template>

<script>
<script setup lang="ts">
import { onMounted, ref } from 'vue3'
import FilesTree from '../components/FilesTree.vue'
import Editor from '../components/Editor.vue'
import { useApi } from '../plugins/api'
import { isImage } from '../utils'
import { previewUrl } from '../composables/preview'
export default {
components: {
FilesTree,
Editor
},
const api = useApi()
const files = ref([])
const currentFile = ref(null)
inject: ['previewUrl'],
onMounted(async () => {
files.value = await api.get('/static')
})
setup() {
return { isImage }
},
data() {
return {
files: [],
currentFile: null
}
},
async mounted() {
this.files = await this.$api.get('/static')
},
methods: {
async openFile(file) {
if (this.isImage(file)) {
this.currentFile = file
} else {
this.currentFile = await this.$api.get(`/static${file.path}`)
}
}
async function openFile(file) {
if (isImage(file)) {
currentFile.value = file
} else {
currentFile.value = await api.get(`/static${file.path}`)
}
}
</script>

0 comments on commit e4c33d1

Please sign in to comment.