refactor(ui): implement search and password type input

This commit is contained in:
upsiflu 2024-12-29 17:18:46 +01:00
parent 709a7be25e
commit f3da51bbe6
3 changed files with 176 additions and 45 deletions

View File

@ -1,35 +1,102 @@
<script setup lang="ts">
import { ref } from 'vue'
import { computed, ref, useAttrs } from 'vue'
import { useI18n } from 'vue-i18n';
import onKeyboardShortcut from '~/composables/onKeyboardShortcut';
const { icon, placeholder } = defineProps<{ icon?: string, placeholder?:string }>()
import Button from "~/components/ui/Button.vue"
import Layout from "~/components/ui/Layout.vue"
const { icon, placeholder, ...restProps } = defineProps<{
icon?: string,
placeholder?:string,
password?:true,
search?:true,
numeric?:true,
}>()
const isNumeric = restProps.numeric
const showPassword = ref(false)
onKeyboardShortcut('escape', () => showPassword.value = false)
// TODO: Accept fallback $attrs: `const fallthroughAttrs = useAttrs()`
const attributes = computed(() => ({
...(restProps.password && !showPassword.value? {type:'password'} : {}),
...(restProps.search? {type:'search'} : {}),
...(restProps.numeric? {type:'numeric'} : {}),
}))
const { t } = useI18n()
const model = defineModel<string|number>()
const input = ref()
// TODO(A11y): Add `inputmode="numeric" pattern="[0-9]*"` to input if model type is number:
// https://technology.blog.gov.uk/2020/02/24/why-the-gov-uk-design-system-team-changed-the-input-type-for-numbers/
</script>
<template>
<label
<Layout stack no-gap label
:class="{ 'has-icon': !!icon }"
class="funkwhale input"
>
>
<span v-if="$slots['label']" class="label">
<slot name="label" />
</span>
<input
v-bind="attributes"
v-model="model"
ref="input"
:placeholder="placeholder"
@click.stop
@blur="showPassword = false"
/>
<!-- Left side icon -->
<div v-if="icon" class="prefix">
<i :class="['bi', icon]" />
</div>
<input
v-bind="$attrs"
v-model="model"
ref="input"
:placeholder="placeholder"
@click.stop
/>
<div v-if="$slots['input-right']" class="input-right">
<slot name="input-right" />
<!-- Search -->
<div v-if="restProps.search" class="prefix">
<i class="bi bi-search" />
</div>
</label>
<!-- Right side -->
<div v-if="$slots['input-right']" class="input-right">
<span>
<slot name="input-right" />
</span>
</div>
<!-- Password -->
<button
v-if="restProps.password"
style="background:transparent; border:none; appearance:none;"
role="switch"
type="button"
@click="showPassword = !showPassword"
@blur="showPassword = false"
class="input-right show-password" title="toggle visibility"
>
<i class="bi bi-eye" />
</button>
<!-- Search -->
<Button
solid primary
v-if="restProps.search"
class="input-right search"
>
{{ t('components.Sidebar.link.search') }}
</Button>
</Layout>
</template>
<style lang="scss">

View File

@ -1,13 +1,7 @@
.funkwhale {
.funkwhale.input {
form label {
display: flex;
margin-bottom: 8px;
color: var(--form-label-color);
font-size: .92857143em;
font-weight: 700;
text-transform: none;
}
position: relative;
flex-grow: 1;
> input {
background-color: var(--fw-bg-color);
@ -60,37 +54,73 @@ form label {
--fw-bg-color: var(--fw-gray-800);
}
}
&.has-icon {
input {
padding-left: 36px;
}
}
}
.prefix,
.input-right {
display: flex;
&.has-icon > input {
padding-left: 36px;
}
> .label {
padding-bottom: 4px;
font-size:14px;
font-weight:600;
}
> .prefix,
> .input-right {
align-items: center;
font-size: 14px;
writing-mode: horizontal-tb;
color: var(--fw-placeholder-color);
}
& .button,
& .button:hover {
background-color: transparent !important;
border: none !important;
> .prefix {
position: absolute;
left: 0;
bottom: 0;
height: 40px;
min-width: 44px;
display: flex;
> i {
font-size:18px;
margin: auto;
}
}
.prefix {
width: 32px;
justify-content: center;
&:has(>.prefix)>input {
padding-left: 40px;
}
> .input-right {
position: absolute;
top: 0;
left: 4px;
bottom: 0;
width: 32px;
justify-content: center;
right: 0px;
bottom: 0px;
height: 40px;
min-width: 44px;
display: flex;
}
> .search {
> i {
font-size:18px;
}
&.button {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
> .show-password {
justify-content:center;
}
&:has(>.show-password)>input {
padding-right: 40px;
}
&:has(>.search)>input {
padding-right: 140px;
}
}

View File

@ -1,5 +1,8 @@
<script setup>
import Input from "~/components/ui/Input.vue"
import Button from "~/components/ui/Button.vue"
import Layout from "~/components/ui/Layout.vue"
import Spacer from "~/components/ui/layout/Spacer.vue"
</script>
# Input
@ -49,3 +52,34 @@ You can add a template on the right-hand side of the input to guide the user's i
suffix
</template>
</Input>
## Presets
### Search
<Input search />
### Password
<Layout flex no-gap style="align-items:flex-end">
<Spacer v
:size="80"
style="outline:1px solid red; align-self: baseline;"
/>
<Input>
<template #label>
User name
</template>
</Input>
</Layout>
<Layout flex no-gap style="align-items:flex-end">
<Spacer v
:size="80"
style="outline:1px solid red; align-self: baseline;"
/>
<Input password>
<template #label>
Password
</template>
</Input>
</Layout>