2 changed files with 169 additions and 0 deletions
@ -0,0 +1,105 @@ |
|||
<script setup> |
|||
defineProps({ |
|||
type: { type: String, default: 'primary' }, |
|||
size: { type: String, default: 'medium' }, |
|||
disabled: { type: Boolean, default: false }, |
|||
block: { type: Boolean, default: false }, |
|||
loading: { type: Boolean, default: false } |
|||
}) |
|||
defineOptions({ name: 'SongButton' }) |
|||
</script> |
|||
|
|||
<template> |
|||
<button |
|||
class="song-btn" |
|||
:class="[`song-btn--${type}`, `song-btn--${size}`, { 'song-btn--block': block }]" |
|||
:disabled="disabled || loading" |
|||
:aria-busy="loading" |
|||
> |
|||
<i v-if="loading" class="song-btn__ink" aria-hidden="true" /> |
|||
<slot /> |
|||
</button> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.song-btn { |
|||
display: inline-flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
gap: 6px; |
|||
font-family: var(--song-font-sans); |
|||
border: 1px solid transparent; |
|||
border-radius: var(--song-radius-m); |
|||
cursor: pointer; |
|||
transition: background-color var(--song-dur-1) var(--song-ease), |
|||
color var(--song-dur-1) var(--song-ease), |
|||
border-color var(--song-dur-1) var(--song-ease); |
|||
user-select: none; |
|||
} |
|||
.song-btn--primary { |
|||
background: var(--song-btn-bg); |
|||
color: var(--song-btn-text); |
|||
} |
|||
.song-btn--primary:hover:not(:disabled) { |
|||
filter: brightness(1.06); |
|||
} |
|||
.song-btn--secondary { |
|||
background: transparent; |
|||
color: var(--song-primary); |
|||
border-color: var(--song-border-strong); |
|||
} |
|||
.song-btn--secondary:hover:not(:disabled) { |
|||
background: var(--song-primary-bg); |
|||
} |
|||
.song-btn--text { |
|||
background: transparent; |
|||
color: var(--song-primary); |
|||
} |
|||
.song-btn--text:hover:not(:disabled) { |
|||
background: var(--song-primary-bg); |
|||
} |
|||
.song-btn--danger { |
|||
background: transparent; |
|||
color: var(--song-danger); |
|||
border-color: var(--song-border-strong); |
|||
} |
|||
.song-btn--danger:hover:not(:disabled) { |
|||
background: var(--song-danger-bg); |
|||
} |
|||
.song-btn--small { |
|||
height: 28px; |
|||
padding: 0 12px; |
|||
font-size: 12px; |
|||
} |
|||
.song-btn--medium { |
|||
height: 34px; |
|||
padding: 0 18px; |
|||
font-size: 14px; |
|||
} |
|||
.song-btn--large { |
|||
height: 42px; |
|||
padding: 0 26px; |
|||
font-size: 15px; |
|||
font-family: var(--song-font-serif); |
|||
letter-spacing: 0.06em; |
|||
} |
|||
.song-btn--block { |
|||
width: 100%; |
|||
} |
|||
.song-btn:disabled { |
|||
opacity: 0.45; |
|||
cursor: not-allowed; |
|||
} |
|||
.song-btn__ink { |
|||
width: 9px; |
|||
height: 9px; |
|||
border-radius: 50%; |
|||
background: currentColor; |
|||
opacity: 0.75; |
|||
animation: song-btn-ink-pulse 1.6s var(--song-ease) infinite; |
|||
} |
|||
@keyframes song-btn-ink-pulse { |
|||
0%, 100% { transform: scale(0.55); opacity: 0.35; } |
|||
50% { transform: scale(0.95); opacity: 0.85; } |
|||
} |
|||
</style> |
|||
@ -0,0 +1,64 @@ |
|||
<script setup> |
|||
defineProps({ |
|||
label: { type: String, default: '' }, |
|||
modelValue: { type: [String, Number], default: '' }, |
|||
placeholder: { type: String, default: '' }, |
|||
type: { type: String, default: 'text' }, |
|||
required: { type: Boolean, default: false } |
|||
}) |
|||
defineEmits(['update:modelValue']) |
|||
defineOptions({ name: 'SongInput' }) |
|||
</script> |
|||
|
|||
<template> |
|||
<label class="song-field"> |
|||
<span v-if="label" class="song-field__label"> |
|||
{{ label }}<span v-if="required" class="song-field__req">*</span> |
|||
</span> |
|||
<input |
|||
class="song-field__input" |
|||
:type="type" |
|||
:value="modelValue" |
|||
:placeholder="placeholder" |
|||
@input="$emit('update:modelValue', $event.target.value)" |
|||
/> |
|||
</label> |
|||
</template> |
|||
|
|||
<style scoped> |
|||
.song-field { |
|||
display: block; |
|||
} |
|||
.song-field__label { |
|||
display: block; |
|||
margin-bottom: 6px; |
|||
font-size: 13px; |
|||
color: var(--song-text-secondary); |
|||
} |
|||
.song-field__req { |
|||
color: var(--song-danger); |
|||
margin-left: 2px; |
|||
} |
|||
.song-field__input { |
|||
width: 100%; |
|||
height: 34px; |
|||
padding: 0 12px; |
|||
font-family: var(--song-font-sans); |
|||
font-size: 14px; |
|||
color: var(--song-text); |
|||
background: var(--song-bg-elevated); |
|||
border: 1px solid var(--song-border); |
|||
border-radius: var(--song-radius-s); |
|||
transition: border-color var(--song-dur-1) var(--song-ease); |
|||
} |
|||
.song-field__input::placeholder { |
|||
color: var(--song-text-disabled); |
|||
} |
|||
.song-field__input:hover { |
|||
border-color: var(--song-border-strong); |
|||
} |
|||
.song-field__input:focus { |
|||
outline: none; |
|||
border-color: var(--song-primary); |
|||
} |
|||
</style> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue