Skip to content

Commit 3f80994

Browse files
committed
adding layouts to the uikit
layouts provide simple, responsive ways to structure a view. the aim here is to provide common layouts to allow programmer to focus on the logic - added layouts - updates builts quizes and constent forms to use the new layouts - added initial docs
1 parent 4187568 commit 3f80994

16 files changed

Lines changed: 1336 additions & 959 deletions

File tree

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<script setup>
2+
import { ref, computed, onMounted } from 'vue'
3+
import { useClipboard } from '@vueuse/core'
4+
5+
const props = defineProps({
6+
name: {
7+
type: String,
8+
required: true
9+
},
10+
description: {
11+
type: String,
12+
default: ''
13+
},
14+
code: {
15+
type: String,
16+
required: true
17+
},
18+
component: {
19+
type: Object,
20+
required: true
21+
}
22+
})
23+
24+
const { copied, copy } = useClipboard()
25+
const tabValue = ref('preview')
26+
const resizableRef = ref()
27+
const currentSize = ref(100)
28+
29+
const resizeComponent = (percentage) => {
30+
currentSize.value = percentage
31+
if (resizableRef.value) {
32+
resizableRef.value.style.width = `${percentage}%`
33+
}
34+
}
35+
36+
const copyCode = () => {
37+
copy(props.code)
38+
}
39+
40+
onMounted(() => {
41+
resizableRef.value.style.width = '100%'
42+
})
43+
</script>
44+
45+
<template>
46+
<div class="component-viewer border border-gray-200 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-900">
47+
<!-- Header -->
48+
<div class="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800">
49+
<div class="flex items-center gap-4">
50+
<!-- Tabs -->
51+
<div class="flex items-center gap-1 bg-gray-200 dark:bg-gray-700 rounded-md p-1">
52+
<button
53+
@click="tabValue = 'preview'"
54+
:class="[
55+
'px-3 py-1.5 text-sm rounded-sm transition-colors',
56+
tabValue === 'preview' ? 'bg-white dark:bg-gray-900 shadow-sm text-gray-900 dark:text-gray-100' : 'text-gray-600 dark:text-gray-300 hover:bg-white/50 dark:hover:bg-gray-800/50'
57+
]"
58+
>
59+
Preview
60+
</button>
61+
<button
62+
@click="tabValue = 'code'"
63+
:class="[
64+
'px-3 py-1.5 text-sm rounded-sm transition-colors',
65+
tabValue === 'code' ? 'bg-white dark:bg-gray-900 shadow-sm text-gray-900 dark:text-gray-100' : 'text-gray-600 dark:text-gray-300 hover:bg-white/50 dark:hover:bg-gray-800/50'
66+
]"
67+
>
68+
Code
69+
</button>
70+
</div>
71+
72+
<!-- Description -->
73+
<div v-if="description" class="text-sm text-gray-600 dark:text-gray-400">
74+
{{ description }}
75+
</div>
76+
</div>
77+
78+
<!-- Controls -->
79+
<div class="flex items-center gap-2">
80+
<!-- Responsive controls -->
81+
<div class="flex items-center gap-1 border border-gray-200 dark:border-gray-600 rounded-md p-1">
82+
<button
83+
@click="resizeComponent(100)"
84+
:class="[
85+
'p-1.5 rounded-sm transition-colors',
86+
currentSize === 100 ? 'bg-gray-200 dark:bg-gray-600' : 'hover:bg-gray-100 dark:hover:bg-gray-700'
87+
]"
88+
title="Desktop"
89+
>
90+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
91+
<rect x="2" y="4" width="20" height="12" rx="2"/>
92+
<path d="M2 16h20"/>
93+
</svg>
94+
</button>
95+
<button
96+
@click="resizeComponent(768)"
97+
:class="[
98+
'p-1.5 rounded-sm transition-colors',
99+
currentSize === 768 ? 'bg-gray-200 dark:bg-gray-600' : 'hover:bg-gray-100 dark:hover:bg-gray-700'
100+
]"
101+
title="Tablet"
102+
>
103+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
104+
<rect x="5" y="2" width="14" height="20" rx="2"/>
105+
</svg>
106+
</button>
107+
<button
108+
@click="resizeComponent(375)"
109+
:class="[
110+
'p-1.5 rounded-sm transition-colors',
111+
currentSize === 375 ? 'bg-gray-200 dark:bg-gray-600' : 'hover:bg-gray-100 dark:hover:bg-gray-700'
112+
]"
113+
title="Mobile"
114+
>
115+
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
116+
<rect x="7" y="1" width="10" height="22" rx="2"/>
117+
</svg>
118+
</button>
119+
</div>
120+
121+
<!-- Copy button -->
122+
<button
123+
@click="copyCode"
124+
class="p-2 border border-gray-200 dark:border-gray-600 rounded-md hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
125+
title="Copy code"
126+
>
127+
<svg v-if="copied" class="w-4 h-4 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
128+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
129+
</svg>
130+
<svg v-else class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
131+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
132+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
133+
</svg>
134+
</button>
135+
</div>
136+
</div>
137+
138+
<!-- Content -->
139+
<div class="p-0">
140+
<!-- Preview -->
141+
<div v-show="tabValue === 'preview'" class="relative overflow-hidden">
142+
<div class="bg-gray-50 dark:bg-gray-800 p-8">
143+
<div
144+
ref="resizableRef"
145+
class="transition-all duration-300 ease-in-out mx-auto bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg p-6 shadow-sm"
146+
:style="{ maxWidth: currentSize === 100 ? '100%' : `${currentSize}px` }"
147+
>
148+
<component :is="component" />
149+
</div>
150+
</div>
151+
</div>
152+
153+
<!-- Code -->
154+
<div v-show="tabValue === 'code'" class="relative">
155+
<pre class="p-4 text-sm overflow-x-auto bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100"><code v-html="code"></code></pre>
156+
</div>
157+
</div>
158+
</div>
159+
</template>
160+
161+
<style scoped>
162+
pre {
163+
white-space: pre-wrap;
164+
word-wrap: break-word;
165+
}
166+
167+
code {
168+
font-family: 'Fira Code', 'Monaco', 'Cascadia Code', 'Roboto Mono', monospace;
169+
}
170+
</style>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<script setup>
2+
import { ref, h, defineComponent, computed } from 'vue'
3+
4+
// Simulate the TwoCol component from the uikit
5+
const TwoCol = defineComponent({
6+
name: 'TwoCol',
7+
props: {
8+
leftFirst: Boolean,
9+
leftWidth: {
10+
type: String,
11+
default: 'w-1/3'
12+
}
13+
},
14+
setup(props, { slots }) {
15+
const getResponsiveWidthClasses = (leftWidth) => {
16+
const widthMap = {
17+
'w-1/12': 'w-full lg:w-1/12',
18+
'w-1/6': 'w-full lg:w-1/6',
19+
'w-1/4': 'w-full lg:w-1/4',
20+
'w-1/3': 'w-full lg:w-1/3',
21+
'w-2/5': 'w-full lg:w-2/5',
22+
'w-1/2': 'w-full lg:w-1/2',
23+
'w-3/5': 'w-full lg:w-3/5',
24+
'w-2/3': 'w-full lg:w-2/3',
25+
'w-3/4': 'w-full lg:w-3/4',
26+
'w-4/5': 'w-full lg:w-4/5',
27+
'w-5/6': 'w-full lg:w-5/6',
28+
'w-11/12': 'w-full lg:w-11/12',
29+
}
30+
return widthMap[leftWidth] || 'w-full lg:w-1/3'
31+
}
32+
33+
const leftColumnClasses = computed(() => getResponsiveWidthClasses(props.leftWidth))
34+
35+
return () => h('div', {
36+
class: 'w-full select-none mx-auto text-left my-10'
37+
}, [
38+
h('div', {
39+
class: ['flex gap-6', props.leftFirst ? 'flex-col lg:flex-row' : 'flex-col-reverse lg:flex-row']
40+
}, [
41+
h('div', {
42+
class: leftColumnClasses.value
43+
}, slots.left?.()),
44+
h('div', {
45+
class: 'flex-1'
46+
}, slots.right?.())
47+
])
48+
])
49+
}
50+
})
51+
52+
const leftWidth = ref('w-1/3')
53+
</script>
54+
55+
<template>
56+
<div class="space-y-6">
57+
<!-- Controls -->
58+
<div class="flex gap-2 flex-wrap">
59+
<label class="text-sm font-medium">Left Width:</label>
60+
<select v-model="leftWidth" class="px-2 py-1 border rounded text-sm">
61+
<option value="w-1/4">w-1/4 (25%)</option>
62+
<option value="w-1/3">w-1/3 (33%)</option>
63+
<option value="w-2/5">w-2/5 (40%)</option>
64+
<option value="w-1/2">w-1/2 (50%)</option>
65+
<option value="w-3/5">w-3/5 (60%)</option>
66+
<option value="w-2/3">w-2/3 (67%)</option>
67+
</select>
68+
</div>
69+
70+
<!-- Example -->
71+
<TwoCol :left-width="leftWidth" left-first>
72+
<template #left>
73+
<div class="bg-blue-100 dark:bg-blue-900 p-4 rounded-lg">
74+
<h3 class="font-semibold mb-2">Left Column</h3>
75+
<p class="text-sm text-gray-600 dark:text-gray-300">
76+
This column's width is controlled by the <code>leftWidth</code> prop.
77+
Try resizing the browser or changing the width setting above.
78+
</p>
79+
</div>
80+
</template>
81+
<template #right>
82+
<div class="bg-green-100 dark:bg-green-900 p-4 rounded-lg">
83+
<h3 class="font-semibold mb-2">Right Column</h3>
84+
<p class="text-sm text-gray-600 dark:text-gray-300">
85+
This column automatically takes up the remaining space using <code>flex-1</code>.
86+
It will stack below the left column on mobile devices.
87+
</p>
88+
<div class="mt-3 space-y-2">
89+
<div class="bg-white dark:bg-gray-800 p-2 rounded text-xs">Content item 1</div>
90+
<div class="bg-white dark:bg-gray-800 p-2 rounded text-xs">Content item 2</div>
91+
<div class="bg-white dark:bg-gray-800 p-2 rounded text-xs">Content item 3</div>
92+
</div>
93+
</div>
94+
</template>
95+
</TwoCol>
96+
</div>
97+
</template>

