summaryrefslogtreecommitdiff
path: root/src/client/app/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/app/common')
-rw-r--r--src/client/app/common/scripts/collect-page-vars.ts6
-rw-r--r--src/client/app/common/scripts/get-face.ts3
-rw-r--r--src/client/app/common/views/components/mention.vue17
-rw-r--r--src/client/app/common/views/components/misskey-flavored-markdown.vue1
-rw-r--r--src/client/app/common/views/components/page/page.block.vue3
-rw-r--r--src/client/app/common/views/components/page/page.radio-button.vue37
-rw-r--r--src/client/app/common/views/components/poll-editor.vue14
-rw-r--r--src/client/app/common/views/components/reaction-picker.vue1
-rw-r--r--src/client/app/common/views/components/settings/app-type.vue19
-rw-r--r--src/client/app/common/views/components/settings/profile.vue69
-rw-r--r--src/client/app/common/views/components/settings/settings.vue39
-rw-r--r--src/client/app/common/views/components/signup.vue8
-rw-r--r--src/client/app/common/views/components/url-preview.vue1
-rw-r--r--src/client/app/common/views/components/url.vue1
-rw-r--r--src/client/app/common/views/pages/page-editor/els/page-editor.el.radio-button.vue53
-rw-r--r--src/client/app/common/views/pages/page-editor/page-editor.blocks.vue3
-rw-r--r--src/client/app/common/views/pages/page-editor/page-editor.vue1
17 files changed, 253 insertions, 23 deletions
diff --git a/src/client/app/common/scripts/collect-page-vars.ts b/src/client/app/common/scripts/collect-page-vars.ts
index 4c40d5d88e..a4096fb2c2 100644
--- a/src/client/app/common/scripts/collect-page-vars.ts
+++ b/src/client/app/common/scripts/collect-page-vars.ts
@@ -32,6 +32,12 @@ export function collectPageVars(content) {
type: 'number',
value: 0
});
+ } else if (x.type === 'radioButton') {
+ pageVars.push({
+ name: x.name,
+ type: 'string',
+ value: x.default || ''
+ });
} else if (x.children) {
collect(x.children);
}
diff --git a/src/client/app/common/scripts/get-face.ts b/src/client/app/common/scripts/get-face.ts
index b523948bd3..19f2bdb064 100644
--- a/src/client/app/common/scripts/get-face.ts
+++ b/src/client/app/common/scripts/get-face.ts
@@ -4,7 +4,8 @@ const faces = [
'🐡( \'-\' 🐡 )フグパンチ!!!!',
'✌️(´・_・`)✌️',
'(。>﹏<。)',
- '(Δ・x・Δ)'
+ '(Δ・x・Δ)',
+ '(コ`・ヘ・´ケ)'
];
export default () => faces[Math.floor(Math.random() * faces.length)];
diff --git a/src/client/app/common/views/components/mention.vue b/src/client/app/common/views/components/mention.vue
index f212fd3ca5..4e9f9e90d6 100644
--- a/src/client/app/common/views/components/mention.vue
+++ b/src/client/app/common/views/components/mention.vue
@@ -1,11 +1,17 @@
<template>
-<router-link class="ldlomzub" :to="`/${ canonical }`" v-user-preview="canonical">
+<router-link class="ldlomzub" :to="url" v-user-preview="canonical" v-if="url.startsWith('/')">
<span class="me" v-if="isMe">{{ $t('@.you') }}</span>
<span class="main">
<span class="username">@{{ username }}</span>
<span class="host" :class="{ fade: $store.state.settings.contrastedAcct }" v-if="(host != localHost) || $store.state.settings.showFullAcct">@{{ toUnicode(host) }}</span>
</span>
</router-link>
+<a class="ldlomzub" :href="url" target="_blank" rel="noopener" v-else>
+ <span class="main">
+ <span class="username">@{{ username }}</span>
+ <span class="host" :class="{ fade: $store.state.settings.contrastedAcct }">@{{ toUnicode(host) }}</span>
+ </span>
+</a>
</template>
<script lang="ts">
@@ -32,6 +38,15 @@ export default Vue.extend({
};
},
computed: {
+ url(): string {
+ switch (this.host) {
+ case 'twitter.com':
+ case 'github.com':
+ return `https://${this.host}/${this.username}`;
+ default:
+ return `/${this.canonical}`;
+ }
+ },
canonical(): string {
return this.host === localHost ? `@${this.username}` : `@${this.username}@${toUnicode(this.host)}`;
},
diff --git a/src/client/app/common/views/components/misskey-flavored-markdown.vue b/src/client/app/common/views/components/misskey-flavored-markdown.vue
index 64496f9c84..963efd9ab8 100644
--- a/src/client/app/common/views/components/misskey-flavored-markdown.vue
+++ b/src/client/app/common/views/components/misskey-flavored-markdown.vue
@@ -30,6 +30,7 @@ export default Vue.extend({
border-radius 4px
>>> .quote
+ display block
margin 8px
padding 6px 0 6px 12px
color var(--mfmQuote)
diff --git a/src/client/app/common/views/components/page/page.block.vue b/src/client/app/common/views/components/page/page.block.vue
index 1c421fc2c0..56d1822013 100644
--- a/src/client/app/common/views/components/page/page.block.vue
+++ b/src/client/app/common/views/components/page/page.block.vue
@@ -16,10 +16,11 @@ import XIf from './page.if.vue';
import XTextarea from './page.textarea.vue';
import XPost from './page.post.vue';
import XCounter from './page.counter.vue';
+import XRadioButton from './page.radio-button.vue';
export default Vue.extend({
components: {
- XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter
+ XText, XSection, XImage, XButton, XNumberInput, XTextInput, XTextareaInput, XTextarea, XPost, XSwitch, XIf, XCounter, XRadioButton
},
props: {
diff --git a/src/client/app/common/views/components/page/page.radio-button.vue b/src/client/app/common/views/components/page/page.radio-button.vue
new file mode 100644
index 0000000000..27c11bebad
--- /dev/null
+++ b/src/client/app/common/views/components/page/page.radio-button.vue
@@ -0,0 +1,37 @@
+<template>
+<div>
+ <div>{{ script.interpolate(value.title) }}</div>
+ <ui-radio v-for="x in value.values" v-model="v" :value="x" :key="x">{{ x }}</ui-radio>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+
+export default Vue.extend({
+ props: {
+ value: {
+ required: true
+ },
+ script: {
+ required: true
+ }
+ },
+
+ data() {
+ return {
+ v: this.value.default,
+ };
+ },
+
+ watch: {
+ v() {
+ this.script.aiScript.updatePageVar(this.value.name, this.v);
+ this.script.eval();
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+</style>
diff --git a/src/client/app/common/views/components/poll-editor.vue b/src/client/app/common/views/components/poll-editor.vue
index f7a4d3af8c..49940134c7 100644
--- a/src/client/app/common/views/components/poll-editor.vue
+++ b/src/client/app/common/views/components/poll-editor.vue
@@ -26,13 +26,19 @@
<option value="after">{{ $t('after') }}</option>
</ui-select>
<section v-if="expiration === 'at'">
- <ui-input v-model="atDate" type="date">{{ $t('deadline-date') }}</ui-input>
- <ui-input v-model="atTime" type="time">{{ $t('deadline-time') }}</ui-input>
+ <ui-input v-model="atDate" type="date">
+ <template #title>{{ $t('deadline-date') }}</template>
+ </ui-input>
+ <ui-input v-model="atTime" type="time">
+ <template #title>{{ $t('deadline-time') }}</template>
+ </ui-input>
</section>
<section v-if="expiration === 'after'">
- <ui-input v-model="after" type="number">{{ $t('interval') }}</ui-input>
+ <ui-input v-model="after" type="number">
+ <template #title>{{ $t('interval') }}</template>
+ </ui-input>
<ui-select v-model="unit">
- <template #label>{{ $t('unit') }}</template>
+ <template #title>{{ $t('unit') }}</template>
<option value="second">{{ $t('second') }}</option>
<option value="minute">{{ $t('minute') }}</option>
<option value="hour">{{ $t('hour') }}</option>
diff --git a/src/client/app/common/views/components/reaction-picker.vue b/src/client/app/common/views/components/reaction-picker.vue
index 970d430069..ff534d37ce 100644
--- a/src/client/app/common/views/components/reaction-picker.vue
+++ b/src/client/app/common/views/components/reaction-picker.vue
@@ -276,6 +276,7 @@ export default Vue.extend({
font-size 14px
color var(--popupFg)
border-bottom solid var(--lineWidth) var(--faceDivider)
+ line-height 20px
> .buttons
padding 4px 4px 8px 4px
diff --git a/src/client/app/common/views/components/settings/app-type.vue b/src/client/app/common/views/components/settings/app-type.vue
index 90ff28803b..d163f1e746 100644
--- a/src/client/app/common/views/components/settings/app-type.vue
+++ b/src/client/app/common/views/components/settings/app-type.vue
@@ -29,8 +29,25 @@ export default Vue.extend({
computed: {
appTypeForce: {
get() { return this.$store.state.device.appTypeForce; },
- set(value) { this.$store.commit('device/set', { key: 'appTypeForce', value }); }
+ set(value) {
+ this.$store.commit('device/set', { key: 'appTypeForce', value });
+ this.reload();
+ }
},
},
+
+ methods: {
+ reload() {
+ this.$root.dialog({
+ type: 'warning',
+ text: this.$t('@.reload-to-apply-the-setting'),
+ showCancelButton: true
+ }).then(({ canceled }) => {
+ if (!canceled) {
+ location.reload();
+ }
+ });
+ },
+ }
});
</script>
diff --git a/src/client/app/common/views/components/settings/profile.vue b/src/client/app/common/views/components/settings/profile.vue
index a22fd6df98..edfc5a9edf 100644
--- a/src/client/app/common/views/components/settings/profile.vue
+++ b/src/client/app/common/views/components/settings/profile.vue
@@ -51,6 +51,26 @@
<template #desc v-if="bannerUploading">{{ $t('uploading') }}<mk-ellipsis/></template>
</ui-input>
+ <div class="fields">
+ <header>{{ $t('profile-metadata') }}</header>
+ <ui-horizon-group>
+ <ui-input v-model="fieldName0">{{ $t('metadata-label') }}</ui-input>
+ <ui-input v-model="fieldValue0">{{ $t('metadata-content') }}</ui-input>
+ </ui-horizon-group>
+ <ui-horizon-group>
+ <ui-input v-model="fieldName1">{{ $t('metadata-label') }}</ui-input>
+ <ui-input v-model="fieldValue1">{{ $t('metadata-content') }}</ui-input>
+ </ui-horizon-group>
+ <ui-horizon-group>
+ <ui-input v-model="fieldName2">{{ $t('metadata-label') }}</ui-input>
+ <ui-input v-model="fieldValue2">{{ $t('metadata-content') }}</ui-input>
+ </ui-horizon-group>
+ <ui-horizon-group>
+ <ui-input v-model="fieldName3">{{ $t('metadata-label') }}</ui-input>
+ <ui-input v-model="fieldValue3">{{ $t('metadata-content') }}</ui-input>
+ </ui-horizon-group>
+ </div>
+
<ui-button @click="save(true)"><fa :icon="faSave"/> {{ $t('save') }}</ui-button>
</ui-form>
</section>
@@ -189,6 +209,17 @@ export default Vue.extend({
this.isLocked = this.$store.state.i.isLocked;
this.carefulBot = this.$store.state.i.carefulBot;
this.autoAcceptFollowed = this.$store.state.i.autoAcceptFollowed;
+
+ if (this.$store.state.i.fields) {
+ this.fieldName0 = this.$store.state.i.fields[0].name;
+ this.fieldValue0 = this.$store.state.i.fields[0].value;
+ this.fieldName1 = this.$store.state.i.fields[1].name;
+ this.fieldValue1 = this.$store.state.i.fields[1].value;
+ this.fieldName2 = this.$store.state.i.fields[2].name;
+ this.fieldValue2 = this.$store.state.i.fields[2].value;
+ this.fieldName3 = this.$store.state.i.fields[3].name;
+ this.fieldValue3 = this.$store.state.i.fields[3].value;
+ }
},
methods: {
@@ -237,6 +268,13 @@ export default Vue.extend({
},
save(notify) {
+ const fields = [
+ { name: this.fieldName0, value: this.fieldValue0 },
+ { name: this.fieldName1, value: this.fieldValue1 },
+ { name: this.fieldName2, value: this.fieldValue2 },
+ { name: this.fieldName3, value: this.fieldValue3 },
+ ];
+
this.saving = true;
this.$root.api('i/update', {
@@ -247,6 +285,7 @@ export default Vue.extend({
birthday: this.birthday || null,
avatarId: this.avatarId || undefined,
bannerId: this.bannerId || undefined,
+ fields,
isCat: !!this.isCat,
isBot: !!this.isBot,
isLocked: !!this.isLocked,
@@ -265,6 +304,29 @@ export default Vue.extend({
text: this.$t('saved')
});
}
+ }).catch(err => {
+ this.saving = false;
+ switch(err.id) {
+ case 'f419f9f8-2f4d-46b1-9fb4-49d3a2fd7191':
+ this.$root.dialog({
+ type: 'error',
+ title: this.$t('unable-to-process'),
+ text: this.$t('avatar-not-an-image')
+ });
+ break;
+ case '75aedb19-2afd-4e6d-87fc-67941256fa60':
+ this.$root.dialog({
+ type: 'error',
+ title: this.$t('unable-to-process'),
+ text: this.$t('banner-not-an-image')
+ });
+ break;
+ default:
+ this.$root.dialog({
+ type: 'error',
+ text: this.$t('unable-to-process')
+ });
+ }
});
},
@@ -366,4 +428,11 @@ export default Vue.extend({
height 72px
margin auto
+.fields
+ > header
+ padding 8px 0px
+ font-weight bold
+ > div
+ padding-left 16px
+
</style>
diff --git a/src/client/app/common/views/components/settings/settings.vue b/src/client/app/common/views/components/settings/settings.vue
index 281524979e..401d9423ae 100644
--- a/src/client/app/common/views/components/settings/settings.vue
+++ b/src/client/app/common/views/components/settings/settings.vue
@@ -143,13 +143,17 @@
<ui-input v-model="webSearchEngine">{{ $t('@._settings.web-search-engine') }}
<template #desc>{{ $t('@._settings.web-search-engine-desc') }}</template>
</ui-input>
+ <ui-button @click="save('webSearchEngine', webSearchEngine)"><fa :icon="faSave"/> {{ $t('@._settings.save') }}</ui-button>
</section>
<section v-if="!$root.isMobile">
<header>{{ $t('@._settings.paste') }}</header>
<ui-input v-model="pastedFileName">{{ $t('@._settings.pasted-file-name') }}
- <template #desc>{{ $t('@._settings.pasted-file-name-desc') }}</template>
+ <template v-if="pastedFileName === this.$store.state.settings.pastedFileName" #desc>{{ $t('@._settings.pasted-file-name-desc') }}</template>
+ <template v-else #desc>{{ pastedFileNamePreview() }}</template>
</ui-input>
+ <ui-button @click="save('pastedFileName', pastedFileName)"><fa :icon="faSave"/> {{ $t('@._settings.save') }}</ui-button>
+
<ui-switch v-model="pasteDialog">{{ $t('@._settings.paste-dialog') }}
<template #desc>{{ $t('@._settings.paste-dialog-desc') }}</template>
</ui-switch>
@@ -289,6 +293,8 @@ import XNotification from './notification.vue';
import { url, version } from '../../../../config';
import checkForUpdate from '../../../scripts/check-for-update';
+import { formatTimeString } from '../../../../../../misc/format-time-string';
+import { faSave } from '@fortawesome/free-regular-svg-icons';
export default Vue.extend({
i18n: i18n(),
@@ -319,8 +325,11 @@ export default Vue.extend({
return {
meta: null,
version,
+ webSearchEngine: this.$store.state.settings.webSearchEngine,
+ pastedFileName : this.$store.state.settings.pastedFileName,
latestVersion: undefined,
- checkingForUpdate: false
+ checkingForUpdate: false,
+ faSave
};
},
computed: {
@@ -419,16 +428,6 @@ export default Vue.extend({
set(value) { this.$store.dispatch('settings/set', { key: 'defaultNoteVisibility', value }); }
},
- webSearchEngine: {
- get() { return this.$store.state.settings.webSearchEngine; },
- set(value) { this.$store.dispatch('settings/set', { key: 'webSearchEngine', value }); }
- },
-
- pastedFileName: {
- get() { return this.$store.state.settings.pastedFileName; },
- set(value) { this.$store.dispatch('settings/set', { key: 'pastedFileName', value }); }
- },
-
pasteDialog: {
get() { return this.$store.state.settings.pasteDialog; },
set(value) { this.$store.dispatch('settings/set', { key: 'pasteDialog', value }); }
@@ -565,6 +564,17 @@ export default Vue.extend({
}
});
},
+ save(key, value) {
+ this.$store.dispatch('settings/set', {
+ key,
+ value
+ }).then(() => {
+ this.$root.dialog({
+ type: 'success',
+ text: this.$t('@._settings.saved')
+ })
+ });
+ },
customizeHome() {
location.href = '/?customize';
},
@@ -600,7 +610,10 @@ export default Vue.extend({
const sound = new Audio(`${url}/assets/message.mp3`);
sound.volume = this.$store.state.device.soundVolume;
sound.play();
- }
+ },
+ pastedFileNamePreview() {
+ return `${formatTimeString(new Date(), this.pastedFileName).replace(/{{number}}/g, `1`)}.png`
+ },
}
});
</script>
diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue
index 421d09a4dd..893f6575fb 100644
--- a/src/client/app/common/views/components/signup.vue
+++ b/src/client/app/common/views/components/signup.vue
@@ -43,7 +43,7 @@
</i18n>
</ui-switch>
<div v-if="meta.enableRecaptcha" class="g-recaptcha" :data-sitekey="meta.recaptchaSiteKey" style="margin: 16px 0;"></div>
- <ui-button type="submit" :disabled="!(meta.ToSUrl ? ToSAgreement : true) || passwordRetypeState == 'not-match'">{{ $t('create') }}</ui-button>
+ <ui-button type="submit" :disabled=" submitting || !(meta.ToSUrl ? ToSAgreement : true) || passwordRetypeState == 'not-match'">{{ $t('create') }}</ui-button>
</template>
</form>
</template>
@@ -70,6 +70,7 @@ export default Vue.extend({
passwordStrength: '',
passwordRetypeState: null,
meta: {},
+ submitting: false,
ToSAgreement: false
}
},
@@ -145,6 +146,9 @@ export default Vue.extend({
},
onSubmit() {
+ if (this.submitting) return;
+ this.submitting = true;
+
this.$root.api('signup', {
username: this.username,
password: this.password,
@@ -159,6 +163,8 @@ export default Vue.extend({
location.href = '/';
});
}).catch(() => {
+ this.submitting = false;
+
this.$root.dialog({
type: 'error',
text: this.$t('some-error')
diff --git a/src/client/app/common/views/components/url-preview.vue b/src/client/app/common/views/components/url-preview.vue
index 476c671e77..80aae5999d 100644
--- a/src/client/app/common/views/components/url-preview.vue
+++ b/src/client/app/common/views/components/url-preview.vue
@@ -66,6 +66,7 @@ export default Vue.extend({
(this.url.substr(local.length) === '/') ||
this.url.substr(local.length).startsWith('/@') ||
this.url.substr(local.length).startsWith('/notes/') ||
+ this.url.substr(local.length).startsWith('/tags/') ||
this.url.substr(local.length).startsWith('/pages/');
return {
local,
diff --git a/src/client/app/common/views/components/url.vue b/src/client/app/common/views/components/url.vue
index b1ca3f285c..3a304ad6e7 100644
--- a/src/client/app/common/views/components/url.vue
+++ b/src/client/app/common/views/components/url.vue
@@ -28,6 +28,7 @@ export default Vue.extend({
(this.url.substr(local.length) === '/') ||
this.url.substr(local.length).startsWith('/@') ||
this.url.substr(local.length).startsWith('/notes/') ||
+ this.url.substr(local.length).startsWith('/tags/') ||
this.url.substr(local.length).startsWith('/pages/'));
return {
local,
diff --git a/src/client/app/common/views/pages/page-editor/els/page-editor.el.radio-button.vue b/src/client/app/common/views/pages/page-editor/els/page-editor.el.radio-button.vue
new file mode 100644
index 0000000000..3401c46f47
--- /dev/null
+++ b/src/client/app/common/views/pages/page-editor/els/page-editor.el.radio-button.vue
@@ -0,0 +1,53 @@
+<template>
+<x-container @remove="() => $emit('remove')" :draggable="true">
+ <template #header><fa :icon="faBolt"/> {{ $t('blocks.radioButton') }}</template>
+
+ <section style="padding: 0 16px 16px 16px;">
+ <ui-input v-model="value.name"><template #prefix><fa :icon="faMagic"/></template><span>{{ $t('blocks._radioButton.name') }}</span></ui-input>
+ <ui-input v-model="value.title"><span>{{ $t('blocks._radioButton.title') }}</span></ui-input>
+ <ui-textarea v-model="values"><span>{{ $t('blocks._radioButton.values') }}</span></ui-textarea>
+ <ui-input v-model="value.default"><span>{{ $t('blocks._radioButton.default') }}</span></ui-input>
+ </section>
+</x-container>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
+import i18n from '../../../../../i18n';
+import XContainer from '../page-editor.container.vue';
+
+export default Vue.extend({
+ i18n: i18n('pages'),
+
+ components: {
+ XContainer
+ },
+
+ props: {
+ value: {
+ required: true
+ },
+ },
+
+ data() {
+ return {
+ values: '',
+ faBolt, faMagic
+ };
+ },
+
+ watch: {
+ values() {
+ Vue.set(this.value, 'values', this.values.split('\n'));
+ }
+ },
+
+ created() {
+ if (this.value.name == null) Vue.set(this.value, 'name', '');
+ if (this.value.title == null) Vue.set(this.value, 'title', '');
+ if (this.value.values == null) Vue.set(this.value, 'values', []);
+ this.values = this.value.values.join('\n');
+ },
+});
+</script>
diff --git a/src/client/app/common/views/pages/page-editor/page-editor.blocks.vue b/src/client/app/common/views/pages/page-editor/page-editor.blocks.vue
index c5f3419e7b..4d7293231f 100644
--- a/src/client/app/common/views/pages/page-editor/page-editor.blocks.vue
+++ b/src/client/app/common/views/pages/page-editor/page-editor.blocks.vue
@@ -19,10 +19,11 @@ import XSwitch from './els/page-editor.el.switch.vue';
import XIf from './els/page-editor.el.if.vue';
import XPost from './els/page-editor.el.post.vue';
import XCounter from './els/page-editor.el.counter.vue';
+import XRadioButton from './els/page-editor.el.radio-button.vue';
export default Vue.extend({
components: {
- XDraggable, XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter
+ XDraggable, XSection, XText, XImage, XButton, XTextarea, XTextInput, XTextareaInput, XNumberInput, XSwitch, XIf, XPost, XCounter, XRadioButton
},
props: {
diff --git a/src/client/app/common/views/pages/page-editor/page-editor.vue b/src/client/app/common/views/pages/page-editor/page-editor.vue
index ade7d86991..0162915c38 100644
--- a/src/client/app/common/views/pages/page-editor/page-editor.vue
+++ b/src/client/app/common/views/pages/page-editor/page-editor.vue
@@ -342,6 +342,7 @@ export default Vue.extend({
label: this.$t('input-blocks'),
items: [
{ value: 'button', text: this.$t('blocks.button') },
+ { value: 'radioButton', text: this.$t('blocks.radioButton') },
{ value: 'textInput', text: this.$t('blocks.textInput') },
{ value: 'textareaInput', text: this.$t('blocks.textareaInput') },
{ value: 'numberInput', text: this.$t('blocks.numberInput') },