This commit is contained in:
syuilo 2018-06-14 14:52:37 +09:00
parent 3a4833818f
commit a1ae832129
12 changed files with 658 additions and 346 deletions

View File

@ -29,8 +29,12 @@ import fileTypeIcon from './file-type-icon.vue';
import Switch from './switch.vue'; import Switch from './switch.vue';
import Othello from './othello.vue'; import Othello from './othello.vue';
import welcomeTimeline from './welcome-timeline.vue'; import welcomeTimeline from './welcome-timeline.vue';
import uiInput from './material/input.vue'; import uiInput from './ui/input.vue';
import uiButton from './material/button.vue'; import uiButton from './ui/button.vue';
import uiGroup from './ui/group.vue';
import uiForm from './ui/form.vue';
import uiTextarea from './ui/textarea.vue';
import uiSwitch from './ui/switch.vue';
Vue.component('mk-analog-clock', analogClock); Vue.component('mk-analog-clock', analogClock);
Vue.component('mk-menu', menu); Vue.component('mk-menu', menu);
@ -63,3 +67,7 @@ Vue.component('mk-othello', Othello);
Vue.component('mk-welcome-timeline', welcomeTimeline); Vue.component('mk-welcome-timeline', welcomeTimeline);
Vue.component('ui-input', uiInput); Vue.component('ui-input', uiInput);
Vue.component('ui-button', uiButton); Vue.component('ui-button', uiButton);
Vue.component('ui-group', uiGroup);
Vue.component('ui-form', uiForm);
Vue.component('ui-textarea', uiTextarea);
Vue.component('ui-switch', uiSwitch);

View File

