diff options
Diffstat (limited to 'packages/frontend/src')
| -rw-r--r-- | packages/frontend/src/components/MkPreview.vue | 8 | ||||
| -rw-r--r-- | packages/frontend/src/components/MkRadio.vue | 136 | ||||
| -rw-r--r-- | packages/frontend/src/components/MkRadios.vue | 141 | ||||
| -rw-r--r-- | packages/frontend/src/pages/admin/ads.vue | 9 |
4 files changed, 119 insertions, 175 deletions
diff --git a/packages/frontend/src/components/MkPreview.vue b/packages/frontend/src/components/MkPreview.vue index c25f9ab0a9..c589cd9685 100644 --- a/packages/frontend/src/components/MkPreview.vue +++ b/packages/frontend/src/components/MkPreview.vue @@ -12,11 +12,6 @@ SPDX-License-Identifier: AGPL-3.0-only <MkSwitch v-model="flag" :class="$style.preview__content1__switch_button"> <span>Switch is now {{ flag ? 'on' : 'off' }}</span> </MkSwitch> - <div :class="$style.preview__content1__input"> - <MkRadio v-model="radio" value="misskey">Misskey</MkRadio> - <MkRadio v-model="radio" value="mastodon">Mastodon</MkRadio> - <MkRadio v-model="radio" value="pleroma">Pleroma</MkRadio> - </div> <div :class="$style.preview__content1__button"> <MkButton inline>This is</MkButton> <MkButton inline primary>the button</MkButton> @@ -40,15 +35,12 @@ import * as config from '@@/js/config.js'; import MkButton from '@/components/MkButton.vue'; import MkInput from '@/components/MkInput.vue'; import MkSwitch from '@/components/MkSwitch.vue'; -import MkTextarea from '@/components/MkTextarea.vue'; -import MkRadio from '@/components/MkRadio.vue'; import * as os from '@/os.js'; import { $i } from '@/i.js'; import { chooseDriveFile } from '@/utility/drive.js'; const text = ref(''); const flag = ref(true); -const radio = ref('misskey'); const mfm = ref(`Hello world! This is an @example mention. BTW you are @${$i ? $i.username : 'guest'}.\nAlso, here is ${config.url} and [example link](${config.url}). for more details, see https://example.com.\nAs you know #misskey is open-source software.`); const openDialog = async () => { diff --git a/packages/frontend/src/components/MkRadio.vue b/packages/frontend/src/components/MkRadio.vue deleted file mode 100644 index 19ba90052c..0000000000 --- a/packages/frontend/src/components/MkRadio.vue +++ /dev/null @@ -1,136 +0,0 @@ -<!-- -SPDX-FileCopyrightText: syuilo and misskey-project -SPDX-License-Identifier: AGPL-3.0-only ---> - -<template> -<div - v-adaptive-border - :class="[$style.root, { [$style.disabled]: disabled, [$style.checked]: checked }]" - :aria-checked="checked" - :aria-disabled="disabled" - role="checkbox" - @click="toggle" -> - <input - type="radio" - :disabled="disabled" - :class="$style.input" - > - <span :class="$style.button"> - <span></span> - </span> - <span :class="$style.label"><slot></slot></span> -</div> -</template> - -<script lang="ts" setup generic="T extends OptionValue | null"> -import { computed } from 'vue'; -import type { OptionValue } from '@/types/option-value.js'; - -const props = defineProps<{ - modelValue: T; - value: T; - disabled?: boolean; -}>(); - -const emit = defineEmits<{ - (ev: 'update:modelValue', value: T): void; -}>(); - -const checked = computed(() => props.modelValue === props.value); - -function toggle(): void { - if (props.disabled) return; - emit('update:modelValue', props.value); -} -</script> - -<style lang="scss" module> -.root { - position: relative; - display: inline-flex; - align-items: center; - text-align: left; - cursor: pointer; - padding: 8px 10px; - min-width: 60px; - background-color: var(--MI_THEME-panel); - background-clip: padding-box !important; - border: solid 1px var(--MI_THEME-panel); - border-radius: 6px; - font-size: 90%; - transition: all 0.2s; - user-select: none; - - &.disabled { - opacity: 0.6; - cursor: not-allowed !important; - } - - &:hover { - border-color: var(--MI_THEME-inputBorderHover) !important; - } - - &:focus-within { - outline: none; - box-shadow: 0 0 0 2px var(--MI_THEME-focus); - } - - &.checked { - background-color: var(--MI_THEME-accentedBg) !important; - border-color: var(--MI_THEME-accentedBg) !important; - color: var(--MI_THEME-accent); - cursor: default !important; - - > .button { - border-color: var(--MI_THEME-accent); - - &::after { - background-color: var(--MI_THEME-accent); - transform: scale(1); - opacity: 1; - } - } - } -} - -.input { - position: absolute; - width: 0; - height: 0; - opacity: 0; - margin: 0; -} - -.button { - position: relative; - display: inline-block; - width: 14px; - height: 14px; - background: none; - border: solid 2px var(--MI_THEME-inputBorder); - border-radius: 100%; - transition: inherit; - - &::after { - content: ''; - display: block; - position: absolute; - top: 3px; - right: 3px; - bottom: 3px; - left: 3px; - border-radius: 100%; - opacity: 0; - transform: scale(0); - transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); - } -} - -.label { - margin-left: 8px; - display: block; - cursor: pointer; -} -</style> diff --git a/packages/frontend/src/components/MkRadios.vue b/packages/frontend/src/components/MkRadios.vue index 43957a0673..e2210e858e 100644 --- a/packages/frontend/src/components/MkRadios.vue +++ b/packages/frontend/src/components/MkRadios.vue @@ -8,15 +8,27 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.label"> <slot name="label"></slot> </div> + <div :class="$style.body"> - <MkRadio + <div v-for="option in options" :key="getKey(option.value)" - v-model="model" - :disabled="option.disabled" - :value="option.value" + v-adaptive-border + :class="[$style.optionRoot, { [$style.disabled]: option.disabled, [$style.checked]: model === option.value }]" + :aria-checked="model === option.value" + :aria-disabled="option.disabled" + role="checkbox" + @click="toggle(option)" > - <div :class="[$style.optionContent, { [$style.checked]: model === option.value }]"> + <input + type="radio" + :disabled="option.disabled" + :class="$style.optionInput" + > + <span :class="$style.optionButton"> + <span></span> + </span> + <div :class="$style.optionContent"> <i v-if="option.icon" :class="[$style.optionIcon, option.icon]" :style="option.iconStyle"></i> <div> <slot v-if="option.slotId != null" :name="`option-${option.slotId as SlotNames}`"></slot> @@ -26,8 +38,9 @@ SPDX-License-Identifier: AGPL-3.0-only </template> </div> </div> - </MkRadio> + </div> </div> + <div :class="$style.caption"> <slot name="caption"></slot> </div> @@ -51,8 +64,6 @@ export type MkRadiosOption<T = OptionValue, S = string> = { </script> <script setup lang="ts" generic="const T extends MkRadiosOption"> -import MkRadio from './MkRadio.vue'; - defineProps<{ options: T[]; vertical?: boolean; @@ -61,18 +72,23 @@ defineProps<{ type SlotNames = NonNullable<T extends MkRadiosOption<any, infer U> ? U : never>; defineSlots<{ - label?: () => any; - caption?: () => any; + label?: () => void; + caption?: () => void; } & { - [K in `option-${SlotNames}`]: () => any; + [K in `option-${SlotNames}`]: () => void; }>(); const model = defineModel<T['value']>({ required: true }); function getKey(value: OptionValue): PropertyKey { - if (value === null) return 'null'; + if (value === null) return '___null___'; return value; } + +function toggle(o: MkRadiosOption): void { + if (o.disabled) return; + model.value = o.value; +} </script> <style lang="scss" module> @@ -102,29 +118,110 @@ function getKey(value: OptionValue): PropertyKey { } } +.vertical > .body { + flex-direction: column; +} + +.optionRoot { + position: relative; + display: inline-flex; + align-items: center; + text-align: left; + cursor: pointer; + padding: 8px 10px; + min-width: 60px; + background-color: var(--MI_THEME-panel); + background-clip: padding-box !important; + border: solid 1px var(--MI_THEME-panel); + border-radius: 6px; + font-size: 90%; + transition: all 0.2s; + user-select: none; + + &.disabled { + opacity: 0.6; + cursor: not-allowed !important; + } + + &:hover { + border-color: var(--MI_THEME-inputBorderHover) !important; + } + + &:focus-within { + outline: none; + box-shadow: 0 0 0 2px var(--MI_THEME-focus); + } + + &.checked { + background-color: var(--MI_THEME-accentedBg) !important; + border-color: var(--MI_THEME-accentedBg) !important; + color: var(--MI_THEME-accent); + cursor: default !important; + + .optionButton { + border-color: var(--MI_THEME-accent); + + &::after { + background-color: var(--MI_THEME-accent); + transform: scale(1); + opacity: 1; + } + } + + .optionCaption { + color: color(from var(--MI_THEME-accent) srgb r g b / 0.75); + } + } +} + +.optionInput { + position: absolute; + width: 0; + height: 0; + opacity: 0; + margin: 0; +} + +.optionButton { + position: relative; + display: inline-block; + width: 14px; + height: 14px; + background: none; + border: solid 2px var(--MI_THEME-inputBorder); + border-radius: 100%; + transition: inherit; + + &::after { + content: ''; + display: block; + position: absolute; + top: 3px; + right: 3px; + bottom: 3px; + left: 3px; + border-radius: 100%; + opacity: 0; + transform: scale(0); + transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + } +} + .optionContent { display: flex; align-items: center; gap: 6px; + margin-left: 8px; } .optionCaption { font-size: 0.85em; padding: 2px 0 0 0; color: color(from var(--MI_THEME-fg) srgb r g b / 0.75); -} - -.optionContent.checked { - .optionCaption { - color: color(from var(--MI_THEME-accent) srgb r g b / 0.75); - } + transition: all 0.2s; } .optionIcon { flex-shrink: 0; } - -.vertical > .body { - flex-direction: column; -} </style> diff --git a/packages/frontend/src/pages/admin/ads.vue b/packages/frontend/src/pages/admin/ads.vue index e06ea50453..0efd1a2e28 100644 --- a/packages/frontend/src/pages/admin/ads.vue +++ b/packages/frontend/src/pages/admin/ads.vue @@ -33,15 +33,6 @@ SPDX-License-Identifier: AGPL-3.0-only <template #label>Form</template> </MkRadios> - <!-- - <div style="margin: 32px 0;"> - {{ i18n.ts.priority }} - <MkRadio v-model="ad.priority" value="high">{{ i18n.ts.high }}</MkRadio> - <MkRadio v-model="ad.priority" value="middle">{{ i18n.ts.middle }}</MkRadio> - <MkRadio v-model="ad.priority" value="low">{{ i18n.ts.low }}</MkRadio> - </div> - --> - <FormSplit> <MkInput v-model="ad.ratio" type="number"> <template #label>{{ i18n.ts.ratio }}</template> |