nanka iroiro (#6853)

* wip

* Update maps.ts

* wip

* wip

* wip

* wip

* Update base.vue

* wip

* wip

* wip

* wip

* Update link.vue

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update privacy.vue

* wip

* wip

* wip

* wip

* Update range.vue

* wip

* wip

* wip

* wip

* Update profile.vue

* wip

* Update a.vue

* Update index.vue

* wip

* Update sidebar.vue

* wip

* wip

* Update account-info.vue

* Update a.vue

* wip

* wip

* Update sounds.vue

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Update account-info.vue

* Update account-info.vue

* wip

* wip

* wip

* Update d-persimmon.json5

* wip
This commit is contained in:
syuilo
2020-11-25 21:31:34 +09:00
committed by GitHub
parent 7660839e40
commit 0144408500
106 changed files with 4489 additions and 1734 deletions

View File

@ -1,6 +1,6 @@
<template>
<XModalWindow ref="dialog"
:width="400"
:width="450"
:can-close="false"
:with-ok-button="true"
:ok-button-disabled="false"
@ -12,42 +12,61 @@
<template #header>
{{ title }}
</template>
<div class="xkpnjxcv _section">
<label v-for="item in Object.keys(form).filter(item => !form[item].hidden)" :key="item">
<MkInput v-if="form[item].type === 'number'" v-model:value="values[item]" type="number" :step="form[item].step || 1">
<FormBase class="xkpnjxcv">
<template v-for="item in Object.keys(form).filter(item => !form[item].hidden)">
<FormInput v-if="form[item].type === 'number'" v-model:value="values[item]" type="number" :step="form[item].step || 1">
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span>
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
</MkInput>
<MkInput v-else-if="form[item].type === 'string' && !form[item].multiline" v-model:value="values[item]" type="text">
</FormInput>
<FormInput v-else-if="form[item].type === 'string' && !form[item].multiline" v-model:value="values[item]" type="text">
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span>
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
</MkInput>
<MkTextarea v-else-if="form[item].type === 'string' && form[item].multiline" v-model:value="values[item]">
</FormInput>
<FormTextarea v-else-if="form[item].type === 'string' && form[item].multiline" v-model:value="values[item]">
<span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span>
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
</MkTextarea>
<MkSwitch v-else-if="form[item].type === 'boolean'" v-model:value="values[item]">
</FormTextarea>
<FormSwitch v-else-if="form[item].type === 'boolean'" v-model:value="values[item]">
<span v-text="form[item].label || item"></span>
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
</MkSwitch>
</label>
</div>
</FormSwitch>
<FormSelect v-else-if="form[item].type === 'enum'" v-model:value="values[item]">
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span></template>
<option v-for="item in form[item].enum" :value="item.value" :key="item.value">{{ item.label }}</option>
</FormSelect>
<FormRange v-else-if="form[item].type === 'range'" v-model:value="values[item]" :min="form[item].mim" :max="form[item].max" :step="form[item].step">
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $t('optional') }})</span></template>
<template v-if="form[item].description" #desc>{{ form[item].description }}</template>
</FormRange>
<FormButton v-else-if="form[item].type === 'button'" @click="form[item].action($event, values)">
<span v-text="form[item].content || item"></span>
</FormButton>
</template>
</FormBase>
</XModalWindow>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XModalWindow from '@/components/ui/modal-window.vue';
import MkInput from './ui/input.vue';
import MkTextarea from './ui/textarea.vue';
import MkSwitch from './ui/switch.vue';
import FormBase from './form/base.vue';
import FormInput from './form/input.vue';
import FormTextarea from './form/textarea.vue';
import FormSwitch from './form/switch.vue';
import FormSelect from './form/select.vue';
import FormRange from './form/range.vue';
import FormButton from './form/button.vue';
export default defineComponent({
components: {
XModalWindow,
MkInput,
MkTextarea,
MkSwitch,
FormBase,
FormInput,
FormTextarea,
FormSwitch,
FormSelect,
FormRange,
FormButton,
},
props: {
@ -95,12 +114,6 @@ export default defineComponent({
<style lang="scss" scoped>
.xkpnjxcv {
> label {
display: block;
&:not(:last-child) {
margin-bottom: 32px;
}
}
}
</style>

View File

@ -0,0 +1,56 @@
<template>
<div class="rbusrurv" :class="{ wide: forceWide }" v-size="{ max: [400] }">
<slot></slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
props: {
forceWide: {
type: Boolean,
required: false,
default: false,
}
}
});
</script>
<style lang="scss" scoped>
.rbusrurv {
line-height: 1.4em;
background: var(--bg);
padding: 32px;
&:not(.wide).max-width_400px {
padding: 32px 0;
> ::v-deep(*) {
._formPanel {
border: solid 0.5px var(--divider);
border-radius: 0;
border-left: none;
border-right: none;
}
._form_group {
> * {
&:not(:first-child) {
&._formPanel, ._formPanel {
border-top: none;
}
}
&:not(:last-child) {
&._formPanel, ._formPanel {
border-bottom: solid 0.5px var(--divider);
}
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,81 @@
<template>
<div class="yzpgjkxe _formItem">
<div class="_formLabel"><slot name="label"></slot></div>
<button class="main _button _formPanel _formClickable" :class="{ center, primary, danger }">
<slot></slot>
<div class="suffix">
<slot name="suffix"></slot>
<div class="icon">
<slot name="suffixIcon"></slot>
</div>
</div>
</button>
<div class="_formCaption"><slot name="desc"></slot></div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import './form.scss';
export default defineComponent({
props: {
primary: {
type: Boolean,
required: false,
default: false,
},
danger: {
type: Boolean,
required: false,
default: false,
},
disabled: {
type: Boolean,
required: false,
default: false,
},
center: {
type: Boolean,
required: false,
default: true,
}
},
});
</script>
<style lang="scss" scoped>
.yzpgjkxe {
> .main {
display: flex;
width: 100%;
box-sizing: border-box;
padding: 14px 16px;
text-align: left;
align-items: center;
&.center {
display: block;
text-align: center;
}
&.primary {
color: var(--accent);
}
&.danger {
color: #ff2a2a;
}
> .suffix {
display: inline-flex;
margin-left: auto;
opacity: 0.7;
> .icon {
margin-left: 1em;
}
}
}
}
</style>

View File

@ -0,0 +1,34 @@
._formPanel {
background: var(--panel);
border-radius: var(--radius);
&._formClickable {
&:hover {
background: var(--panelHighlight);
}
}
}
._formLabel {
font-size: 80%;
padding: 0 16px 8px 16px;
&:empty {
display: none;
}
}
._formCaption {
font-size: 80%;
padding: 8px 16px 0 16px;
&:empty {
display: none;
}
}
._formItem {
& + ._formItem {
margin-top: 24px;
}
}

View File

@ -0,0 +1,42 @@
<template>
<div class="vrtktovg _formItem" v-size="{ max: [500] }">
<div class="_formLabel"><slot name="label"></slot></div>
<div class="main _form_group">
<slot></slot>
</div>
<div class="_formCaption"><slot name="caption"></slot></div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
});
</script>
<style lang="scss" scoped>
.vrtktovg {
> .main {
> ::v-deep(*) {
margin: 0;
&:not(:first-child) {
&._formPanel, ._formPanel {
border-top: none;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
&:not(:last-child) {
&._formPanel, ._formPanel {
border-bottom: solid 0.5px var(--divider);
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
}
}
}
</style>

View File

@ -0,0 +1,306 @@
<template>
<div class="ztzhwixg _formItem" :class="{ inline, disabled }">
<div class="_formLabel"><slot></slot></div>
<div class="icon" ref="icon"><slot name="icon"></slot></div>
<div class="input _formPanel">
<div class="prefix" ref="prefixEl"><slot name="prefix"></slot></div>
<input v-if="debounce" ref="inputEl"
v-debounce="500"
:type="type"
v-model.lazy="v"
:disabled="disabled"
:required="required"
:readonly="readonly"
:placeholder="placeholder"
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
:step="step"
@focus="focused = true"
@blur="focused = false"
@keydown="onKeydown($event)"
@input="onInput"
:list="id"
>
<input v-else ref="inputEl"
:type="type"
v-model="v"
:disabled="disabled"
:required="required"
:readonly="readonly"
:placeholder="placeholder"
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
:step="step"
@focus="focused = true"
@blur="focused = false"
@keydown="onKeydown($event)"
@input="onInput"
:list="id"
>
<datalist :id="id" v-if="datalist">
<option v-for="data in datalist" :value="data"/>
</datalist>
<div class="suffix" ref="suffixEl"><slot name="suffix"></slot></div>
</div>
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $t('save') }}</button>
<div class="_formCaption"><slot name="desc"></slot></div>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
import debounce from 'v-debounce';
import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
import './form.scss';
export default defineComponent({
directives: {
debounce
},
props: {
value: {
required: false
},
type: {
type: String,
required: false
},
required: {
type: Boolean,
required: false
},
readonly: {
type: Boolean,
required: false
},
disabled: {
type: Boolean,
required: false
},
pattern: {
type: String,
required: false
},
placeholder: {
type: String,
required: false
},
autofocus: {
type: Boolean,
required: false,
default: false
},
autocomplete: {
required: false
},
spellcheck: {
required: false
},
step: {
required: false
},
debounce: {
required: false
},
datalist: {
type: Array,
required: false,
},
inline: {
type: Boolean,
required: false,
default: false
},
save: {
type: Function,
required: false,
},
},
emits: ['change', 'keydown', 'enter'],
setup(props, context) {
const { value, type, autofocus } = toRefs(props);
const v = ref(value.value);
const id = Math.random().toString(); // TODO: uuid?
const focused = ref(false);
const changed = ref(false);
const invalid = ref(false);
const filled = computed(() => v.value !== '' && v.value != null);
const inputEl = ref(null);
const prefixEl = ref(null);
const suffixEl = ref(null);
const focus = () => inputEl.value.focus();
const onInput = (ev) => {
changed.value = true;
context.emit('change', ev);
};
const onKeydown = (ev: KeyboardEvent) => {
context.emit('keydown', ev);
if (ev.code === 'Enter') {
context.emit('enter');
}
};
watch(value, newValue => {
v.value = newValue;
});
watch(v, newValue => {
if (type?.value === 'number') {
context.emit('update:value', parseFloat(newValue));
} else {
context.emit('update:value', newValue);
}
invalid.value = inputEl.value.validity.badInput;
});
onMounted(() => {
nextTick(() => {
if (autofocus.value) {
focus();
}
// このコンポーネントが作成された時、非表示状態である場合がある
// 非表示状態だと要素の幅などは0になってしまうので、定期的に計算する
const clock = setInterval(() => {
if (prefixEl.value) {
if (prefixEl.value.offsetWidth) {
inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
}
}
if (suffixEl.value) {
if (suffixEl.value.offsetWidth) {
inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px';
}
}
}, 100);
onUnmounted(() => {
clearInterval(clock);
});
});
});
return {
id,
v,
focused,
invalid,
changed,
filled,
inputEl,
prefixEl,
suffixEl,
focus,
onInput,
onKeydown,
faExclamationCircle,
};
},
});
</script>
<style lang="scss" scoped>
.ztzhwixg {
position: relative;
> .icon {
position: absolute;
top: 0;
left: 0;
width: 24px;
text-align: center;
line-height: 32px;
&:not(:empty) + .input {
margin-left: 28px;
}
}
> .input {
$height: 52px;
position: relative;
> input {
display: block;
height: $height;
width: 100%;
margin: 0;
padding: 0 16px;
font: inherit;
font-weight: normal;
font-size: 1em;
line-height: $height;
color: var(--inputText);
background: transparent;
border: none;
border-radius: 0;
outline: none;
box-shadow: none;
box-sizing: border-box;
&[type='file'] {
display: none;
}
}
> .prefix,
> .suffix {
display: block;
position: absolute;
z-index: 1;
top: 0;
padding: 0 16px;
font-size: 1em;
line-height: $height;
color: var(--inputLabel);
pointer-events: none;
&:empty {
display: none;
}
> * {
display: inline-block;
min-width: 16px;
max-width: 150px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
> .prefix {
left: 0;
padding-right: 8px;
}
> .suffix {
right: 0;
padding-left: 8px;
}
}
> .save {
margin: 6px 0 0 0;
font-size: 0.8em;
}
&.inline {
display: inline-block;
margin: 0;
}
&.disabled {
opacity: 0.7;
&, * {
cursor: not-allowed !important;
}
}
}
</style>

View File

@ -0,0 +1,30 @@
<template>
<div class="_formItem">
<div class="_formPanel anocepby">
<span class="key"><slot name="key"></slot></span>
<span class="value"><slot name="value"></slot></span>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import './form.scss';
export default defineComponent({
});
</script>
<style lang="scss" scoped>
.anocepby {
display: flex;
align-items: center;
padding: 14px 16px;
> .value {
margin-left: auto;
opacity: 0.7;
}
}
</style>

View File

@ -0,0 +1,90 @@
<template>
<div class="qmfkfnzi _formItem">
<a class="main _button _formPanel _formClickable" :href="to" target="_blank" v-if="external">
<span class="icon"><slot name="icon"></slot></span>
<span class="text"><slot></slot></span>
<Fa :icon="faExternalLinkAlt" class="right"/>
</a>
<MkA class="main _button _formPanel _formClickable" :class="{ active }" :to="to" v-else>
<span class="icon"><slot name="icon"></slot></span>
<span class="text"><slot></slot></span>
<Fa :icon="faChevronRight" class="right"/>
</MkA>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { faChevronRight, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
import './form.scss';
export default defineComponent({
props: {
to: {
type: String,
required: true
},
active: {
type: Boolean,
required: false
},
external: {
type: Boolean,
required: false
},
},
data() {
return {
faChevronRight, faExternalLinkAlt
};
}
});
</script>
<style lang="scss" scoped>
.qmfkfnzi {
> .main {
display: flex;
align-items: center;
width: 100%;
box-sizing: border-box;
padding: 14px 16px 14px 14px;
&:hover {
text-decoration: none;
}
&.active {
color: var(--accent);
}
> .icon {
width: 32px;
margin-right: 2px;
flex-shrink: 0;
text-align: center;
opacity: 0.8;
&:empty {
display: none;
& + .text {
padding-left: 4px;
}
}
}
> .text {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
padding-right: 12px;
}
> .right {
margin-left: auto;
opacity: 0.7;
}
}
}
</style>

View File

@ -0,0 +1,42 @@
<template>
<FormGroup class="uljviswt _formItem">
<template #label><slot name="label"></slot></template>
<slot :items="items"></slot>
<div class="empty" v-if="empty" key="_empty_">
<slot name="empty"></slot>
</div>
<FormButton v-show="more" class="button" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary>
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
<template v-if="moreFetching"><MkLoading inline/></template>
</FormButton>
</FormGroup>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import FormButton from './button.vue';
import FormGroup from './group.vue';
import paging from '@/scripts/paging';
export default defineComponent({
components: {
FormButton,
FormGroup,
},
mixins: [
paging({}),
],
props: {
pagination: {
required: true
},
},
});
</script>
<style lang="scss" scoped>
.uljviswt {
}
</style>

View File

@ -0,0 +1,106 @@
<script lang="ts">
import { defineComponent, h } from 'vue';
import MkRadio from '@/components/ui/radio.vue';
import './form.scss';
export default defineComponent({
components: {
MkRadio
},
props: {
modelValue: {
required: false
},
},
data() {
return {
value: this.modelValue,
}
},
watch: {
value() {
this.$emit('update:modelValue', this.value);
}
},
render() {
const label = this.$slots.desc();
const options = this.$slots.default();
return h('div', {
class: 'cnklmpwm _formItem'
}, [
h('div', {
class: '_formLabel',
}, label),
...options.map(option => h('button', {
class: '_button _formPanel _formClickable',
key: option.props.value,
onClick: () => this.value = option.props.value,
}, [h('span', {
class: ['check', { checked: this.value === option.props.value }],
}), option.children]))
]);
}
});
</script>
<style lang="scss">
.cnklmpwm {
> button {
display: block;
width: 100%;
box-sizing: border-box;
padding: 14px 18px;
text-align: left;
&:not(:first-of-type) {
border-top: none !important;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
&:not(:last-of-type) {
border-bottom: solid 0.5px var(--divider);
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
> .check {
display: inline-block;
vertical-align: bottom;
position: relative;
width: 20px;
height: 20px;
margin-right: 8px;
background: none;
border: 2px solid var(--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: .4s cubic-bezier(.25,.8,.25,1);
}
&.checked {
border-color: var(--accent);
&:after {
background-color: var(--accent);
transform: scale(1);
opacity: 1;
}
}
}
}
}
</style>

View File

@ -0,0 +1,122 @@
<template>
<div class="ifitouly _formItem" :class="{ focused, disabled }">
<div class="_formLabel"><slot name="label"></slot></div>
<div class="_formPanel main">
<input
type="range"
ref="input"
v-model="v"
:disabled="disabled"
:min="min"
:max="max"
:step="step"
@focus="focused = true"
@blur="focused = false"
@input="$emit('update:value', $event.target.value)"
/>
</div>
<div class="_formCaption"><slot name="caption"></slot></div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
props: {
value: {
type: Number,
required: false,
default: 0
},
disabled: {
type: Boolean,
required: false,
default: false
},
min: {
type: Number,
required: false,
default: 0
},
max: {
type: Number,
required: false,
default: 100
},
step: {
type: Number,
required: false,
default: 1
},
},
data() {
return {
v: this.value,
focused: false
};
},
watch: {
value(v) {
this.v = parseFloat(v);
}
},
});
</script>
<style lang="scss" scoped>
.ifitouly {
position: relative;
> .main {
padding: 24px 16px;
> input {
display: block;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: var(--X10);
height: 4px;
width: 100%;
box-sizing: border-box;
margin: 0;
outline: 0;
border: 0;
border-radius: 7px;
&.disabled {
opacity: 0.6;
cursor: not-allowed;
}
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
cursor: pointer;
width: 20px;
height: 20px;
display: block;
border-radius: 50%;
border: none;
background: var(--accent);
box-shadow: 0 0 6px rgba(0, 0, 0, 0.3);
box-sizing: content-box;
}
&::-moz-range-thumb {
-moz-appearance: none;
appearance: none;
cursor: pointer;
width: 20px;
height: 20px;
display: block;
border-radius: 50%;
border: none;
background: var(--accent);
box-shadow: 0 0 6px rgba(0, 0, 0, 0.3);
}
}
}
}
</style>

View File

@ -0,0 +1,147 @@
<template>
<div class="yrtfrpux _formItem" :class="{ disabled, inline }">
<div class="_formLabel"><slot name="label"></slot></div>
<div class="icon" ref="icon"><slot name="icon"></slot></div>
<div class="input _formPanel _formClickable" @click="focus">
<div class="prefix" ref="prefix"><slot name="prefix"></slot></div>
<select ref="input"
v-model="v"
:required="required"
:disabled="disabled"
@focus="focused = true"
@blur="focused = false"
>
<slot></slot>
</select>
<div class="suffix">
<Fa :icon="faChevronDown"/>
</div>
</div>
<div class="_formCaption"><slot name="caption"></slot></div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
import './form.scss';
export default defineComponent({
props: {
value: {
required: false
},
required: {
type: Boolean,
required: false
},
disabled: {
type: Boolean,
required: false
},
inline: {
type: Boolean,
required: false,
default: false
},
},
data() {
return {
faChevronDown,
};
},
computed: {
v: {
get() {
return this.value;
},
set(v) {
this.$emit('update:value', v);
}
},
},
methods: {
focus() {
this.$refs.input.focus();
}
}
});
</script>
<style lang="scss" scoped>
.yrtfrpux {
position: relative;
> .icon {
position: absolute;
top: 0;
left: 0;
width: 24px;
text-align: center;
line-height: 32px;
&:not(:empty) + .input {
margin-left: 28px;
}
}
> .input {
display: flex;
position: relative;
> select {
display: block;
flex: 1;
width: 100%;
padding: 0 16px;
font: inherit;
font-weight: normal;
font-size: 1em;
height: 52px;
background: none;
border: none;
border-radius: 0;
outline: none;
box-shadow: none;
appearance: none;
-webkit-appearance: none;
color: var(--fg);
option,
optgroup {
color: var(--fg);
background: var(--bg);
}
}
> .prefix,
> .suffix {
display: block;
align-self: center;
justify-self: center;
font-size: 1em;
line-height: 32px;
color: var(--inputLabel);
pointer-events: none;
&:empty {
display: none;
}
> * {
display: block;
min-width: 16px;
}
}
> .prefix {
padding-right: 4px;
}
> .suffix {
padding: 0 16px 0 0;
opacity: 0.7;
}
}
}
</style>

View File

@ -0,0 +1,132 @@
<template>
<div class="ijnpvmgr _formItem">
<div class="main _formPanel _formClickable"
:class="{ disabled, checked }"
:aria-checked="checked"
:aria-disabled="disabled"
@click.prevent="toggle"
>
<input
type="checkbox"
ref="input"
:disabled="disabled"
@keydown.enter="toggle"
>
<span class="button">
<span></span>
</span>
<span class="label">
<span><slot></slot></span>
</span>
</div>
<div class="_formCaption"><slot name="desc"></slot></div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import './form.scss';
export default defineComponent({
props: {
value: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
}
},
computed: {
checked(): boolean {
return this.value;
}
},
methods: {
toggle() {
if (this.disabled) return;
this.$emit('update:value', !this.checked);
}
}
});
</script>
<style lang="scss" scoped>
.ijnpvmgr {
> .main {
position: relative;
display: flex;
padding: 16px;
cursor: pointer;
> * {
user-select: none;
}
&.disabled {
opacity: 0.6;
cursor: not-allowed;
}
&.checked {
> .button {
background-color: var(--X10);
border-color: var(--X10);
> * {
background-color: var(--accent);
transform: translateX(14px);
}
}
}
> input {
position: absolute;
width: 0;
height: 0;
opacity: 0;
margin: 0;
}
> .button {
position: relative;
display: inline-block;
flex-shrink: 0;
margin: 3px 0 0 0;
width: 34px;
height: 14px;
background: var(--X6);
outline: none;
border-radius: 14px;
transition: all 0.3s;
cursor: pointer;
> * {
position: absolute;
top: -3px;
left: 0;
border-radius: 100%;
transition: background-color 0.3s, transform 0.3s;
width: 20px;
height: 20px;
background-color: #fff;
box-shadow: 0 2px 1px -1px rgba(#000, 0.2), 0 1px 1px 0 rgba(#000, 0.14), 0 1px 3px 0 rgba(#000, 0.12);
}
}
> .label {
margin-left: 12px;
display: block;
transition: inherit;
color: var(--fg);
> span {
display: block;
line-height: 20px;
transition: inherit;
}
}
}
}
</style>

View File

@ -0,0 +1,136 @@
<template>
<div class="rivhosbp _formItem" :class="{ tall, pre }">
<div class="_formLabel"><slot></slot></div>
<div class="input _formPanel">
<textarea ref="input" :class="{ code, _monospace: code }"
:value="value"
:required="required"
:readonly="readonly"
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="!code"
@input="onInput"
@focus="focused = true"
@blur="focused = false"
></textarea>
</div>
<button class="save _textButton" v-if="save && changed" @click="() => { changed = false; save(); }">{{ $t('save') }}</button>
<div class="_formCaption"><slot name="desc"></slot></div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import './form.scss';
export default defineComponent({
props: {
value: {
required: false
},
required: {
type: Boolean,
required: false
},
readonly: {
type: Boolean,
required: false
},
pattern: {
type: String,
required: false
},
autocomplete: {
type: String,
required: false
},
code: {
type: Boolean,
required: false
},
tall: {
type: Boolean,
required: false,
default: false
},
pre: {
type: Boolean,
required: false,
default: false
},
save: {
type: Function,
required: false,
},
},
data() {
return {
changed: false,
}
},
methods: {
focus() {
this.$refs.input.focus();
},
onInput(ev) {
this.changed = true;
this.$emit('update:value', ev.target.value);
}
}
});
</script>
<style lang="scss" scoped>
.rivhosbp {
position: relative;
> .input {
position: relative;
> textarea {
display: block;
width: 100%;
min-width: 100%;
max-width: 100%;
min-height: 130px;
margin: 0;
padding: 16px;
box-sizing: border-box;
font: inherit;
font-weight: normal;
font-size: 1em;
background: transparent;
border: none;
border-radius: 0;
outline: none;
box-shadow: none;
color: var(--fg);
&.code {
tab-size: 2;
}
}
}
> .save {
margin: 6px 0 0 0;
font-size: 0.8em;
}
&.tall {
> .input {
> textarea {
min-height: 200px;
}
}
}
&.pre {
> .input {
> textarea {
white-space: pre;
}
}
}
}
</style>

View File

@ -0,0 +1,36 @@
<template>
<div class="wthhikgt _formItem" v-size="{ max: [500] }">
<slot></slot>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
});
</script>
<style lang="scss" scoped>
.wthhikgt {
position: relative;
display: flex;
> ::v-deep(*) {
flex: 1;
margin: 0;
&:not(:last-child) {
margin-right: 16px;
}
}
&.max-width_500px {
display: block;
> ::v-deep(*) {
margin: inherit;
}
}
}
</style>

View File

@ -68,7 +68,7 @@ export default defineComponent({
created() {
// Plugin:register_note_view_interruptor を使って書き換えられる可能性があるためwatchする
this.$watch('image', () => {
this.hide = this.image.isSensitive && !this.$store.state.device.alwaysShowNsfw;
this.hide = (this.$store.state.device.nsfw === 'force') ? true : this.image.isSensitive && (this.$store.state.device.nsfw !== 'ignore');
if (this.image.blurhash) {
this.color = extractAvgColorFromBlurhash(this.image.blurhash);
}

View File

@ -48,7 +48,7 @@ export default defineComponent({
}
},
created() {
this.hide = this.video.isSensitive && !this.$store.state.device.alwaysShowNsfw;
this.hide = (this.$store.state.device.nsfw === 'force') ? true : this.video.isSensitive && (this.$store.state.device.nsfw !== 'ignore');
},
});
</script>

View File

@ -14,8 +14,8 @@
<option value="res">Response</option>
</MkTab>
<code v-if="tab === 'req'">{{ reqStr }}</code>
<code v-if="tab === 'res'">{{ resStr }}</code>
<code v-if="tab === 'req'" class="_monospace">{{ reqStr }}</code>
<code v-if="tab === 'res'" class="_monospace">{{ resStr }}</code>
</div>
</XWindow>
</template>
@ -67,7 +67,6 @@ export default defineComponent({
font-size: 0.9em;
tab-size: 2;
white-space: pre;
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
}
}
</style>

View File

@ -3,7 +3,7 @@
<template #header>
<Fa :icon="faTerminal" style="margin-right: 0.5em;"/>Task Manager
</template>
<div class="qljqmnzj">
<div class="qljqmnzj _monospace">
<MkTab v-model:value="tab" style="border-bottom: solid 1px var(--divider);">
<option value="windows">Windows</option>
<option value="stream">Stream</option>
@ -150,7 +150,6 @@ export default defineComponent({
display: flex;
flex-direction: column;
height: 100%;
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
> .content {
flex: 1;

View File

@ -6,6 +6,7 @@
import { defineComponent } from 'vue';
import XNotes from './notes.vue';
import * as os from '@/os';
import * as sound from '@/scripts/sound';
export default defineComponent({
components: {
@ -65,7 +66,7 @@ export default defineComponent({
this.$emit('note');
if (this.sound) {
os.sound(note.userId === this.$store.state.i.id ? 'noteMy' : 'note');
sound.play(note.userId === this.$store.state.i.id ? 'noteMy' : 'note');
}
};

View File

@ -1,7 +1,7 @@
<template>
<div class="timctyfi" :class="{ focused, disabled }">
<div class="icon"><slot name="icon"></slot></div>
<span class="title"><slot name="title"></slot></span>
<span class="label"><slot name="label"></slot></span>
<input
type="range"
ref="input"
@ -19,7 +19,7 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';import * as os from '@/os';
import { defineComponent } from 'vue';
export default defineComponent({
props: {

View File

@ -17,10 +17,8 @@
<span></span>
</span>
<span class="label">
<span :aria-hidden="!checked"><slot></slot></span>
<p :aria-hidden="!checked">
<slot name="desc"></slot>
</p>
<span><slot></slot></span>
<p><slot name="desc"></slot></p>
</span>
</div>
</template>

View File

@ -2,7 +2,7 @@
<div class="adhpbeos" :class="{ focused, filled, tall, pre }">
<div class="input">
<span class="label" ref="label"><slot></slot></span>
<textarea ref="input" :class="{ code }"
<textarea ref="input" :class="{ code, _monospace: code }"
:value="value"
:required="required"
:readonly="readonly"
@ -166,7 +166,6 @@ export default defineComponent({
&.code {
tab-size: 2;
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
}
}
}