@ -1,6 +1,5 @@
<template> <template>
<form class="mk-signup" @submit.prevent="onSubmit" autocomplete="off"> <form class="mk-signup" @submit.prevent="onSubmit" autocomplete="off">
<label class="username">
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" autocomplete="off" required @input="onChangeUsername"> <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" autocomplete="off" required @input="onChangeUsername">
<span>%i18n:@username%</span> <span>%i18n:@username%</span>
<span slot="prefix">@</span> <span slot="prefix">@</span>
@ -13,38 +12,29 @@
<p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p> <p slot="text" v-if="usernameState == 'min-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-short%</p>
<p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p> <p slot="text" v-if="usernameState == 'max-range'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@too-long%</p>
</ui-input> </ui-input>
</label> <ui-input v-model="password" type="password" autocomplete="off" required @input="onChangePassword" :with-password-meter="true">
<label class="password">
<ui-input v-model="password" type="password" autocomplete="off" required @input="onChangePassword">
<span>%i18n:@password%</span> <span>%i18n:@password%</span>
<span slot="prefix">%fa:lock%</span> <span slot="prefix">%fa:lock%</span>
<div slot="text"> <div slot="text">
<p slot="text" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@weak-password%</p>
<p slot="text" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw% %i18n:@normal-password%</p>
<p slot="text" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw% %i18n:@strong-password%</p>
</div> </div>
</ui-input> </ui-input>
<div class="meter" v-show="passwordStrength != ''" :data-strength="passwordStrength">
<div class="value" ref="passwordMetar"></div>
</div>
<p class="info" v-if="passwordStrength == 'low'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@weak-password%</p>
<p class="info" v-if="passwordStrength == 'medium'" style="color:#3CB7B5">%fa:check .fw%%i18n:@normal-password%</p>
<p class="info" v-if="passwordStrength == 'high'" style="color:#3CB7B5">%fa:check .fw%%i18n:@strong-password%</p>
</label>
<label class="retype-password">
<ui-input v-model="retypedPassword" type="password" autocomplete="off" required @input="onChangePasswordRetype"> <ui-input v-model="retypedPassword" type="password" autocomplete="off" required @input="onChangePasswordRetype">
<span>%i18n:@password% (%i18n:@retype%)</span> <span>%i18n:@password% (%i18n:@retype%)</span>
<span slot="prefix">%fa:lock%</span> <span slot="prefix">%fa:lock%</span>
<div slot="text">
<p slot="text" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw% %i18n:@password-matched%</p>
<p slot="text" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw% %i18n:@password-not-matched%</p>
</div>
</ui-input> </ui-input>
<p class="info" v-if="passwordRetypeState == 'match'" style="color:#3CB7B5">%fa:check .fw%%i18n:@password-matched%</p> <div class="g-recaptcha" :data-sitekey="recaptchaSitekey" style="margin: 16px 0;"></div>
<p class="info" v-if="passwordRetypeState == 'not-match'" style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:@password-not-matched%</p> <label class="agree-tou" style="display: block; margin: 16px 0;">
</label>
<label class="recaptcha">
<div class="g-recaptcha" :data-sitekey="recaptchaSitekey"></div>
</label>
<label class="agree-tou">
<input name="agree-tou" type="checkbox" autocomplete="off" required/> <input name="agree-tou" type="checkbox" autocomplete="off" required/>
<p><a :href="touUrl" target="_blank">利用規約</a>に同意する</p> <p><a :href="touUrl" target="_blank">利用規約</a>に同意する</p>
</label> </label>
<button type="submit">%i18n:@create%</button> <ui-button type="submit">%i18n:@create%</ui-button>
</form> </form>
</template> </template>
@ -112,7 +102,6 @@ export default Vue.extend({
const strength = getPasswordStrength(this.password); const strength = getPasswordStrength(this.password);
this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low'; this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low';
(this.$refs.passwordMetar as any).style.width = `${strength * 100}%`;
}, },
onChangePasswordRetype() { onChangePasswordRetype() {
if (this.retypedPassword == '') { if (this.retypedPassword == '') {
@ -156,100 +145,6 @@ export default Vue.extend({
.mk-signup .mk-signup
min-width 302px min-width 302px
label
display block
margin 0 0 16px 0
> .caption
margin 0 0 4px 0
color #828888
font-size 0.95em
> [data-fa]
margin-right 0.25em
color #96adac
> .info
display block
margin 4px 0
font-size 0.8em
> [data-fa]
margin-right 0.3em
&.username
.profile-page-url-preview
display block
margin 4px 8px 0 4px
font-size 0.8em
color #888
&:empty
display none
&:not(:empty) + .info
margin-top 0
&.password
.meter
display block
margin-top 8px
width 100%
height 8px
&[data-strength='']
display none
&[data-strength='low']
> .value
background #d73612
&[data-strength='medium']
> .value
background #d7ca12
&[data-strength='high']
> .value
background #61bb22
> .value
display block
width 0%
height 100%
background transparent
border-radius 4px
transition all 0.1s ease
[type=text], [type=password]
user-select text
display inline-block
cursor auto
padding 0 12px
margin 0
width 100%
line-height 44px
font-size 1em
color #333 !important
background #fff !important
outline none
border solid 1px rgba(#000, 0.1)
border-radius 4px
box-shadow 0 0 0 114514px #fff inset
transition all .3s ease
&:hover
border-color rgba(#000, 0.2)
transition all .1s ease
&:focus
color $theme-color !important
border-color $theme-color
box-shadow 0 0 0 1024px #fff inset, 0 0 0 4px rgba($theme-color, 10%)
transition all 0s ease
&:disabled
opacity 0.5
.agree-tou .agree-tou
padding 4px padding 4px
border-radius 4px border-radius 4px
@ -267,19 +162,4 @@ export default Vue.extend({
display inline display inline
color #555 color #555
button
margin 0
padding 16px
width 100%
font-size 1em
color #fff
background $theme-color
border-radius 3px
&:hover
background lighten($theme-color, 5%)
&:active
background darken($theme-color, 5%)
</style> </style>

View File

@ -25,7 +25,7 @@ export default Vue.extend({
> button > button
display block display block
width 100% width 100%
margin 32px 0 16px 0 margin 0
padding 0 padding 0
color $theme-color-foreground color $theme-color-foreground
font-weight bold font-weight bold
@ -37,4 +37,10 @@ export default Vue.extend({
outline none outline none
box-shadow none box-shadow none
&:hover
background lighten($theme-color, 5%)
&:active
background darken($theme-color, 5%)
</style> </style>

View File

@ -0,0 +1,28 @@
<template>
<div class="ui-form">
<fieldset :disabled="disabled">
<slot></slot>
</fieldset>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
disabled: {
type: String,
required: false
}
}
});
</script>
<style lang="stylus" scoped>
@import '~const.styl'
.ui-form
> fieldset
border none
</style>

View File

@ -0,0 +1,23 @@
<template>
<div class="ui-group">
<header>
<slot name="title"></slot>
</header>
<slot></slot>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({});
</script>
<style lang="stylus" scoped>
@import '~const.styl'
.ui-group
> header
font-weight bold
</style>

View File

@ -0,0 +1,215 @@
<template>
<div class="ui-input" :class="{ focused, filled }">
<div class="input" @click="focus">
<div class="password-meter" v-if="withPasswordMeter" v-show="passwordStrength != ''" :data-strength="passwordStrength">
<div class="value" ref="passwordMetar"></div>
</div>
<span class="label" ref="label"><slot></slot></span>
<div class="prefix" ref="prefix"><slot name="prefix"></slot></div>
<input ref="input"
:type="type"
:value="value"
:required="required"
:readonly="readonly"
:pattern="pattern"
:autocomplete="autocomplete"
@input="$emit('input', $event.target.value)"
@focus="focused = true"
@blur="focused = false">
<div class="suffix"><slot name="suffix"></slot></div>
</div>
<div class="text"><slot name="text"></slot></div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
const getPasswordStrength = require('syuilo-password-strength');
export default Vue.extend({
props: {
value: {
required: false
},
type: {
type: String,
required: false
},
required: {
type: Boolean,
required: false
},
readonly: {
type: Boolean,
required: false
},
pattern: {
type: String,
required: false
},
autocomplete: {
type: String,
required: false
},
withPasswordMeter: {
type: Boolean,
required: false,
default: false
}
},
data() {
return {
focused: false,
passwordStrength: ''
}
},
computed: {
filled(): boolean {
return this.value != '' && this.value != null;
}
},
watch: {
value(v) {
if (this.withPasswordMeter) {
if (v == '') {
this.passwordStrength = '';
return;
}
const strength = getPasswordStrength(v);
this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low';
(this.$refs.passwordMetar as any).style.width = `${strength * 100}%`;
}
}
},
mounted() {
if (this.$refs.prefix) {
this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px';
}
},
methods: {
focus() {
this.$refs.input.focus();
}
}
});
</script>
<style lang="stylus" scoped>
@import '~const.styl'
.ui-input
margin 32px 0
> .input
display flex
padding 6px 12px
background rgba(#000, 0.035)
border-radius 6px
> .password-meter
position absolute
top 0
left 0
width 100%
height 100%
border-radius 6px
overflow hidden
opacity 0.3
&[data-strength='']
display none
&[data-strength='low']
> .value
background #d73612
&[data-strength='medium']
> .value
background #d7ca12
&[data-strength='high']
> .value
background #61bb22
> .value
display block
width 0%
height 100%
background transparent
border-radius 6px
transition all 0.1s ease
> .label
position absolute
top 6px
left 0
pointer-events none
transition 0.4s cubic-bezier(0.25, 0.8, 0.25, 1)
transition-duration 0.3s
font-size 16px
line-height 32px
color rgba(#000, 0.54)
pointer-events none
//will-change transform
transform-origin top left
transform scale(1)
> input
display block
flex 1
width 100%
padding 0
font inherit
font-weight bold
font-size 16px
line-height 32px
background transparent
border none
border-radius 0
outline none
box-shadow none
> .prefix
> .suffix
display block
align-self center
justify-self center
font-size 16px
line-height 32px
color rgba(#000, 0.54)
pointer-events none
> *
display block
min-width 16px
> .prefix
padding-right 4px
> .suffix
padding-left 4px
> .text
margin 6px 0
font-size 13px
*
margin 0
&.focused
> .input
background rgba(#000, 0.05)
> .label
color $theme-color
&.focused
&.filled
> .input
> .label
top -24px
left 0 !important
transform scale(0.8)
</style>

View File

@ -0,0 +1,199 @@
<template>
<div
class="ui-switch"
:class="{ disabled, checked }"
role="switch"
:aria-checked="checked"
:aria-disabled="disabled"
@click="switchValue"
@mouseover="mouseenter"
>
<input
type="checkbox"
@change="handleChange"
ref="input"
:disabled="disabled"
@keydown.enter="switchValue"
>
<span class="button">
<span :style="{ transform }"></span>
</span>
<span class="label">
<span :aria-hidden="!checked"><slot></slot></span>
<p :aria-hidden="!checked">
<slot name="text"></slot>
</p>
</span>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
value: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
}
},/*
created() {
if (!~[true, false].indexOf(this.value)) {
this.$emit('input', false);
}
},*/
computed: {
checked(): boolean {
return this.value;
},
transform(): string {
return this.checked ? 'translate3d(14px, 0, 0)' : '';
}
},
watch: {
value() {
(this.$el).style.transition = 'all 0.3s';
(this.$refs.input as any).checked = this.checked;
}
},
mounted() {
(this.$refs.input as any).checked = this.checked;
},
methods: {
mouseenter() {
(this.$el).style.transition = 'all 0s';
},
handleChange() {
(this.$el).style.transition = 'all 0.3s';
this.$emit('input', !this.checked);
this.$emit('change', !this.checked);
this.$nextTick(() => {
// set input's checked property
// in case parent refuses to change component's value
(this.$refs.input as any).checked = this.checked;
});
},
switchValue() {
!this.disabled && this.handleChange();
}
}
});
</script>
<style lang="stylus" scoped>
@import '~const.styl'
root(isDark)
display flex
margin 16px 0
cursor pointer
transition all 0.3s
> *
user-select none
&.disabled
opacity 0.6
cursor not-allowed
&.checked
> .button
background-color $theme-color
border-color $theme-color
> .label
> span
color $theme-color
&:hover
> .label
> span
color darken($theme-color, 10%)
> .button
background darken($theme-color, 10%)
border-color darken($theme-color, 10%)
&:hover
> .label
> span
color isDark ? #fff : #2e3338
> .button
$color = isDark ? #15181d : #ced2da
background $color
border-color $color
> input
position absolute
width 0
height 0
opacity 0
margin 0
&:focus + .button
&:after
content ""
pointer-events none
position absolute
top -5px
right -5px
bottom -5px
left -5px
border 2px solid rgba($theme-color, 0.3)
border-radius 14px
> .button
$color = isDark ? #1c1f25 : #dcdfe6
display inline-block
margin 0
width 46px
min-width 46px
height 32px
min-height 32px
background $color
border 1px solid $color
outline none
border-radius 6px
transition inherit
> *
position absolute
top 1px
left 1px
border-radius 6px
transition transform 0.3s
width 28px
height 28px
background-color #fff
> .label
margin-left 8px
display block
font-size 16px
cursor pointer
transition inherit
> span
display block
line-height 32px
font-weight bold
color isDark ? #c4ccd2 : #4a535a
transition inherit
> p
margin 0
//font-size 90%
color isDark ? #78858e : #9daab3
.ui-switch[data-darkmode]
root(true)
.ui-switch:not([data-darkmode])
root(false)
</style>

View File

@ -1,17 +1,17 @@
<template> <template>
<div class="ui-input" :class="{ focused, filled }"> <div class="ui-textarea" :class="{ focused, filled }">
<div class="input"> <div class="input">
<span class="label" ref="label"><slot></slot></span> <span class="label" ref="label"><slot></slot></span>
<div class="prefix" ref="prefix" @click="focus"><slot name="prefix"></slot></div> <textarea ref="input"
<input ref="input"
:type="type"
:value="value" :value="value"
:required="required" :required="required"
:readonly="readonly" :readonly="readonly"
:pattern="pattern"
:autocomplete="autocomplete"
@input="$emit('input', $event.target.value)" @input="$emit('input', $event.target.value)"
@focus="focused = true" @focus="focused = true"
@blur="focused = false"> @blur="focused = false">
<div class="suffix" @click="focus"><slot name="suffix"></slot></div> </textarea>
</div> </div>
<div class="text"><slot name="text"></slot></div> <div class="text"><slot name="text"></slot></div>
</div> </div>
@ -19,15 +19,13 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
const getPasswordStrength = require('syuilo-password-strength');
export default Vue.extend({ export default Vue.extend({
props: { props: {
value: { value: {
required: false required: false
}, },
type: {
type: String,
required: false
},
required: { required: {
type: Boolean, type: Boolean,
required: false required: false
@ -35,11 +33,20 @@ export default Vue.extend({
readonly: { readonly: {
type: Boolean, type: Boolean,
required: false required: false
},
pattern: {
type: String,
required: false
},
autocomplete: {
type: String,
required: false
} }
}, },
data() { data() {
return { return {
focused: false focused: false,
passwordStrength: ''
} }
}, },
computed: { computed: {
@ -47,9 +54,6 @@ export default Vue.extend({
return this.value != '' && this.value != null; return this.value != '' && this.value != null;
} }
}, },
mounted() {
this.$refs.label.style.left = (this.$refs.prefix.offsetLeft + this.$refs.prefix.offsetWidth) + 'px';
},
methods: { methods: {
focus() { focus() {
this.$refs.input.focus(); this.$refs.input.focus();
@ -61,20 +65,18 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
@import '~const.styl' @import '~const.styl'
.ui-input .ui-textarea
margin-bottom 16px margin 32px 0
padding-top 16px
> .input > .input
display flex padding 12px
padding 6px 12px
background rgba(#000, 0.035) background rgba(#000, 0.035)
border-radius 6px border-radius 6px
> .label > .label
position absolute position absolute
top 6px top 6px
left 0 left 12px
pointer-events none pointer-events none
transition 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) transition 0.4s cubic-bezier(0.25, 0.8, 0.25, 1)
transition-duration 0.3s transition-duration 0.3s
@ -82,42 +84,29 @@ export default Vue.extend({
line-height 32px line-height 32px
color rgba(#000, 0.54) color rgba(#000, 0.54)
pointer-events none pointer-events none
//will-change transform
transform-origin top left
transform scale(1)
> input > textarea
display block display block
flex 1
width 100% width 100%
min-height 100px
padding 0 padding 0
font inherit font inherit
font-weight bold font-weight bold
font-size 16px font-size 16px
line-height 32px
background transparent background transparent
border none border none
border-radius 0 border-radius 0
outline none outline none
box-shadow none box-shadow none
> .prefix
> .suffix
display block
align-self center
justify-self center
font-size 16px
line-height 32px
color rgba(#000, 0.54)
> .prefix
padding-right 4px
> .suffix
padding-left 4px
> .text > .text
margin 8px 0 margin 6px 0
font-size 14px font-size 13px
> p *
margin 0 margin 0
&.focused &.focused
@ -131,9 +120,8 @@ export default Vue.extend({
&.filled &.filled
> .input > .input
> .label > .label
top -20px top -24px
left 0 !important left 0 !important
font-size 12px transform scale(0.8)
line-height 20px
</style> </style>

View File

@ -6,33 +6,30 @@
<div> <div>
<x-profile/> <x-profile/>
<md-card> <ui-group>
<md-card-header> <div slot="title">%fa:palette% %i18n:@design%</div>
<div class="md-title">%fa:palette% %i18n:@design%</div>
</md-card-header>
<md-card-content>
<div> <div>
<md-switch v-model="darkmode">%i18n:@dark-mode%</md-switch> <ui-switch v-model="darkmode">%i18n:@dark-mode%</ui-switch>
</div> </div>
<div> <div>
<md-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</md-switch> <ui-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</ui-switch>
</div> </div>
<div> <div>
<div class="md-body-2">%i18n:@timeline%</div> <div class="md-body-2">%i18n:@timeline%</div>
<div> <div>
<md-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</md-switch> <ui-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</ui-switch>
</div> </div>
<div> <div>
<md-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</md-switch> <ui-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</ui-switch>
</div> </div>
<div> <div>
<md-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</md-switch> <ui-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</ui-switch>
</div> </div>
</div> </div>
@ -42,43 +39,35 @@
<md-radio v-model="postStyle" value="standard">%i18n:@post-style-standard%</md-radio> <md-radio v-model="postStyle" value="standard">%i18n:@post-style-standard%</md-radio>
<md-radio v-model="postStyle" value="smart">%i18n:@post-style-smart%</md-radio> <md-radio v-model="postStyle" value="smart">%i18n:@post-style-smart%</md-radio>
</div> </div>
</md-card-content> </ui-group>
</md-card>
<md-card> <ui-group>
<md-card-header> <div slot="title">%fa:cog% %i18n:@behavior%</div>
<div class="md-title">%fa:cog% %i18n:@behavior%</div>
</md-card-header>
<md-card-content>
<div> <div>
<md-switch v-model="$store.state.settings.fetchOnScroll" @change="onChangeFetchOnScroll">%i18n:@fetch-on-scroll%</md-switch> <ui-switch v-model="$store.state.settings.fetchOnScroll" @change="onChangeFetchOnScroll">%i18n:@fetch-on-scroll%</ui-switch>
</div> </div>
<div> <div>
<md-switch v-model="$store.state.settings.disableViaMobile" @change="onChangeDisableViaMobile">%i18n:@disable-via-mobile%</md-switch> <ui-switch v-model="$store.state.settings.disableViaMobile" @change="onChangeDisableViaMobile">%i18n:@disable-via-mobile%</ui-switch>
</div> </div>
<div> <div>
<md-switch v-model="loadRawImages">%i18n:@load-raw-images%</md-switch> <ui-switch v-model="loadRawImages">%i18n:@load-raw-images%</ui-switch>
</div> </div>
<div> <div>
<md-switch v-model="$store.state.settings.loadRemoteMedia" @change="onChangeLoadRemoteMedia">%i18n:@load-remote-media%</md-switch> <ui-switch v-model="$store.state.settings.loadRemoteMedia" @change="onChangeLoadRemoteMedia">%i18n:@load-remote-media%</ui-switch>
</div> </div>
<div> <div>
<md-switch v-model="lightmode">%i18n:@i-am-under-limited-internet%</md-switch> <ui-switch v-model="lightmode">%i18n:@i-am-under-limited-internet%</ui-switch>
</div> </div>
</md-card-content> </ui-group>
</md-card>
<md-card> <ui-group>
<md-card-header> <div slot="title">%fa:language% %i18n:@lang%</div>
<div class="md-title">%fa:language% %i18n:@lang%</div>
</md-card-header>
<md-card-content>
<md-field> <md-field>
<md-select v-model="lang" placeholder="%i18n:@auto%"> <md-select v-model="lang" placeholder="%i18n:@auto%">
<md-optgroup label="%i18n:@recommended%"> <md-optgroup label="%i18n:@recommended%">
@ -91,30 +80,22 @@
</md-select> </md-select>
</md-field> </md-field>
<span class="md-helper-text">%fa:info-circle% %i18n:@lang-tip%</span> <span class="md-helper-text">%fa:info-circle% %i18n:@lang-tip%</span>
</md-card-content> </ui-group>
</md-card>
<md-card> <ui-group>
<md-card-header> <div slot="title">%fa:B twitter% %i18n:@twitter%</div>
<div class="md-title">%fa:B twitter% %i18n:@twitter%</div>
</md-card-header>
<md-card-content>
<p class="account" v-if="$store.state.i.twitter"><a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p> <p class="account" v-if="$store.state.i.twitter"><a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<p> <p>
<a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ $store.state.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a> <a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ $store.state.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a>
<span v-if="$store.state.i.twitter"> or </span> <span v-if="$store.state.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter">%i18n:@twitter-disconnect%</a> <a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter">%i18n:@twitter-disconnect%</a>
</p> </p>
</md-card-content> </ui-group>
</md-card>
<md-card> <ui-group>
<md-card-header> <div slot="title">%fa:sync-alt% %i18n:@update%</div>
<div class="md-title">%fa:sync-alt% %i18n:@update%</div>
</md-card-header>
<md-card-content>
<div>%i18n:@version% <i>{{ version }}</i></div> <div>%i18n:@version% <i>{{ version }}</i></div>
<template v-if="latestVersion !== undefined"> <template v-if="latestVersion !== undefined">
<div>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></div> <div>%i18n:@latest-version% <i>{{ latestVersion ? latestVersion : version }}</i></div>
@ -123,8 +104,7 @@
<template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template> <template v-if="checkingForUpdate">%i18n:@update-checking%<mk-ellipsis/></template>
<template v-else>%i18n:@check-for-updates%</template> <template v-else>%i18n:@check-for-updates%</template>
</md-button> </md-button>
</md-card-content> </ui-group>
</md-card>
</div> </div>
<p><small>ver {{ version }} ({{ codename }})</small></p> <p><small>ver {{ version }} ({{ codename }})</small></p>
</main> </main>

View File

@ -1,62 +1,47 @@
<template> <template>
<md-card> <ui-group>
<md-card-header> <div slot="title">%fa:pencil-alt% %i18n:@title%</div>
<div class="md-title">%fa:pencil-alt% %i18n:@title%</div>
</md-card-header>
<md-card-content> <ui-form :disabled="saving">
<md-field> <ui-input v-model="name" :max="30">
<label>%i18n:@name%</label> <span>%i18n:@name%</span>
<md-input v-model="name" :disabled="saving" md-counter="30"/> </ui-input>
</md-field>
<md-field> <ui-input v-model="username" readonly>
<label>%i18n:@account%</label> <span>%i18n:@account%</span>
<span class="md-prefix">@</span> <span slot="prefix">@</span>
<md-input v-model="username" readonly></md-input> <span slot="suffix">@{{ host }}</span>
<span class="md-suffix">@{{ host }}</span> </ui-input>
</md-field>
<md-field> <ui-input v-model="location">
<md-icon>%fa:map-marker-alt%</md-icon> <span>%i18n:@location%</span>
<label>%i18n:@location%</label> <span slot="prefix">%fa:map-marker-alt%</span>
<md-input v-model="location" :disabled="saving"/> </ui-input>
</md-field>
<md-field> <ui-input v-model="birthday" type="date">
<md-icon>%fa:birthday-cake%</md-icon> <span>%i18n:@birthday%</span>
<label>%i18n:@birthday%</label> <span slot="prefix">%fa:birthday-cake%</span>
<md-input type="date" v-model="birthday" :disabled="saving"/> </ui-input>
</md-field>
<md-field> <ui-textarea v-model="description" :max="500">
<label>%i18n:@description%</label> <span>%i18n:@description%</span>
<md-textarea v-model="description" :disabled="saving" md-counter="500"/> </ui-textarea>
</md-field>
<md-field> <ui-input type="file" @change="onAvatarChange">
<label>%i18n:@avatar%</label> <span>%i18n:@avatar%</span>
<md-file @md-change="onAvatarChange"/> <span slot="prefix">%fa:picture-o%</span>
</md-field> </ui-input>
<md-field> <ui-input type="file" @change="onBannerChange">
<label>%i18n:@banner%</label> <span>%i18n:@banner%</span>
<md-file @md-change="onBannerChange"/> <span slot="prefix">%fa:picture-o%</span>
</md-field> </ui-input>
<md-dialog-alert <ui-switch v-model="isCat">%i18n:@is-cat%</ui-switch>
:md-active.sync="uploading"
md-content="%18n:!@uploading%"/>
<div> <ui-button @click="save">%i18n:@save%</ui-button>
<md-switch v-model="isCat">%i18n:@is-cat%</md-switch> </ui-form>
</div> </ui-group>
</md-card-content>
<md-card-actions>
<md-button class="md-primary" :disabled="saving" @click="save">%i18n:@save%</md-button>
</md-card-actions>
</md-card>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -18,7 +18,7 @@ export default Vue.extend({});
h1 h1
margin 0 margin 0
padding 8px padding 8px 0 0 0
font-size 1.5em font-size 1.5em
font-weight bold font-weight bold
color #444 color #444

View File

@ -10,16 +10,16 @@
</div> </div>
<div class="login"> <div class="login">
<form @submit.prevent="onSubmit"> <form @submit.prevent="onSubmit">
<ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" placeholder="ユーザー名" autofocus required @change="onUsernameChange"> <ui-input v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" autofocus required @change="onUsernameChange">
<span>ユーザー名</span> <span>ユーザー名</span>
<span slot="prefix">@</span> <span slot="prefix">@</span>
<span slot="suffix">@{{ host }}</span> <span slot="suffix">@{{ host }}</span>
</ui-input> </ui-input>
<ui-input v-model="password" type="password" placeholder="パスワード" required> <ui-input v-model="password" type="password" required>
<span>パスワード</span> <span>パスワード</span>
<span slot="prefix">%fa:lock%</span> <span slot="prefix">%fa:lock%</span>
</ui-input> </ui-input>
<ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" placeholder="トークン" required/> <ui-input v-if="user && user.twoFactorEnabled" v-model="token" type="number" required/>
<ui-button type="submit" :disabled="signing">{{ signing ? 'ログインしています' : 'ログイン' }}</ui-button> <ui-button type="submit" :disabled="signing">{{ signing ? 'ログインしています' : 'ログイン' }}</ui-button>
</form> </form>
<div> <div>
@ -113,7 +113,7 @@ export default Vue.extend({
> .about > .about
margin-top 16px margin-top 16px
padding 16px padding 16px
color #444 color #555
background #fff background #fff
border-radius 6px border-radius 6px