Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/commands/make/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export default async function makeComponent(filePath?: string) {
p.text({
message: 'Directory to place it in',
placeholder: './components',
initialValue: './components',
validate: value => {
if (!value) return 'Please enter a path.'
if (value[0] !== '.') return 'Please enter a relative path.'
},
}),
},
Expand Down
2 changes: 1 addition & 1 deletion src/commands/make/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default async function makeConfig(name?: string) {
placeholder: 'production',
validate: value => {
if (!value) return 'Please enter a config name.'
if (value.includes(' ')) return 'Use - instead of spaces.'
if (value.includes(' ')) return 'Use - or . instead of spaces.'
},
}),
},
Expand Down
6 changes: 3 additions & 3 deletions src/commands/make/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { scaffold, onCancel } from './scaffold.ts'

export default async function makeLayout(filePath?: string) {
if (filePath) {
await scaffold(filePath, 'layout.vue')
await scaffold(filePath, 'Layout.vue')
return
}

Expand All @@ -24,14 +24,14 @@ export default async function makeLayout(filePath?: string) {
p.text({
message: 'Directory to place it in',
placeholder: './components',
initialValue: './components',
validate: value => {
if (!value) return 'Please enter a path.'
if (value[0] !== '.') return 'Please enter a relative path.'
},
}),
},
{ onCancel },
)

await scaffold(`${result.path}/${result.filename}`, 'layout.vue')
await scaffold(`${result.path}/${result.filename}`, 'Layout.vue')
}
2 changes: 1 addition & 1 deletion src/commands/make/scaffold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ export async function scaffold(filePath: string, stubName: string) {
}

export function onCancel() {
p.cancel('Cancelled.')
p.cancel('Canceled.')
process.exit(0)
}
146 changes: 146 additions & 0 deletions src/commands/make/stubs/Layout.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<script setup lang="ts">
import { computed, useAttrs, createStaticVNode, type PropType } from 'vue'
import { twMerge } from 'tailwind-merge'
import { outlookFallbackProp } from './utils.ts'
import { useOutlookFallback } from '../composables/useOutlookFallback'

defineOptions({ inheritAttrs: false })

const props = defineProps({
/**
* Classes to add to the `<body>` tag.
*/
bodyClass: {
type: String,
default: ''
},
/**
* Language code for the `lang` and `xml:lang` attributes.
*
* @default 'en'
*/
lang: {
type: String,
default: 'en'
},
/**
* Text direction.
*
* @default 'ltr'
*/
dir: {
type: String as PropType<'ltr' | 'rtl'>,
default: 'ltr'
},
/**
* Render an empty `<head>` before the main head element.
*
* This is a workaround for Yahoo! Mail on Android, which
* strips the first `<head>` element it finds.
*
* @default false
*/
doubleHead: {
type: [Boolean, String],
default: false
},
/**
* Accessible label for the email article wrapper.
*
* Used as the `aria-label` on the inner `<div role="article">`.
*
* @example 'Order confirmation'
*/
ariaLabel: {
type: String,
default: undefined
},
/**
* Toggle Outlook (MSO) and VML fallback markup for this
* component and all descendants.
*
* When `false`, skips MSO ghost tables, VML shapes,
* `xmlns:v`/`xmlns:o` attributes, and mso-specific CSS
* in all built-in components.
*
* @default true
*/
outlookFallback: outlookFallbackProp,
})

const outlookFallback = useOutlookFallback(props.outlookFallback)

const attrs = useAttrs()
const bodyMergedClass = computed(() => twMerge('m-0 p-0 size-full [word-break:break-word]', props.bodyClass))
const articleMergedClass = computed(() => twMerge('[font-size:max(16px,1rem)] font-inter', attrs.class as string))

const EmptyHead = () => createStaticVNode('<head></head>', 1)

const MsoHead = () => createStaticVNode(
`<!--[if mso]>
<style>
td,th,div,p,a,h1,h2,h3,h4,h5,h6 {font-family: "Segoe UI", sans-serif; mso-line-height-rule: exactly;}
.mso-break-all {word-break: break-all;}
</style>
<![endif]-->`,
1
)

const msoBody = `<!--[if mso]>
<xml>
<o:OfficeDocumentSettings>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
<w:WordDocument>
<w:DontUseAdvancedTypographyReadingMail />
</w:WordDocument>
</xml>
<![endif]-->`

