wip bsky client for the web & android
bbell.vt3e.cat
1<script setup lang="ts">
2withDefaults(
3 defineProps<{
4 variant?: 'primary' | 'secondary' | 'ghost' | 'danger' | 'subtle' | 'subtle-alt' | 'text'
5 size?: 'sm' | 'md' | 'lg'
6 icon?: boolean
7 block?: boolean
8 loading?: boolean
9 disabled?: boolean
10 flat?: boolean
11 type?: 'button' | 'submit' | 'reset'
12 pill?: boolean
13 }>(),
14 {
15 variant: 'primary',
16 size: 'md',
17 type: 'button',
18 disabled: false,
19 },
20)
21
22const emit = defineEmits<{
23 (e: 'click', event: MouseEvent): void
24}>()
25</script>
26
27<template>
28 <button
29 :type="type"
30 class="th-btn"
31 :class="[
32 `variant-${variant}`,
33 `size-${size}`,
34 {
35 'is-icon': icon,
36 'is-block': block,
37 'is-loading': loading,
38 'is-flat': flat,
39 'is-pill': pill,
40 },
41 ]"
42 :disabled="disabled || loading"
43 @click.stop="emit('click', $event)"
44 >
45 <span v-if="loading" class="spinner"></span>
46 <slot v-else />
47 </button>
48</template>
49
50<style scoped>
51.th-btn {
52 display: inline-flex;
53 align-items: center;
54 justify-content: center;
55 gap: 0.5rem;
56 border: 1px solid transparent;
57 border-radius: var(--radius-sm);
58 font-family: inherit;
59 font-weight: 600;
60 line-height: 1;
61 cursor: pointer;
62 position: relative;
63 overflow: hidden;
64
65 &.is-flat {
66 border: none !important;
67 }
68 &.is-pill {
69 border-radius: 10rem !important;
70 }
71
72 &:disabled {
73 opacity: 0.5;
74 cursor: not-allowed;
75 pointer-events: none;
76 }
77
78 &.is-block {
79 width: 100%;
80 display: flex;
81 }
82
83 background-color: hsla(var(--bg-colour) / 0.9);
84 color: hsl(var(--text-colour));
85 /*border-color: hsla(var(--border-colour) / 0.2);*/
86
87 &:not(.variant-text) {
88 &:hover:not(:disabled) {
89 background-color: hsla(var(--bg-colour) / 1);
90 /*border-color: hsla(var(--border-colour) / 0.5);*/
91 }
92
93 &:active:not(:disabled) {
94 background-color: hsla(var(--bg-colour) / 0.7);
95 /*border-color: hsla(var(--border-colour) / 0.5);*/
96 }
97 }
98}
99
100/* Sizes */
101.size-sm {
102 font-size: 0.75rem;
103 padding: 0.375rem 0.75rem;
104 &.is-icon {
105 padding: 0;
106 width: 2rem;
107 height: 2rem;
108 }
109}
110.size-md {
111 font-size: 0.875rem;
112 padding: 0.625rem 1.25rem;
113 &.is-icon {
114 padding: 0;
115 width: 2.5rem;
116 height: 2.5rem;
117 }
118}
119.size-lg {
120 font-size: 1rem;
121 padding: 0.875rem 1.75rem;
122 &.is-icon {
123 padding: 0;
124 width: 3rem;
125 height: 3rem;
126 }
127}
128
129.th-btn.variant-primary {
130 --bg-colour: var(--accent);
131 --text-colour: var(--base);
132 --border-colour: var(--accent);
133}
134
135.th-btn.variant-secondary {
136 --bg-colour: var(--surface0);
137 --text-colour: var(--text);
138 --border-colour: var(--surface2);
139}
140
141.th-btn.variant-subtle {
142 --bg-colour: var(--accent);
143 --text-colour: var(--accent);
144 --border-colour: var(--accent);
145
146 border-color: hsla(var(--accent) / 0.05);
147 background-color: hsla(var(--accent) / 0.05);
148
149 &:hover:not(:disabled) {
150 background-color: hsla(var(--accent) / 0.15);
151 border-color: hsla(var(--accent) / 0.1);
152 }
153 &:active:not(:disabled) {
154 background-color: hsla(var(--accent) / 0.1);
155 border-color: hsla(var(--accent) / 0.1);
156 }
157}
158
159.th-btn.variant-subtle-alt {
160 border-color: transparent;
161 background-color: hsla(var(--overlay0) / 0.1);
162 color: hsl(var(--subtext0));
163
164 &:hover:not(:disabled) {
165 background-color: hsla(var(--overlay0) / 0.15);
166 border-color: transparent;
167 }
168 &:active:not(:disabled) {
169 background-color: hsla(var(--overlay0) / 0.075);
170 border-color: transparent;
171 }
172}
173
174.th-btn.variant-ghost {
175 --bg-colour: transparent;
176 --text-colour: var(--subtext0);
177 --border-colour: transparent;
178
179 border-color: transparent;
180
181 &:hover:not(:disabled) {
182 background-color: hsla(var(--surface1) / 0.35);
183 border-color: hsla(var(--surface2) / 0);
184 }
185 &:active:not(:disabled) {
186 background-color: hsla(var(--surface1) / 0.25);
187 border-color: hsla(var(--surface2) / 0);
188 }
189}
190
191.variant-danger {
192 --background-colour: var(--red);
193 --text-colour: var(--red);
194 --border-colour: var(--red);
195
196 border-color: hsla(var(--red) / 0.05);
197 background-color: hsla(var(--red) / 0.25);
198
199 &:hover:not(:disabled) {
200 background-color: hsla(var(--red) / 0.4);
201 border-color: hsla(var(--red) / 0.3);
202 }
203 &:active:not(:disabled) {
204 background-color: hsla(var(--red) / 0.3);
205 border-color: hsla(var(--red) / 0.3);
206 }
207}
208
209.variant-text {
210 background-color: none;
211 color: hsl(var(--text-colour));
212 border-color: transparent;
213
214 &:hover {
215 color: hsla(var(--text) / 0.9);
216 }
217 &:active {
218 color: hsla(var(--text) / 0.75);
219 }
220}
221
222/* Spinner */
223.spinner {
224 width: 1em;
225 height: 1em;
226 border: 2px solid currentColor;
227 border-right-color: transparent;
228 border-radius: 50%;
229 animation: spin 0.75s linear infinite;
230}
231@keyframes spin {
232 to {
233 transform: rotate(360deg);
234 }
235}
236</style>