Skip to content
This repository has been archived by the owner on Jun 22, 2024. It is now read-only.

Commit

Permalink
feat: send props to renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
Flowko committed Feb 2, 2024
1 parent 8d0aa3b commit 4446dc9
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 38 deletions.
22 changes: 19 additions & 3 deletions client/components/CodeContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defineEmits(['setlang'])
const toast = useToast()
const { editorCode } = useTool()
const { template, email } = useEmail()
const { template, email, props, renderEmail } = useEmail()
function handleDownload(lang: 'html' | 'txt' | 'vue') {
const content = template.value[lang]
Expand Down Expand Up @@ -58,6 +58,11 @@ const items = computed(() => {
icon: 'i-ph-text-t-duotone',
code: template.value.txt,
},
{
key: 'props',
label: 'Props',
icon: 'i-ph-code-duotone',
},
]
}
else if (editorCode.value.id === 'html') {
Expand Down Expand Up @@ -102,7 +107,7 @@ const tab = ref(0)
<UIcon :name="item.icon" class="w-7 h-7 flex-shrink-0" />

<span class="truncate">{{ item.label }}</span>
<template v-if="selected">
<template v-if="selected && item.code">
<UTooltip text="Copy to clipboard">
<UButton class="ml-6" icon="i-ph-copy-duotone" size="xs" square color="gray" variant="solid" @click="handleClipboard(item.key)" />
</UTooltip>
Expand All @@ -116,7 +121,18 @@ const tab = ref(0)
</template>

<template #item="{ item }">
<div class="w-full h-full" v-html="highlight(item.code, item.key)" />
<div v-if="item.code" class="w-full h-full" v-html="highlight(item.code, item.key)" />
<div v-else-if="item.key === 'props'" class="w-full h-full">
<UContainer class="py-5 flex flex-col gap-y-4">
<template v-for="(prop, idx) in props" :key="idx">
<UFormGroup v-if="prop.type === 'string'" :label="prop.label" :description="prop.description">
<UInput v-model="prop.value" type="text" />
</UFormGroup>

<UButton label="Update" @click="renderEmail()" />
</template>
</UContainer>
</div>
</template>
</UTabs>
</template>
Expand Down
4 changes: 2 additions & 2 deletions client/composables/shiki.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Highlighter } from 'shikiji'
import { getHighlighter } from 'shikiji'
import type { Highlighter } from 'shiki'
import { getHighlighter } from 'shiki'
import { ref } from 'vue'

export const shiki = ref<Highlighter>()
Expand Down
83 changes: 68 additions & 15 deletions client/composables/useEmail.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
import pretty from 'pretty'
import type { Result } from '@vue-email/compiler'
import type { Email } from '@/types/email'
import { upperFirst } from 'scule'
import type { Email, Template } from '@/types/email'

function removeQuotes(inputString: any) {
// Check if the input is a string and has at least two characters
if (typeof inputString === 'string' && inputString.length >= 2) {
// Check if the string starts and ends with double quotes
if (inputString[0] === '"' && inputString[inputString.length - 1] === '"') {
// Remove the quotes and return the modified string
return inputString.slice(1, -1)
}
else {
// If the string doesn't have quotes at the start and end, return the original string
return inputString
}
}
else {
// If the input is not a valid string, return an empty string or handle it accordingly
return ''
}
}

export function useEmail() {
const emails = useState<Email[]>('emails')
const email = useState<Email>('email')
const sending = useState<boolean>('sending', () => false)
const refresh = useState<boolean>('refresh', () => false)
const template = useState<{
vue: string
html: string
txt: string
}>('template')
const template = useState<Template>('template')
const props = useState<{
label: string
value: any
type: string
description?: string
}[]>('props')

const { host } = useWindow()

Expand All @@ -34,18 +56,20 @@ export function useEmail() {
return null

const { data } = await useFetch<Result>(`/api/render/${email.value.filename}`, {
method: 'POST',
baseURL: host.value,
body: {
props: props.value,
},
})

if (data.value) {
return {
template.value = {
vue: email.value.content,
html: pretty(data.value.html),
txt: data.value.text,
}
} as Template
}

return null
}

const getEmail = async (filename: string) => {
Expand All @@ -54,11 +78,39 @@ export function useEmail() {

if (found) {
email.value = found

await renderEmail().then((value) => {
if (value)
template.value = value
})
try {
if (found.props) {
props.value = found.props.map((prop) => {
const value = removeQuotes(prop.default) || ''
const destructuredType = prop.type.split('|').map((type) => {
if (type === 'string')
return 'string'

if (type === 'number')
return 'number'

if (type === 'boolean')
return 'boolean'

if (type === 'object')
return 'object'

return 'string'
})

return {
label: upperFirst(prop.name),
type: destructuredType[0],
value,
}
})
}
}
catch (error) {
console.error(error)
}

await renderEmail()
}
}
}
Expand Down Expand Up @@ -119,6 +171,7 @@ export function useEmail() {
sending,
refresh,
template,
props,
getEmail,
sendTestEmail,
renderEmail,
Expand Down
2 changes: 1 addition & 1 deletion client/emails/code-components.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const box = {
padding: '0 48px',
}
const code = `import { codeToThemedTokens } from 'shikiji'
const code = `import { codeToThemedTokens } from 'shiki'
const tokens = await codeToThemedTokens('<div class="foo">bar</div>', {
lang: 'html',
Expand Down
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"nuxt": "^3.9.3",
"pretty": "^2.0.0",
"scule": "^1.2.0",
"shikiji": "^0.9.19",
"shiki": "^1.0.0-beta.3",
"splitpanes": "^3.1.5",
"vue-component-meta": "^1.8.27"
}
Expand Down
4 changes: 2 additions & 2 deletions client/pages/email/[file].vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ const route = useRoute()
const { getEmail, template } = useEmail()
const { horizontalSplit, previewMode } = useTool({
async onReload() {
await getEmail(`${route.params.file}`)
await getEmail(route.params.file as string)
},
})
onMounted(async () => {
await getEmail(`${route.params.file}`)
await getEmail(route.params.file as string)
})
const showBoth = computed(() => previewMode.value.id === 'both')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,20 @@ import { createError, defineEventHandler } from '#imports'
export default defineEventHandler(async (event: any) => {
try {
const file = event.context.params && event.context.params.file ? event.context.params.file : null
const body = await readBody(event)

let props: any = null
if (body && body.props) {
props = body.props.reduce((acc: Record<string, any>, prop: any) => {
acc[prop.label.toLowerCase()] = prop.value
return acc
}, {})
}

// TODO: pass props to template
const template = await useCompiler(file)
const template = await useCompiler(file, {
props,
})

if (!template) {
throw createError({
Expand Down
31 changes: 18 additions & 13 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 4446dc9

Please sign in to comment.