docs/help.md

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,13 @@ guarantee of support. Effective use of this project assumes you know modern
55
[Javascript](https://javascript.info/) syntax, have some familiarity with typing
66
commands in a terminal program, git, [GitHub](https://github.com), and
77
understand basic concepts about web servers and web design. Smile is designed to
8-
make life easier **for programmers/developers**.
9-
10-
::: warning Wait, I thought you said this makes life fun and easy?
11-
12-
Yes. <SmileText/> makes common development tasks easier and more fun for people
13-
who are already programmers. It lower the amount of code you need to write to
14-
make a complex web experiment, test it, and deploy it online. Smile glues
15-
together many services that you would otherwise have to configure yourself.
16-
However, there are better packages and services for people looking for no-code
17-
solutions that avoid the need to program altogether including
18-
[Qualtrics](https://www.qualtrics.com/),
8+
make life easier **for programmers/developers**. There are better packages and
9+
services for people looking for no-code solutions that avoid the need to program
10+
altogether including [Qualtrics](https://www.qualtrics.com/),
1911
[SurveyMonkey](https://www.surveymonkey.com/), and
2012
[Google Forms](https://www.google.com/forms/about/).
2113

22-
:::
23-
24-
That all said, if you need help or are stuck we have collected some useful
25-
resources.
14+
If you need help or are stuck we have collected some useful resources.
2615

2716
## Documentation
2817

0 commit comments

Comments
 (0)