diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 2df16db6a..ab4b10549 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -519,6 +519,8 @@ fixedWidgetsPosition: "ウィジェットの位置を固定する"
enablePlayer: "プレイヤーを開く"
disablePlayer: "プレイヤーを閉じる"
expandTweet: "ツイートを展開する"
+deck: "デッキ"
+undeck: "デッキ解除"
_theme:
explore: "テーマを探す"
@@ -651,6 +653,7 @@ _widgets:
rss: "RSSリーダー"
activity: "アクティビティ"
photos: "フォト"
+ digitalClock: "デジタル時計"
_cw:
hide: "隠す"
@@ -1129,3 +1132,15 @@ _notification:
yourFollowRequestAccepted: "フォローリクエストが承認されました"
youWereInvitedToGroup: "グループに招待されました"
+_deck:
+ alwaysShowMainColumn: "常にメインカラムを表示"
+ columnAlign: "カラムの寄せ"
+
+ _columns:
+ widgets: "ウィジェット"
+ notifications: "通知"
+ tl: "タイムライン"
+ antenna: "アンテナ"
+ list: "リスト"
+ mentions: "あなた宛て"
+ direct: "ダイレクト"
diff --git a/src/client/app.vue b/src/client/app.vue
index f1a834049..4f3918356 100644
--- a/src/client/app.vue
+++ b/src/client/app.vue
@@ -29,47 +29,7 @@
-
-
-
-
-
-
-
+
-
+
@@ -135,14 +95,17 @@ import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt,
import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons';
import { ResizeObserver } from '@juggle/resize-observer';
import { v4 as uuid } from 'uuid';
-import { host, instanceName } from './config';
+import { host } from './config';
import { search } from './scripts/search';
import { StickySidebar } from './scripts/sticky-sidebar';
+import { widgets } from './widgets';
+import XSidebar from './components/sidebar.vue';
const DESKTOP_THRESHOLD = 1100;
export default Vue.extend({
components: {
+ XSidebar,
XClock: () => import('./components/header-clock.vue').then(m => m.default),
MkButton: () => import('./components/ui/button.vue').then(m => m.default),
XDraggable: () => import('vuedraggable'),
@@ -152,19 +115,14 @@ export default Vue.extend({
return {
host: host,
pageKey: 0,
- showNav: false,
searching: false,
- accounts: [],
- lists: [],
connection: null,
searchQuery: '',
searchWait: false,
widgetsEditMode: false,
- menuDef: this.$store.getters.nav({
- search: this.search
- }),
isDesktop: window.innerWidth >= DESKTOP_THRESHOLD,
canBack: false,
+ menuDef: this.$store.getters.nav({}),
wallpaper: localStorage.getItem('wallpaper') != null,
faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram
};
@@ -210,30 +168,19 @@ export default Vue.extend({
return this.$store.state.deviceUser.menu;
},
- otherNavItemIndicated(): boolean {
- if (!this.$store.getters.isSignedIn) return false;
- for (const def in this.menuDef) {
- if (this.menu.includes(def)) continue;
- if (this.menuDef[def].indicated) return true;
- }
- return false;
- },
-
navIndicated(): boolean {
if (!this.$store.getters.isSignedIn) return false;
for (const def in this.menuDef) {
- if (def === 'timeline') continue;
- if (def === 'notifications') continue;
+ if (def === 'notifications') continue; // 通知は下にボタンとして表示されてるから
if (this.menuDef[def].indicated) return true;
}
return false;
}
},
- watch:{
+ watch: {
$route(to, from) {
this.pageKey++;
- this.showNav = false;
this.canBack = (window.history.length > 0 && !['index'].includes(to.name));
},
@@ -245,6 +192,8 @@ export default Vue.extend({
},
created() {
+ document.documentElement.style.overflowY = 'scroll';
+
if (this.$store.getters.isSignedIn) {
this.connection = this.$root.stream.useSharedConnection('main');
this.connection.on('notification', this.onNotification);
@@ -266,7 +215,7 @@ export default Vue.extend({
mounted() {
const adjustTitlePosition = () => {
- const left = this.$refs.main.getBoundingClientRect().left - this.$refs.nav.offsetWidth;
+ const left = this.$refs.main.getBoundingClientRect().left - this.$refs.nav.$el.offsetWidth;
if (left >= 0) {
this.$refs.title.style.left = left + 'px';
}
@@ -293,6 +242,10 @@ export default Vue.extend({
},
methods: {
+ showNav() {
+ this.$refs.nav.show();
+ },
+
attachSticky() {
if (!this.isDesktop) return;
if (this.$store.state.device.fixedWidgetsPosition) return;
@@ -351,180 +304,6 @@ export default Vue.extend({
}
},
- async openAccountMenu(ev) {
- const accounts = (await this.$root.api('users/show', { userIds: this.$store.state.device.accounts.map(x => x.id) })).filter(x => x.id !== this.$store.state.i.id);
-
- const accountItems = accounts.map(account => ({
- type: 'user',
- user: account,
- action: () => { this.switchAccount(account); }
- }));
-
- this.$root.menu({
- items: [...[{
- type: 'link',
- text: this.$t('profile'),
- to: `/@${ this.$store.state.i.username }`,
- avatar: this.$store.state.i,
- }, {
- type: 'link',
- text: this.$t('accountSettings'),
- to: '/my/settings',
- icon: faCog,
- }, null, ...accountItems, {
- icon: faPlus,
- text: this.$t('addAcount'),
- action: () => {
- this.$root.menu({
- items: [{
- text: this.$t('existingAcount'),
- action: () => { this.addAcount(); },
- }, {
- text: this.$t('createAccount'),
- action: () => { this.createAccount(); },
- }],
- align: 'left',
- fixed: true,
- width: 240,
- source: ev.currentTarget || ev.target,
- });
- },
- }]],
- align: 'left',
- fixed: true,
- width: 240,
- source: ev.currentTarget || ev.target,
- });
- },
-
- oepnInstanceMenu(ev) {
- this.$root.menu({
- items: [{
- type: 'link',
- text: this.$t('dashboard'),
- to: '/instance',
- icon: faTachometerAlt,
- }, null, {
- type: 'link',
- text: this.$t('settings'),
- to: '/instance/settings',
- icon: faCog,
- }, {
- type: 'link',
- text: this.$t('customEmojis'),
- to: '/instance/emojis',
- icon: faLaugh,
- }, {
- type: 'link',
- text: this.$t('users'),
- to: '/instance/users',
- icon: faUsers,
- }, {
- type: 'link',
- text: this.$t('files'),
- to: '/instance/files',
- icon: faCloud,
- }, {
- type: 'link',
- text: this.$t('jobQueue'),
- to: '/instance/queue',
- icon: faExchangeAlt,
- }, {
- type: 'link',
- text: this.$t('federation'),
- to: '/instance/federation',
- icon: faGlobe,
- }, {
- type: 'link',
- text: this.$t('relays'),
- to: '/instance/relays',
- icon: faProjectDiagram,
- }, {
- type: 'link',
- text: this.$t('announcements'),
- to: '/instance/announcements',
- icon: faBroadcastTower,
- }],
- align: 'left',
- fixed: true,
- width: 200,
- source: ev.currentTarget || ev.target,
- });
- },
-
- more(ev) {
- const items = Object.keys(this.menuDef).filter(k => !this.menu.includes(k)).map(k => this.menuDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({
- type: def.to ? 'link' : 'button',
- text: this.$t(def.title),
- icon: def.icon,
- to: def.to,
- action: def.action,
- indicate: def.indicated,
- }));
- this.$root.menu({
- items: [...items, null, {
- type: 'link',
- text: this.$t('help'),
- to: '/docs',
- icon: faQuestionCircle,
- }, {
- type: 'link',
- text: this.$t('aboutX', { x: instanceName || host }),
- to: '/about',
- icon: faInfoCircle,
- }, {
- type: 'link',
- text: this.$t('aboutMisskey'),
- to: '/about-misskey',
- icon: faInfoCircle,
- }],
- align: 'left',
- fixed: true,
- width: 200,
- source: ev.currentTarget || ev.target,
- });
- },
-
- async addAcount() {
- this.$root.new(await import('./components/signin-dialog.vue').then(m => m.default)).$once('login', res => {
- this.$store.dispatch('addAcount', res);
- this.$root.dialog({
- type: 'success',
- iconOnly: true, autoClose: true
- });
- });
- },
-
- async createAccount() {
- this.$root.new(await import('./components/signup-dialog.vue').then(m => m.default)).$once('signup', res => {
- this.$store.dispatch('addAcount', res);
- this.switchAccountWithToken(res.i);
- });
- },
-
- async switchAccount(account: any) {
- const token = this.$store.state.device.accounts.find((x: any) => x.id === account.id).token;
- this.switchAccountWithToken(token);
- },
-
- switchAccountWithToken(token: string) {
- this.$root.dialog({
- type: 'waiting',
- iconOnly: true
- });
-
- this.$root.api('i', {}, token).then((i: any) => {
- this.$store.dispatch('switchAccount', {
- ...i,
- token: token
- }).then(() => {
- this.$nextTick(() => {
- location.reload();
- });
- });
- });
- },
-
async onNotification(notification) {
if (document.visibilityState === 'visible') {
this.$root.stream.send('readNotification', {
@@ -540,8 +319,7 @@ export default Vue.extend({
},
widgetFunc(id) {
- const w = this.$refs[id][0];
- if (w.func) w.func();
+ this.$refs[id][0].setting();
},
onWidgetSort() {
@@ -549,18 +327,6 @@ export default Vue.extend({
},
async addWidget(place) {
- const widgets = [
- 'memo',
- 'notifications',
- 'timeline',
- 'calendar',
- 'rss',
- 'trends',
- 'clock',
- 'activity',
- 'photos',
- ];
-
const { canceled, result: widget } = await this.$root.dialog({
type: null,
title: this.$t('chooseWidget'),
@@ -594,36 +360,14 @@ export default Vue.extend({
diff --git a/src/client/components/deck/column-core.vue b/src/client/components/deck/column-core.vue
new file mode 100644
index 000000000..44f19e7ed
--- /dev/null
+++ b/src/client/components/deck/column-core.vue
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/client/components/deck/column.vue b/src/client/components/deck/column.vue
new file mode 100644
index 000000000..f7620e574
--- /dev/null
+++ b/src/client/components/deck/column.vue
@@ -0,0 +1,426 @@
+
+
+
+
+
+
+
+
diff --git a/src/client/components/deck/direct-column.vue b/src/client/components/deck/direct-column.vue
new file mode 100644
index 000000000..f340048d6
--- /dev/null
+++ b/src/client/components/deck/direct-column.vue
@@ -0,0 +1,39 @@
+
+
+ {{ column.name }}
+
+
+
+
+
+
diff --git a/src/client/components/deck/list-column.vue b/src/client/components/deck/list-column.vue
new file mode 100644
index 000000000..a3576e8d6
--- /dev/null
+++ b/src/client/components/deck/list-column.vue
@@ -0,0 +1,87 @@
+
+
+
+ {{ column.name }}
+
+
+ $emit('loaded')"/>
+
+
+
+
+
+
diff --git a/src/client/components/deck/mentions-column.vue b/src/client/components/deck/mentions-column.vue
new file mode 100644
index 000000000..19e49d2a8
--- /dev/null
+++ b/src/client/components/deck/mentions-column.vue
@@ -0,0 +1,39 @@
+
+
+ {{ column.name }}
+
+
+
+
+
+
diff --git a/src/client/components/deck/notifications-column.vue b/src/client/components/deck/notifications-column.vue
new file mode 100644
index 000000000..58873aa13
--- /dev/null
+++ b/src/client/components/deck/notifications-column.vue
@@ -0,0 +1,69 @@
+
+
+ {{ column.name }}
+
+
+
+
+
+
diff --git a/src/client/components/deck/tl-column.vue b/src/client/components/deck/tl-column.vue
new file mode 100644
index 000000000..c3ee67af3
--- /dev/null
+++ b/src/client/components/deck/tl-column.vue
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+ {{ column.name }}
+
+
+
+
+
+ {{ $t('disabled-timeline.title') }}
+
+
{{ $t('disabled-timeline.description') }}
+
+ $emit('loaded')" @queue="queueUpdated" @note="onNote" :key="column.tl"/>
+
+
+
+
+
+
diff --git a/src/client/components/deck/widgets-column.vue b/src/client/components/deck/widgets-column.vue
new file mode 100644
index 000000000..37b17451e
--- /dev/null
+++ b/src/client/components/deck/widgets-column.vue
@@ -0,0 +1,151 @@
+
+
+ {{ column.name }}
+
+
+
+
+
+
+
+
diff --git a/src/client/components/error.vue b/src/client/components/error.vue
index b1d91fb3e..90efa700b 100644
--- a/src/client/components/error.vue
+++ b/src/client/components/error.vue
@@ -40,7 +40,7 @@ export default Vue.extend({
> img {
vertical-align: bottom;
- height: 150px;
+ height: 128px;
margin-bottom: 16px;
border-radius: 16px;
}
diff --git a/src/client/components/form-window.vue b/src/client/components/form-window.vue
new file mode 100644
index 000000000..25eee9164
--- /dev/null
+++ b/src/client/components/form-window.vue
@@ -0,0 +1,71 @@
+
+ { $emit('closed'); destroyDom(); }" :with-ok-button="true" :ok-button-disabled="false" @ok="ok()" :can-close="false">
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/client/components/modal.vue b/src/client/components/modal.vue
index 1a9d98a8c..f941d4d50 100644
--- a/src/client/components/modal.vue
+++ b/src/client/components/modal.vue
@@ -1,10 +1,10 @@
-
+ {}">
{ $emit('closed'); destroyDom(); }">
-
+ {}">
@@ -14,6 +14,11 @@ import Vue from 'vue';
export default Vue.extend({
props: {
+ canClose: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
data() {
return {
diff --git a/src/client/components/note-header.vue b/src/client/components/note-header.vue
index 93cf2cdf3..039287818 100644
--- a/src/client/components/note-header.vue
+++ b/src/client/components/note-header.vue
@@ -54,7 +54,6 @@ export default Vue.extend({
margin: 0 .5em 0 0;
padding: 0;
overflow: hidden;
- color: var(--noteHeaderName);
font-size: 1em;
font-weight: bold;
text-decoration: none;
diff --git a/src/client/components/note.vue b/src/client/components/note.vue
index 118fef661..badb9f12f 100644
--- a/src/client/components/note.vue
+++ b/src/client/components/note.vue
@@ -724,61 +724,6 @@ export default Vue.extend({
transition: box-shadow 0.1s ease;
overflow: hidden;
- &.max-width_500px {
- font-size: 0.9em;
- }
-
- &.max-width_450px {
- > .renote {
- padding: 8px 16px 0 16px;
- }
-
- > .article {
- padding: 14px 16px 9px;
-
- > .avatar {
- margin: 0 10px 8px 0;
- width: 50px;
- height: 50px;
- }
- }
- }
-
- &.max-width_350px {
- > .article {
- > .main {
- > .footer {
- > .button {
- &:not(:last-child) {
- margin-right: 18px;
- }
- }
- }
- }
- }
- }
-
- &.max-width_300px {
- font-size: 0.825em;
-
- > .article {
- > .avatar {
- width: 44px;
- height: 44px;
- }
-
- > .main {
- > .footer {
- > .button {
- &:not(:last-child) {
- margin-right: 12px;
- }
- }
- }
- }
- }
- }
-
&:focus {
outline: none;
box-shadow: 0 0 0 3px var(--focus);
@@ -797,10 +742,6 @@ export default Vue.extend({
white-space: pre;
color: #d28a3f;
- @media (max-width: 450px) {
- padding: 8px 16px 0 16px;
- }
-
> [data-icon] {
margin-right: 4px;
}
@@ -985,5 +926,64 @@ export default Vue.extend({
> .reply {
border-top: solid 1px var(--divider);
}
+
+ &.max-width_500px {
+ font-size: 0.9em;
+ }
+
+ &.max-width_450px {
+ > .renote {
+ padding: 8px 16px 0 16px;
+ }
+
+ > .info {
+ padding: 8px 16px 0 16px;
+ }
+
+ > .article {
+ padding: 14px 16px 9px;
+
+ > .avatar {
+ margin: 0 10px 8px 0;
+ width: 50px;
+ height: 50px;
+ }
+ }
+ }
+
+ &.max-width_350px {
+ > .article {
+ > .main {
+ > .footer {
+ > .button {
+ &:not(:last-child) {
+ margin-right: 18px;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ &.max-width_300px {
+ font-size: 0.825em;
+
+ > .article {
+ > .avatar {
+ width: 44px;
+ height: 44px;
+ }
+
+ > .main {
+ > .footer {
+ > .button {
+ &:not(:last-child) {
+ margin-right: 12px;
+ }
+ }
+ }
+ }
+ }
+ }
}
diff --git a/src/client/components/sidebar.vue b/src/client/components/sidebar.vue
new file mode 100644
index 000000000..3ddef7d12
--- /dev/null
+++ b/src/client/components/sidebar.vue
@@ -0,0 +1,488 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/client/components/timeline.vue b/src/client/components/timeline.vue
index bd1901a62..ce0fd95ca 100644
--- a/src/client/components/timeline.vue
+++ b/src/client/components/timeline.vue
@@ -17,9 +17,11 @@ export default Vue.extend({
required: true
},
list: {
+ type: String,
required: false
},
antenna: {
+ type: String,
required: false
},
sound: {
@@ -53,6 +55,8 @@ export default Vue.extend({
const _note = JSON.parse(JSON.stringify(note)); // deepcopy
(this.$refs.tl as any).prepend(_note);
+ this.$emit('note');
+
if (this.sound) {
this.$root.sound(note.userId === this.$store.state.i.id ? 'noteMy' : 'note');
}
@@ -77,10 +81,10 @@ export default Vue.extend({
if (this.src == 'antenna') {
endpoint = 'antennas/notes';
this.query = {
- antennaId: this.antenna.id
+ antennaId: this.antenna
};
this.connection = this.$root.stream.connectToChannel('antenna', {
- antennaId: this.antenna.id
+ antennaId: this.antenna
});
this.connection.on('note', prepend);
} else if (this.src == 'home') {
@@ -106,10 +110,10 @@ export default Vue.extend({
} else if (this.src == 'list') {
endpoint = 'notes/user-list-timeline';
this.query = {
- listId: this.list.id
+ listId: this.list
};
this.connection = this.$root.stream.connectToChannel('userList', {
- listId: this.list.id
+ listId: this.list
});
this.connection.on('note', prepend);
this.connection.on('userAdded', onUserAdded);
diff --git a/src/client/components/ui/container.vue b/src/client/components/ui/container.vue
index 3fed1f65c..6a718439a 100644
--- a/src/client/components/ui/container.vue
+++ b/src/client/components/ui/container.vue
@@ -1,5 +1,5 @@
-
+
@@ -47,6 +47,11 @@ export default Vue.extend({
required: false,
default: true
},
+ scrollable: {
+ type: Boolean,
+ required: false,
+ default: false
+ },
},
data() {
return {
@@ -107,10 +112,19 @@ export default Vue.extend({
box-shadow: none !important;
}
+ &.scrollable {
+ display: flex;
+ flex-direction: column;
+
+ > div {
+ overflow: auto;
+ }
+ }
+
> header {
position: relative;
box-shadow: 0 1px 0 0 var(--panelHeaderDivider);
- z-index: 1;
+ z-index: 2;
background: var(--panelHeaderBg);
color: var(--panelHeaderFg);
@@ -118,10 +132,6 @@ export default Vue.extend({
margin: 0;
padding: 12px 16px;
- @media (max-width: 500px) {
- padding: 8px 10px;
- }
-
> [data-icon] {
margin-right: 6px;
}
@@ -141,5 +151,21 @@ export default Vue.extend({
height: 100%;
}
}
+
+ &.max-width_500px {
+ > header {
+ > .title {
+ padding: 8px 10px;
+ }
+ }
+ }
+}
+
+._forceContainerFull_ .ukygtjoj {
+ > header {
+ > .title {
+ padding: 12px 16px !important;
+ }
+ }
}
diff --git a/src/client/components/ui/input.vue b/src/client/components/ui/input.vue
index c9f62e3cc..d5317db7f 100644
--- a/src/client/components/ui/input.vue
+++ b/src/client/components/ui/input.vue
@@ -20,6 +20,7 @@
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
+ :step="step"
@focus="focused = true"
@blur="focused = false"
@keydown="$emit('keydown', $event)"
@@ -36,6 +37,7 @@
:pattern="pattern"
:autocomplete="autocomplete"
:spellcheck="spellcheck"
+ :step="step"
@focus="focused = true"
@blur="focused = false"
@keydown="$emit('keydown', $event)"
@@ -114,6 +116,9 @@ export default Vue.extend({
spellcheck: {
required: false
},
+ step: {
+ required: false
+ },
debounce: {
required: false
},
@@ -164,7 +169,7 @@ export default Vue.extend({
},
v(v) {
if (this.type === 'number') {
- this.$emit('input', parseInt(v, 10));
+ this.$emit('input', parseFloat(v));
} else {
this.$emit('input', v);
}
@@ -297,7 +302,7 @@ export default Vue.extend({
pointer-events: none;
transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
transition-duration: 0.3s;
- font-size: 16px;
+ font-size: 1em;
line-height: 32px;
color: var(--inputLabel);
pointer-events: none;
@@ -312,7 +317,7 @@ export default Vue.extend({
top: -17px;
left: 0 !important;
pointer-events: none;
- font-size: 16px;
+ font-size: 1em;
line-height: 32px;
color: var(--inputLabel);
pointer-events: none;
@@ -343,7 +348,7 @@ export default Vue.extend({
padding: 0;
font: inherit;
font-weight: normal;
- font-size: 16px;
+ font-size: 1em;
line-height: $height;
color: var(--inputText);
background: transparent;
@@ -364,7 +369,7 @@ export default Vue.extend({
position: absolute;
z-index: 1;
top: 0;
- font-size: 16px;
+ font-size: 1em;
line-height: 32px;
color: var(--inputLabel);
pointer-events: none;
diff --git a/src/client/components/ui/select.vue b/src/client/components/ui/select.vue
index ce2194971..55f76553a 100644
--- a/src/client/components/ui/select.vue
+++ b/src/client/components/ui/select.vue
@@ -135,7 +135,7 @@ export default Vue.extend({
pointer-events: none;
transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
transition-duration: 0.3s;
- font-size: 16px;
+ font-size: 1em;
line-height: 32px;
pointer-events: none;
//will-change transform
@@ -150,7 +150,7 @@ export default Vue.extend({
padding: 0;
font: inherit;
font-weight: normal;
- font-size: 16px;
+ font-size: 1em;
height: 32px;
background: none;
border: none;
@@ -170,7 +170,7 @@ export default Vue.extend({
display: block;
align-self: center;
justify-self: center;
- font-size: 16px;
+ font-size: 1em;
line-height: 32px;
color: rgba(#000, 0.54);
pointer-events: none;
diff --git a/src/client/components/ui/switch.vue b/src/client/components/ui/switch.vue
index 18a2ec33f..9652a0102 100644
--- a/src/client/components/ui/switch.vue
+++ b/src/client/components/ui/switch.vue
@@ -5,7 +5,7 @@
role="switch"
:aria-checked="checked"
:aria-disabled="disabled"
- @click="toggle"
+ @click.prevent="toggle"
>
- { $emit('closed'); destroyDom(); }">
+ { $emit('closed'); destroyDom(); }" :can-close="canClose">
diff --git a/src/client/pages/note.vue b/src/client/pages/note.vue
index 48629a4eb..5464875df 100644
--- a/src/client/pages/note.vue
+++ b/src/client/pages/note.vue
@@ -15,14 +15,15 @@
-
-
-
+
+
+
+
diff --git a/src/client/pages/preferences/index.vue b/src/client/pages/preferences/index.vue
index 92d745a84..ffc885876 100644
--- a/src/client/pages/preferences/index.vue
+++ b/src/client/pages/preferences/index.vue
@@ -51,6 +51,20 @@
+
+ {{ $t('deck') }}
+
+
+ {{ $t('_deck.alwaysShowMainColumn') }}
+
+
+
+
{{ $t('_deck.columnAlign') }}
+
{{ $t('left') }}
+
{{ $t('center') }}
+
+
+
{{ $t('accessibility') }}
@@ -93,7 +107,7 @@
diff --git a/src/client/widgets/define.ts b/src/client/widgets/define.ts
index 96b1b4ab5..107045bf4 100644
--- a/src/client/widgets/define.ts
+++ b/src/client/widgets/define.ts
@@ -1,6 +1,7 @@
import Vue from 'vue';
+import { Form } from '../scripts/form';
-export default function
(data: {
+export default function (data: {
name: string;
props?: () => T;
}) {
@@ -15,22 +16,22 @@ export default function (data: {
}
},
+ data() {
+ return {
+ bakedOldProps: null
+ };
+ },
+
computed: {
id(): string {
return this.widget.id;
},
- props(): T {
+ props(): Record {
return this.widget.data;
}
},
- data() {
- return {
- bakedOldProps: null
- };
- },
-
created() {
this.mergeProps();
@@ -45,11 +46,26 @@ export default function (data: {
const defaultProps = data.props();
for (const prop of Object.keys(defaultProps)) {
if (this.props.hasOwnProperty(prop)) continue;
- Vue.set(this.props, prop, defaultProps[prop]);
+ Vue.set(this.props, prop, defaultProps[prop].default);
}
}
},
+ async setting() {
+ const form = data.props();
+ for (const item of Object.keys(form)) {
+ form[item].default = this.props[item];
+ }
+ const { canceled, result } = await this.$root.form(data.name, form);
+ if (canceled) return;
+
+ for (const key of Object.keys(result)) {
+ Vue.set(this.props, key, result[key]);
+ }
+
+ this.save();
+ },
+
save() {
this.$store.commit('deviceUser/updateWidget', this.widget);
}
diff --git a/src/client/widgets/digital-clock.vue b/src/client/widgets/digital-clock.vue
new file mode 100644
index 000000000..0e68fe0ff
--- /dev/null
+++ b/src/client/widgets/digital-clock.vue
@@ -0,0 +1,75 @@
+
+
+
+
+ :
+
+ :
+
+ :
+
+
+
+
+
+
+
+
diff --git a/src/client/widgets/index.ts b/src/client/widgets/index.ts
index 878d42c0c..2d27d27e5 100644
--- a/src/client/widgets/index.ts
+++ b/src/client/widgets/index.ts
@@ -10,3 +10,17 @@ Vue.component('mkw-trends', () => import('./trends.vue').then(m => m.default));
Vue.component('mkw-clock', () => import('./clock.vue').then(m => m.default));
Vue.component('mkw-activity', () => import('./activity.vue').then(m => m.default));
Vue.component('mkw-photos', () => import('./photos.vue').then(m => m.default));
+Vue.component('mkw-digitalClock', () => import('./digital-clock.vue').then(m => m.default));
+
+export const widgets = [
+ 'memo',
+ 'notifications',
+ 'timeline',
+ 'calendar',
+ 'rss',
+ 'trends',
+ 'clock',
+ 'activity',
+ 'photos',
+ 'digitalClock',
+];
diff --git a/src/client/widgets/memo.vue b/src/client/widgets/memo.vue
index cdc716b9f..0d319b225 100644
--- a/src/client/widgets/memo.vue
+++ b/src/client/widgets/memo.vue
@@ -1,14 +1,12 @@
-
-
- {{ $t('_widgets.memo') }}
+
+ {{ $t('_widgets.memo') }}
-
-
-
-
-
-
+
+
+
+
+
-
-
diff --git a/src/client/widgets/photos.vue b/src/client/widgets/photos.vue
index 6e4e43a56..2b8399df9 100644
--- a/src/client/widgets/photos.vue
+++ b/src/client/widgets/photos.vue
@@ -1,19 +1,17 @@
-
-
- {{ $t('_widgets.photos') }}
+
+ {{ $t('_widgets.photos') }}
-
+
diff --git a/src/client/widgets/trends.vue b/src/client/widgets/trends.vue
index 61f5bfbd3..d4a4b2d28 100644
--- a/src/client/widgets/trends.vue
+++ b/src/client/widgets/trends.vue
@@ -1,22 +1,20 @@
-
-
- {{ $t('_widgets.trends') }}
+
+ {{ $t('_widgets.trends') }}
-
-
-
-
-
-
#{{ stat.tag }}
-
{{ $t('nUsersMentioned', { n: stat.usersCount }) }}
-
-
+
+
+
+
+
+
#{{ stat.tag }}
+
{{ $t('nUsersMentioned', { n: stat.usersCount }) }}
-
-
-
-
+
+
+
+
+