Skip to content

Commit b21bc79

Browse files
authored
docs(playground): add airbnb demo (#153)
1 parent 2c9e6e9 commit b21bc79

10 files changed

Lines changed: 355 additions & 14 deletions

File tree

docs/app/components/Playground.vue

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@ import mermaid from '@comark/nuxt/plugins/mermaid'
88
import jsonRender from '@comark/nuxt/plugins/json-render'
99
import footnotes from '@comark/nuxt/plugins/footnotes'
1010
import punctuation from '@comark/nuxt/plugins/punctuation'
11-
import breaks from '@comark/vue/plugins/breaks'
11+
import breaks from '@comark/nuxt/plugins/breaks'
1212
1313
import { renderMarkdown } from 'comark/render'
1414
import { Splitpanes, Pane } from 'splitpanes'
15-
import { defaultMarkdown } from '~/constants'
15+
import { airbnbMarkdown, playgroundExamples } from '~/constants'
16+
import PropertyGallery from '~/components/playground/PropertyGallery.vue'
17+
import RatingBar from '~/components/playground/RatingBar.vue'
18+
import HostInfo from '~/components/playground/HostInfo.vue'
19+
import Facility from '~/components/playground/Facility.vue'
20+
import TwoColumn from '~/components/playground/TwoColumn.vue'
21+
import BookingCard from '~/components/playground/BookingCard.vue'
1622
import { useLocalStorage, watchDebounced } from '@vueuse/core'
1723
import type { ComarkTree, ComarkPlugin } from 'comark'
1824
import VueJsonPretty from 'vue-json-pretty'
@@ -21,7 +27,12 @@ const props = defineProps<{
2127
compact?: boolean
2228
}>()
2329
24-
const markdown = ref<string>(defaultMarkdown.trim())
30+
const selectedExample = ref('airbnb')
31+
const currentExample = computed(() =>
32+
playgroundExamples.find(e => e.value === selectedExample.value) ?? playgroundExamples[0]!,
33+
)
34+
35+
const markdown = ref<string>(airbnbMarkdown.trim())
2536
const tree = ref<ComarkTree | null>(null)
2637
const parseTime = ref<number>(0)
2738
const nodeCount = ref<number>(0)
@@ -125,7 +136,7 @@ const parseOptionDefs = [
125136
126137
const activePlugins = computed<ComarkPlugin[]>(() =>
127138
pluginDefs
128-
.filter(p => pluginToggles.value[p.key])
139+
.filter(p => pluginToggles.value[p.key as keyof typeof pluginToggles.value])
129140
.map(p => p.factory()),
130141
)
131142
@@ -195,15 +206,19 @@ onMounted(() => {
195206
nextTick(() => parseMarkdown())
196207
})
197208
209+
watch(selectedExample, () => {
210+
markdown.value = currentExample.value.content.trim()
211+
})
212+
198213
function resetComark(): void {
199-
markdown.value = defaultMarkdown.trim()
214+
markdown.value = currentExample.value.content.trim()
200215
}
201216
202217
const formattedOutput = ref<string>('')
203218
204-
watch(tree, async (t: ComarkTree | null) => {
205-
formattedOutput.value = t ? await renderMarkdown(t) : ''
206-
}, { immediate: true })
219+
watchEffect(async () => {
220+
formattedOutput.value = tree.value ? await renderMarkdown(tree.value as any) : ''
221+
})
207222
208223
const formattedOutputModel = computed({
209224
get: () => formattedOutput.value,
@@ -228,12 +243,20 @@ const isMatch = computed(() =>
228243
>
229244
<div class="h-full flex flex-col">
230245
<div class="shrink-0 flex items-center gap-2 px-3 h-9 border-b border-default bg-default">
246+
<USelect
247+
v-if="!compact"
248+
v-model="selectedExample"
249+
:items="playgroundExamples"
250+
size="xs"
251+
color="neutral"
252+
variant="ghost"
253+
class="w-32"
254+
/>
231255
<UTooltip
232-
v-if="markdown !== defaultMarkdown.trim()"
233-
text="Reset to default content"
256+
v-if="markdown !== currentExample.content.trim()"
257+
text="Reset to example"
234258
>
235259
<UButton
236-
:disabled="markdown === defaultMarkdown.trim()"
237260
size="xs"
238261
color="neutral"
239262
variant="ghost"
@@ -279,7 +302,7 @@ const isMatch = computed(() =>
279302
v-for="plugin in pluginDefs"
280303
:key="plugin.key"
281304
class="flex items-center gap-2.5 w-full px-2 py-1.5 rounded-md text-sm hover:bg-elevated transition-colors"
282-
@click="pluginToggles[plugin.key] = !pluginToggles[plugin.key] as any"
305+
@click="pluginToggles[plugin.key] = !pluginToggles[plugin.key]"
283306
>
284307
<UIcon
285308
:name="plugin.icon"
@@ -432,7 +455,7 @@ const isMatch = computed(() =>
432455
>
433456
<ComarkDocsRenderer
434457
:tree="tree"
435-
:components="{ Binding }"
458+
:components="{ Binding, PropertyGallery, RatingBar, HostInfo, Facility, TwoColumn, BookingCard }"
436459
/>
437460
</div>
438461
</UScrollArea>
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<script setup lang="ts">
2+
defineProps<{
3+
title: string
4+
cta: string
5+
}>()
6+
</script>
7+
8+
<template>
9+
<div class="not-prose rounded-xl border border-muted p-5 shadow-lg">
10+
<p class="mb-4 text-base font-semibold text-highlighted">
11+
{{ title }}
12+
</p>
13+
14+
<div class="mb-3 overflow-hidden rounded-lg border border-muted">
15+
<div class="grid grid-cols-2 divide-x divide-muted">
16+
<div class="p-3">
17+
<p class="text-[10px] font-semibold uppercase tracking-wider text-muted">
18+
Check-in
19+
</p>
20+
<p class="text-sm text-dimmed">
21+
Add date
22+
</p>
23+
</div>
24+
<div class="p-3">
25+
<p class="text-[10px] font-semibold uppercase tracking-wider text-muted">
26+
Checkout
27+
</p>
28+
<p class="text-sm text-dimmed">
29+
Add date
30+
</p>
31+
</div>
32+
</div>
33+
<div class="flex items-center justify-between border-t border-muted p-3">
34+
<div>
35+
<p class="text-[10px] font-semibold uppercase tracking-wider text-muted">
36+
Guests
37+
</p>
38+
<p class="text-sm text-highlighted">
39+
1 guest
40+
</p>
41+
</div>
42+
<UIcon
43+
name="i-lucide-chevron-down"
44+
class="size-4 text-muted"
45+
/>
46+
</div>
47+
</div>
48+
49+
<UButton
50+
block
51+
color="primary"
52+
:label="cta"
53+
/>
54+
55+
<p class="mt-3 text-center text-xs text-muted">
56+
You won't be charged yet
57+
</p>
58+
</div>
59+
</template>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<script setup lang="ts">
2+
defineProps<{
3+
icon: string
4+
}>()
5+
</script>
6+
7+
<template>
8+
<div class="not-prose flex items-start gap-4 py-3">
9+
<UIcon
10+
:name="icon"
11+
class="mt-0.5 size-6 shrink-0 text-highlighted"
12+
/>
13+
<div>
14+
<div class="text-sm font-medium text-highlighted [&>p]:m-0">
15+
<slot name="title" />
16+
</div>
17+
<div class="text-sm text-muted [&>p]:m-0">
18+
<slot name="description" />
19+
</div>
20+
</div>
21+
</div>
22+
</template>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script setup lang="ts">
2+
defineProps<{
3+
name: string
4+
badge?: string
5+
duration?: string
6+
}>()
7+
</script>
8+
9+
<template>
10+
<div class="not-prose flex items-center gap-3 py-5">
11+
<div class="flex size-11 shrink-0 items-center justify-center rounded-full bg-linear-to-br from-primary-200 to-primary-400 text-sm font-semibold text-white dark:from-primary-700 dark:to-primary-500">
12+
{{ name[0] }}
13+
</div>
14+
<div>
15+
<p class="text-sm font-semibold text-highlighted">
16+
Hosted by {{ name }}
17+
</p>
18+
<p class="text-xs text-muted">
19+
<span v-if="badge">{{ badge }}</span>
20+
<span
21+
v-if="badge && duration"
22+
class="mx-1"
23+
>·</span>
24+
<span v-if="duration">{{ duration }}</span>
25+
</p>
26+
</div>
27+
</div>
28+
</template>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<template>
2+
<div class="not-prose relative my-6 grid h-72 grid-cols-[2fr_1fr_1fr] grid-rows-2 gap-2 overflow-hidden rounded-xl">
3+
<div class="row-span-2 overflow-hidden [&_img]:block [&_img]:size-full [&_img]:object-cover">
4+
<slot name="main" />
5+
</div>
6+
<div class="col-span-2 row-span-2 grid grid-cols-2 grid-rows-2 gap-2 *:overflow-hidden [&>p]:m-0 [&_img]:block [&_img]:size-full [&_img]:object-cover">
7+
<slot name="thumbnails" />
8+
</div>
9+
<button class="absolute bottom-3 right-3 z-10 flex items-center gap-1.5 rounded-lg border border-neutral-300 bg-white px-2.5 py-1.5 text-xs font-medium shadow-sm dark:border-neutral-600 dark:bg-neutral-800">
10+
<UIcon
11+
name="i-lucide-grid-2x2"
12+
class="size-3"
13+
/>
14+
Show all photos
15+
</button>
16+
</div>
17+
</template>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<script setup lang="ts">
2+
defineProps<{
3+
rating: string
4+
reviews: string | number
5+
}>()
6+
</script>
7+
8+
<template>
9+
<div class="not-prose my-4 flex items-center gap-5 rounded-xl border border-muted px-5 py-4">
10+
<div class="flex min-w-0 flex-1 items-start gap-3">
11+
<div class="flex shrink-0 -space-x-2">
12+
<div class="flex size-8 items-center justify-center rounded-full bg-primary-100 dark:bg-primary-900">
13+
<UIcon
14+
name="i-lucide-user"
15+
class="size-4 text-primary"
16+
/>
17+
</div>
18+
<div class="flex size-8 items-center justify-center rounded-full border-2 border-white bg-primary-100 dark:border-neutral-900 dark:bg-primary-900">
19+
<UIcon
20+
name="i-lucide-user"
21+
class="size-4 text-primary"
22+
/>
23+
</div>
24+
</div>
25+
<div class="min-w-0">
26+
<p class="text-sm font-semibold text-highlighted">
27+
Guest favorite
28+
</p>
29+
<p class="text-xs leading-snug text-muted">
30+
One of the most loved homes on Airbnb, according to guests
31+
</p>
32+
</div>
33+
</div>
34+
35+
<div class="h-10 w-px shrink-0 bg-muted" />
36+
37+
<div class="shrink-0 text-center">
38+
<p class="text-xl font-bold text-highlighted">
39+
{{ rating }}
40+
</p>
41+
<div class="mt-0.5 flex justify-center gap-0.5">
42+
<UIcon
43+
v-for="i in 5"
44+
:key="i"
45+
name="i-lucide-star"
46+
class="size-3 text-primary"
47+
/>
48+
</div>
49+
</div>
50+
51+
<div class="h-10 w-px shrink-0 bg-muted" />
52+
53+
<div class="shrink-0 text-center">
54+
<p class="text-xl font-bold text-highlighted">
55+
{{ reviews }}
56+
</p>
57+
<p class="text-xs text-muted">
58+
Reviews
59+
</p>
60+
</div>
61+
</div>
62+
</template>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<template>
2+
<div class="not-prose mt-6 grid grid-cols-1 gap-8 lg:grid-cols-[1fr_320px]">
3+
<div class="prose prose-sm max-w-none dark:prose-invert prose-headings:no-underline">
4+
<slot name="left" />
5+
</div>
6+
<div class="self-start lg:sticky lg:top-4">
7+
<slot name="right" />
8+
</div>
9+
</div>
10+
</template>

0 commit comments

Comments
 (0)