wip bsky client for the web & android bbell.vt3e.cat
at main 124 lines 2.4 kB view raw
1<script setup lang="ts"> 2import { useId, useSlots } from 'vue' 3 4defineProps<{ 5 label?: string 6 placeholder?: string 7 type?: 'text' | 'password' | 'email' | 'number' | 'search' 8 error?: string 9}>() 10 11const model = defineModel<string | number>() 12const id = useId() 13const slots = useSlots() 14</script> 15 16<template> 17 <div class="input-group"> 18 <label v-if="label" :for="id" class="label"> 19 {{ label }} 20 </label> 21 <div class="input-wrapper"> 22 <div v-if="slots.prefix" class="prefix-wrapper"> 23 <slot name="prefix"></slot> 24 </div> 25 <input 26 :id="id" 27 v-model="model" 28 :type="type || 'text'" 29 :placeholder="placeholder" 30 :class="{ input: true, 'has-prefix': !!slots.prefix, 'has-error': !!error }" 31 /> 32 </div> 33 <span v-if="error" class="error-text">{{ error }}</span> 34 </div> 35</template> 36 37<style scoped lang="scss"> 38.input-group { 39 display: flex; 40 flex-direction: column; 41 gap: 0.375rem; 42 width: 100%; 43 margin-bottom: 1rem; 44} 45 46.label { 47 font-size: 0.875rem; 48 font-weight: 600; 49 color: hsl(var(--text)); 50 margin-left: 0.125rem; 51} 52 53.input-wrapper { 54 position: relative; 55 width: 100%; 56 57 display: flex; 58 align-items: center; 59 60 border-radius: var(--radius-md); 61 border: 1px solid hsla(var(--surface2) / 0.5); 62 background-color: hsl(var(--surface0) / 0.3); 63 64 outline: 2px solid transparent; 65 outline-offset: 4px; 66 67 &:hover { 68 background-color: hsl(var(--surface0)); 69 border-color: hsl(var(--surface2)); 70 } 71 &:focus-within { 72 background-color: hsl(var(--base)); 73 outline-color: hsl(var(--accent)); 74 outline-offset: 2px; 75 } 76 &:has(.has-error) { 77 border-color: hsl(var(--red)); 78 color: hsl(var(--red)); 79 &:focus-visible { 80 box-shadow: 0 0 0 3px hsla(var(--red) / 0.15); 81 } 82 } 83} 84 85.input { 86 color: hsl(var(--text)); 87 font-size: 1rem; 88 font-family: inherit; 89 background: transparent; 90 border: none; 91 width: 100%; 92 padding: 0.75rem 1rem; 93 94 outline: none; 95 96 &.has-prefix { 97 padding-left: 0; 98 } 99 100 &:focus-visible { 101 outline: none; 102 } 103 104 &::placeholder { 105 color: hsl(var(--overlay0)); 106 } 107} 108 109.prefix-wrapper { 110 height: 100%; 111 display: flex; 112 align-items: center; 113 color: hsl(var(--overlay0)); 114 min-width: 2.5rem; 115 justify-content: center; 116} 117 118.error-text { 119 font-size: 0.75rem; 120 color: hsl(var(--red)); 121 font-weight: 600; 122 margin-left: 0.125rem; 123} 124</style>