const htmlXmlns = computed(() => outlookFallback ? {
'xmlns:v': 'urn:schemas-microsoft-com:vml',
'xmlns:o': 'urn:schemas-microsoft-com:office:office',
} : {})
</script>

<template>
<html :lang="lang" :dir="dir" v-bind="htmlXmlns">
<EmptyHead v-if="props.doubleHead === true || props.doubleHead === 'true'" />

<head>
<meta charset="utf-8">
<meta name="x-apple-disable-message-reformatting">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no, url=no">
<meta name="color-scheme" content="light dark">
<meta name="supported-color-schemes" content="light dark">
<MsoHead v-if="outlookFallback" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet" media="screen">
<style>
@import "@maizzle/tailwindcss";

img {
@apply max-w-full align-middle;
}

</style>
</head>

<body :xml:lang="outlookFallback ? lang : null" :class="bodyMergedClass">
<span v-if="outlookFallback" style="display: none" v-html="msoBody"></span>
<div
role="article"
aria-roledescription="email"
:aria-label="ariaLabel"
:lang="lang"
:dir="dir"
style="font-size: medium;"
:class="articleMergedClass">
<slot />
</div>
</body>

</html>
</template>
6 changes: 2 additions & 4 deletions src/commands/make/stubs/component.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
<script setup lang="ts">
defineProps({
//
})
<script setup>

</script>

<template>
Expand Down
6 changes: 1 addition & 5 deletions src/commands/make/stubs/config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { defineConfig } from '@maizzle/framework'

export default defineConfig({
css: {
purge: true,
inline: true,
shorthand: true,
},

})
39 changes: 0 additions & 39 deletions src/commands/make/stubs/layout.vue

This file was deleted.

2 changes: 1 addition & 1 deletion src/commands/make/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export default async function makeTemplate(filePath?: string) {
p.text({
message: 'Directory to place it in',
placeholder: './emails',
initialValue: './emails',
validate: value => {
if (!value) return 'Please enter a path.'
if (value[0] !== '.') return 'Please enter a relative path.'
},
}),
},
Expand Down
54 changes: 27 additions & 27 deletions src/commands/new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ export default async function newProject(starterArg?: string, dirArg?: string, o
p.text({
message: 'Where should we create your project?',
placeholder: './maizzle',
initialValue: './maizzle',
validate: value => {
if (!value) return 'Please enter a path.'
if (value[0] !== '.') return 'Please enter a relative path.'
if (existsSync(value)) return 'That directory already exists. Please enter a different path.'
},
}),
Expand Down Expand Up @@ -186,44 +186,44 @@ export default async function newProject(starterArg?: string, dirArg?: string, o
) as unknown as Project
}

const spinner = p.spinner()

spinner.start('Creating project')

const starter = starters.find(s => s.value === project.starter)
const source = starter ? starter.path : project.starter

await downloadTemplate(source.includes(':') ? source : `gh:${source}`, {
dir: project.path,
})

await rm(`${project.path}/.github`, {
recursive: true,
force: true
})

spinner.stop(`Created project in ${project.path}`)

if (project.install) {
try {
execSync(`${project.pm} --version`, { stdio: 'ignore' })
} catch {
p.log.error(`${project.pm} is not installed. Please install it first.`)
process.exit(1)
}

spinner.start('Installing dependencies')
const startTime = Date.now()

await installDependencies({
cwd: project.path,
silent: true,
packageManager: project.pm as any,
})

spinner.stop(`Installed dependencies ${color.gray((Date.now() - startTime) / 1000 + 's')}`)
}

await p.tasks([
{
title: 'Creating project',
task: async () => {
await downloadTemplate(source.includes(':') ? source : `gh:${source}`, {
dir: project.path,
})
await rm(`${project.path}/.github`, { recursive: true, force: true })
return `Created project in ${project.path}`
},
},
{
title: 'Installing dependencies',
enabled: project.install,
task: async () => {
const startTime = Date.now()
await installDependencies({
cwd: project.path,
silent: true,
packageManager: project.pm as any,
})
return `Installed dependencies ${color.gray((Date.now() - startTime) / 1000 + 's')}`
},
},
])

const pm = project.pm || 'npm'
const runCmd = pm === 'yarn' ? 'yarn dev' : `${pm} run dev`

Expand Down
Loading
Loading