summaryrefslogtreecommitdiff
path: root/src/web
diff options
context:
space:
mode:
authorこぴなたみぽ <syuilotan@yahoo.co.jp>2018-02-09 09:46:23 +0900
committerこぴなたみぽ <syuilotan@yahoo.co.jp>2018-02-09 09:46:23 +0900
commitd1aba96a2909654e9869edd18b43c5f863719e99 (patch)
treead254255cd9405cdf3cf2835c3b5fb07722c7676 /src/web
parentwip (diff)
downloadmisskey-d1aba96a2909654e9869edd18b43c5f863719e99.tar.gz
misskey-d1aba96a2909654e9869edd18b43c5f863719e99.tar.bz2
misskey-d1aba96a2909654e9869edd18b43c5f863719e99.zip
wip
Diffstat (limited to 'src/web')
-rw-r--r--src/web/app/desktop/tags/home.tag388
-rw-r--r--src/web/app/desktop/tags/home.vue392
2 files changed, 392 insertions, 388 deletions
diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag
deleted file mode 100644
index 827622930d..0000000000
--- a/src/web/app/desktop/tags/home.tag
+++ /dev/null
@@ -1,388 +0,0 @@
-<mk-home data-customize={ opts.customize }>
- <div class="customize" v-if="opts.customize">
- <a href="/">%fa:check%完了</a>
- <div>
- <div class="adder">
- <p>ウィジェットを追加:</p>
- <select ref="widgetSelector">
- <option value="profile">プロフィール</option>
- <option value="calendar">カレンダー</option>
- <option value="timemachine">カレンダー(タイムマシン)</option>
- <option value="activity">アクティビティ</option>
- <option value="rss-reader">RSSリーダー</option>
- <option value="trends">トレンド</option>
- <option value="photo-stream">フォトストリーム</option>
- <option value="slideshow">スライドショー</option>
- <option value="version">バージョン</option>
- <option value="broadcast">ブロードキャスト</option>
- <option value="notifications">通知</option>
- <option value="user-recommendation">おすすめユーザー</option>
- <option value="recommended-polls">投票</option>
- <option value="post-form">投稿フォーム</option>
- <option value="messaging">メッセージ</option>
- <option value="channel">チャンネル</option>
- <option value="access-log">アクセスログ</option>
- <option value="server">サーバー情報</option>
- <option value="donation">寄付のお願い</option>
- <option value="nav">ナビゲーション</option>
- <option value="tips">ヒント</option>
- </select>
- <button @click="addWidget">追加</button>
- </div>
- <div class="trash">
- <div ref="trash"></div>
- <p>ゴミ箱</p>
- </div>
- </div>
- </div>
- <div class="main">
- <div class="left">
- <div ref="left" data-place="left"></div>
- </div>
- <main ref="main">
- <div class="maintop" ref="maintop" data-place="main" v-if="opts.customize"></div>
- <mk-timeline-home-widget ref="tl" v-if="mode == 'timeline'"/>
- <mk-mentions-home-widget ref="tl" v-if="mode == 'mentions'"/>
- </main>
- <div class="right">
- <div ref="right" data-place="right"></div>
- </div>
- </div>
- <style lang="stylus" scoped>
- :scope
- display block
-
- &[data-customize]
- padding-top 48px
- background-image url('/assets/desktop/grid.svg')
-
- > .main > main > *:not(.maintop)
- cursor not-allowed
-
- > *
- pointer-events none
-
- &:not([data-customize])
- > .main > *:empty
- display none
-
- > .customize
- position fixed
- z-index 1000
- top 0
- left 0
- width 100%
- height 48px
- background #f7f7f7
- box-shadow 0 1px 1px rgba(0, 0, 0, 0.075)
-
- > a
- display block
- position absolute
- z-index 1001
- top 0
- right 0
- padding 0 16px
- line-height 48px
- text-decoration none
- color $theme-color-foreground
- background $theme-color
- transition background 0.1s ease
-
- &:hover
- background lighten($theme-color, 10%)
-
- &:active
- background darken($theme-color, 10%)
- transition background 0s ease
-
- > [data-fa]
- margin-right 8px
-
- > div
- display flex
- margin 0 auto
- max-width 1200px - 32px
-
- > div
- width 50%
-
- &.adder
- > p
- display inline
- line-height 48px
-
- &.trash
- border-left solid 1px #ddd
-
- > div
- width 100%
- height 100%
-
- > p
- position absolute
- top 0
- left 0
- width 100%
- line-height 48px
- margin 0
- text-align center
- pointer-events none
-
- > .main
- display flex
- justify-content center
- margin 0 auto
- max-width 1200px
-
- > *
- .customize-container
- cursor move
-
- > *
- pointer-events none
-
- > main
- padding 16px
- width calc(100% - 275px * 2)
-
- > *:not(.maintop):not(:last-child)
- > .maintop > *:not(:last-child)
- margin-bottom 16px
-
- > .maintop
- min-height 64px
- margin-bottom 16px
-
- > *:not(main)
- width 275px
-
- > *
- padding 16px 0 16px 0
-
- > *:not(:last-child)
- margin-bottom 16px
-
- > .left
- padding-left 16px
-
- > .right
- padding-right 16px
-
- @media (max-width 1100px)
- > *:not(main)
- display none
-
- > main
- float none
- width 100%
- max-width 700px
- margin 0 auto
-
- </style>
- <script lang="typescript">
- import uuid from 'uuid';
- import Sortable from 'sortablejs';
- import dialog from '../scripts/dialog';
- import ScrollFollower from '../scripts/scroll-follower';
-
- this.mixin('i');
- this.mixin('api');
-
- this.mode = this.opts.mode || 'timeline';
-
- this.home = [];
-
- this.bakeHomeData = () => JSON.stringify(this.I.client_settings.home);
- this.bakedHomeData = this.bakeHomeData();
-
- this.on('mount', () => {
- this.$refs.tl.on('loaded', () => {
- this.trigger('loaded');
- });
-
- this.I.on('refreshed', this.onMeRefreshed);
-
- this.I.client_settings.home.forEach(widget => {
- try {
- this.setWidget(widget);
- } catch (e) {
- // noop
- }
- });
-
- if (!this.opts.customize) {
- if (this.$refs.left.children.length == 0) {
- this.$refs.left.parentNode.removeChild(this.$refs.left);
- }
- if (this.$refs.right.children.length == 0) {
- this.$refs.right.parentNode.removeChild(this.$refs.right);
- }
- }
-
- if (this.opts.customize) {
- dialog('%fa:info-circle%カスタマイズのヒント',
- '<p>ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。</p>' +
- '<p>一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。</p>' +
- '<p>ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。</p>' +
- '<p>カスタマイズを終了するには、右上の「完了」をクリックします。</p>',
- [{
- text: 'Got it!'
- }]);
-
- const sortableOption = {
- group: 'kyoppie',
- animation: 150,
- onMove: evt => {
- const id = evt.dragged.getAttribute('data-widget-id');
- this.home.find(tag => tag.id == id).update({ place: evt.to.getAttribute('data-place') });
- },
- onSort: () => {
- this.saveHome();
- }
- };
-
- new Sortable(this.$refs.left, sortableOption);
- new Sortable(this.$refs.right, sortableOption);
- new Sortable(this.$refs.maintop, sortableOption);
- new Sortable(this.$refs.trash, Object.assign({}, sortableOption, {
- onAdd: evt => {
- const el = evt.item;
- const id = el.getAttribute('data-widget-id');
- el.parentNode.removeChild(el);
- this.I.client_settings.home = this.I.client_settings.home.filter(w => w.id != id);
- this.saveHome();
- }
- }));
- }
-
- if (!this.opts.customize) {
- this.scrollFollowerLeft = this.$refs.left.parentNode ? new ScrollFollower(this.$refs.left, this.root.getBoundingClientRect().top) : null;
- this.scrollFollowerRight = this.$refs.right.parentNode ? new ScrollFollower(this.$refs.right, this.root.getBoundingClientRect().top) : null;
- }
- });
-
- this.on('unmount', () => {
- this.I.off('refreshed', this.onMeRefreshed);
-
- this.home.forEach(widget => {
- widget.unmount();
- });
-
- if (!this.opts.customize) {
- if (this.scrollFollowerLeft) this.scrollFollowerLeft.dispose();
- if (this.scrollFollowerRight) this.scrollFollowerRight.dispose();
- }
- });
-
- this.onMeRefreshed = () => {
- if (this.bakedHomeData != this.bakeHomeData()) {
- alert('別の場所でホームが編集されました。ページを再度読み込みすると編集が反映されます。');
- }
- };
-
- this.setWidget = (widget, prepend = false) => {
- const el = document.createElement(`mk-${widget.name}-home-widget`);
-
- let actualEl;
-
- if (this.opts.customize) {
- const container = document.createElement('div');
- container.classList.add('customize-container');
- container.setAttribute('data-widget-id', widget.id);
- container.appendChild(el);
- actualEl = container;
- } else {
- actualEl = el;
- }
-
- switch (widget.place) {
- case 'left':
- if (prepend) {
- this.$refs.left.insertBefore(actualEl, this.$refs.left.firstChild);
- } else {
- this.$refs.left.appendChild(actualEl);
- }
- break;
- case 'right':
- if (prepend) {
- this.$refs.right.insertBefore(actualEl, this.$refs.right.firstChild);
- } else {
- this.$refs.right.appendChild(actualEl);
- }
- break;
- case 'main':
- if (this.opts.customize) {
- this.$refs.maintop.appendChild(actualEl);
- } else {
- this.$refs.main.insertBefore(actualEl, this.$refs.tl.root);
- }
- break;
- }
-
- const tag = riot.mount(el, {
- id: widget.id,
- data: widget.data,
- place: widget.place,
- tl: this.$refs.tl
- })[0];
-
- this.home.push(tag);
-
- if (this.opts.customize) {
- actualEl.oncontextmenu = e => {
- e.preventDefault();
- e.stopImmediatePropagation();
- if (tag.func) tag.func();
- return false;
- };
- }
- };
-
- this.addWidget = () => {
- const widget = {
- name: this.$refs.widgetSelector.options[this.$refs.widgetSelector.selectedIndex].value,
- id: uuid(),
- place: 'left',
- data: {}
- };
-
- this.I.client_settings.home.unshift(widget);
-
- this.setWidget(widget, true);
-
- this.saveHome();
- };
-
- this.saveHome = () => {
- const data = [];
-
- Array.from(this.$refs.left.children).forEach(el => {
- const id = el.getAttribute('data-widget-id');
- const widget = this.I.client_settings.home.find(w => w.id == id);
- widget.place = 'left';
- data.push(widget);
- });
-
- Array.from(this.$refs.right.children).forEach(el => {
- const id = el.getAttribute('data-widget-id');
- const widget = this.I.client_settings.home.find(w => w.id == id);
- widget.place = 'right';
- data.push(widget);
- });
-
- Array.from(this.$refs.maintop.children).forEach(el => {
- const id = el.getAttribute('data-widget-id');
- const widget = this.I.client_settings.home.find(w => w.id == id);
- widget.place = 'main';
- data.push(widget);
- });
-
- this.api('i/update_home', {
- home: data
- }).then(() => {
- this.I.update();
- });
- };
- </script>
-</mk-home>
diff --git a/src/web/app/desktop/tags/home.vue b/src/web/app/desktop/tags/home.vue
new file mode 100644
index 0000000000..ee12200ba3
--- /dev/null
+++ b/src/web/app/desktop/tags/home.vue
@@ -0,0 +1,392 @@
+<template>
+ <div :data-customize="customize">
+ <div class="customize" v-if="customize">
+ <a href="/">%fa:check%完了</a>
+ <div>
+ <div class="adder">
+ <p>ウィジェットを追加:</p>
+ <select ref="widgetSelector">
+ <option value="profile">プロフィール</option>
+ <option value="calendar">カレンダー</option>
+ <option value="timemachine">カレンダー(タイムマシン)</option>
+ <option value="activity">アクティビティ</option>
+ <option value="rss-reader">RSSリーダー</option>
+ <option value="trends">トレンド</option>
+ <option value="photo-stream">フォトストリーム</option>
+ <option value="slideshow">スライドショー</option>
+ <option value="version">バージョン</option>
+ <option value="broadcast">ブロードキャスト</option>
+ <option value="notifications">通知</option>
+ <option value="user-recommendation">おすすめユーザー</option>
+ <option value="recommended-polls">投票</option>
+ <option value="post-form">投稿フォーム</option>
+ <option value="messaging">メッセージ</option>
+ <option value="channel">チャンネル</option>
+ <option value="access-log">アクセスログ</option>
+ <option value="server">サーバー情報</option>
+ <option value="donation">寄付のお願い</option>
+ <option value="nav">ナビゲーション</option>
+ <option value="tips">ヒント</option>
+ </select>
+ <button @click="addWidget">追加</button>
+ </div>
+ <div class="trash">
+ <div ref="trash"></div>
+ <p>ゴミ箱</p>
+ </div>
+ </div>
+ </div>
+ <div class="main">
+ <div class="left">
+ <div ref="left" data-place="left"></div>
+ </div>
+ <main ref="main">
+ <div class="maintop" ref="maintop" data-place="main" v-if="customize"></div>
+ <mk-timeline-home-widget ref="tl" v-if="mode == 'timeline'"/>
+ <mk-mentions-home-widget ref="tl" v-if="mode == 'mentions'"/>
+ </main>
+ <div class="right">
+ <div ref="right" data-place="right"></div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<style lang="stylus" scoped>
+ :scope
+ display block
+
+ &[data-customize]
+ padding-top 48px
+ background-image url('/assets/desktop/grid.svg')
+
+ > .main > main > *:not(.maintop)
+ cursor not-allowed
+
+ > *
+ pointer-events none
+
+ &:not([data-customize])
+ > .main > *:empty
+ display none
+
+ > .customize
+ position fixed
+ z-index 1000
+ top 0
+ left 0
+ width 100%
+ height 48px
+ background #f7f7f7
+ box-shadow 0 1px 1px rgba(0, 0, 0, 0.075)
+
+ > a
+ display block
+ position absolute
+ z-index 1001
+ top 0
+ right 0
+ padding 0 16px
+ line-height 48px
+ text-decoration none
+ color $theme-color-foreground
+ background $theme-color
+ transition background 0.1s ease
+
+ &:hover
+ background lighten($theme-color, 10%)
+
+ &:active
+ background darken($theme-color, 10%)
+ transition background 0s ease
+
+ > [data-fa]
+ margin-right 8px
+
+ > div
+ display flex
+ margin 0 auto
+ max-width 1200px - 32px
+
+ > div
+ width 50%
+
+ &.adder
+ > p
+ display inline
+ line-height 48px
+
+ &.trash
+ border-left solid 1px #ddd
+
+ > div
+ width 100%
+ height 100%
+
+ > p
+ position absolute
+ top 0
+ left 0
+ width 100%
+ line-height 48px
+ margin 0
+ text-align center
+ pointer-events none
+
+ > .main
+ display flex
+ justify-content center
+ margin 0 auto
+ max-width 1200px
+
+ > *
+ .customize-container
+ cursor move
+
+ > *
+ pointer-events none
+
+ > main
+ padding 16px
+ width calc(100% - 275px * 2)
+
+ > *:not(.maintop):not(:last-child)
+ > .maintop > *:not(:last-child)
+ margin-bottom 16px
+
+ > .maintop
+ min-height 64px
+ margin-bottom 16px
+
+ > *:not(main)
+ width 275px
+
+ > *
+ padding 16px 0 16px 0
+
+ > *:not(:last-child)
+ margin-bottom 16px
+
+ > .left
+ padding-left 16px
+
+ > .right
+ padding-right 16px
+
+ @media (max-width 1100px)
+ > *:not(main)
+ display none
+
+ > main
+ float none
+ width 100%
+ max-width 700px
+ margin 0 auto
+
+</style>
+
+<script lang="typescript">
+ import uuid from 'uuid';
+ import Sortable from 'sortablejs';
+ import dialog from '../scripts/dialog';
+ import ScrollFollower from '../scripts/scroll-follower';
+
+ this.mixin('i');
+ this.mixin('api');
+
+ this.mode = this.opts.mode || 'timeline';
+
+ this.home = [];
+
+ this.bakeHomeData = () => JSON.stringify(this.I.client_settings.home);
+ this.bakedHomeData = this.bakeHomeData();
+
+ this.on('mount', () => {
+ this.$refs.tl.on('loaded', () => {
+ this.trigger('loaded');
+ });
+
+ this.I.on('refreshed', this.onMeRefreshed);
+
+ this.I.client_settings.home.forEach(widget => {
+ try {
+ this.setWidget(widget);
+ } catch (e) {
+ // noop
+ }
+ });
+
+ if (!this.opts.customize) {
+ if (this.$refs.left.children.length == 0) {
+ this.$refs.left.parentNode.removeChild(this.$refs.left);
+ }
+ if (this.$refs.right.children.length == 0) {
+ this.$refs.right.parentNode.removeChild(this.$refs.right);
+ }
+ }
+
+ if (this.opts.customize) {
+ dialog('%fa:info-circle%カスタマイズのヒント',
+ '<p>ホームのカスタマイズでは、ウィジェットを追加/削除したり、ドラッグ&ドロップして並べ替えたりすることができます。</p>' +
+ '<p>一部のウィジェットは、<strong><strong>右</strong>クリック</strong>することで表示を変更することができます。</p>' +
+ '<p>ウィジェットを削除するには、ヘッダーの<strong>「ゴミ箱」</strong>と書かれたエリアにウィジェットをドラッグ&ドロップします。</p>' +
+ '<p>カスタマイズを終了するには、右上の「完了」をクリックします。</p>',
+ [{
+ text: 'Got it!'
+ }]);
+
+ const sortableOption = {
+ group: 'kyoppie',
+ animation: 150,
+ onMove: evt => {
+ const id = evt.dragged.getAttribute('data-widget-id');
+ this.home.find(tag => tag.id == id).update({ place: evt.to.getAttribute('data-place') });
+ },
+ onSort: () => {
+ this.saveHome();
+ }
+ };
+
+ new Sortable(this.$refs.left, sortableOption);
+ new Sortable(this.$refs.right, sortableOption);
+ new Sortable(this.$refs.maintop, sortableOption);
+ new Sortable(this.$refs.trash, Object.assign({}, sortableOption, {
+ onAdd: evt => {
+ const el = evt.item;
+ const id = el.getAttribute('data-widget-id');
+ el.parentNode.removeChild(el);
+ this.I.client_settings.home = this.I.client_settings.home.filter(w => w.id != id);
+ this.saveHome();
+ }
+ }));
+ }
+
+ if (!this.opts.customize) {
+ this.scrollFollowerLeft = this.$refs.left.parentNode ? new ScrollFollower(this.$refs.left, this.root.getBoundingClientRect().top) : null;
+ this.scrollFollowerRight = this.$refs.right.parentNode ? new ScrollFollower(this.$refs.right, this.root.getBoundingClientRect().top) : null;
+ }
+ });
+
+ this.on('unmount', () => {
+ this.I.off('refreshed', this.onMeRefreshed);
+
+ this.home.forEach(widget => {
+ widget.unmount();
+ });
+
+ if (!this.opts.customize) {
+ if (this.scrollFollowerLeft) this.scrollFollowerLeft.dispose();
+ if (this.scrollFollowerRight) this.scrollFollowerRight.dispose();
+ }
+ });
+
+ this.onMeRefreshed = () => {
+ if (this.bakedHomeData != this.bakeHomeData()) {
+ alert('別の場所でホームが編集されました。ページを再度読み込みすると編集が反映されます。');
+ }
+ };
+
+ this.setWidget = (widget, prepend = false) => {
+ const el = document.createElement(`mk-${widget.name}-home-widget`);
+
+ let actualEl;
+
+ if (this.opts.customize) {
+ const container = document.createElement('div');
+ container.classList.add('customize-container');
+ container.setAttribute('data-widget-id', widget.id);
+ container.appendChild(el);
+ actualEl = container;
+ } else {
+ actualEl = el;
+ }
+
+ switch (widget.place) {
+ case 'left':
+ if (prepend) {
+ this.$refs.left.insertBefore(actualEl, this.$refs.left.firstChild);
+ } else {
+ this.$refs.left.appendChild(actualEl);
+ }
+ break;
+ case 'right':
+ if (prepend) {
+ this.$refs.right.insertBefore(actualEl, this.$refs.right.firstChild);
+ } else {
+ this.$refs.right.appendChild(actualEl);
+ }
+ break;
+ case 'main':
+ if (this.opts.customize) {
+ this.$refs.maintop.appendChild(actualEl);
+ } else {
+ this.$refs.main.insertBefore(actualEl, this.$refs.tl.root);
+ }
+ break;
+ }
+
+ const tag = riot.mount(el, {
+ id: widget.id,
+ data: widget.data,
+ place: widget.place,
+ tl: this.$refs.tl
+ })[0];
+
+ this.home.push(tag);
+
+ if (this.opts.customize) {
+ actualEl.oncontextmenu = e => {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ if (tag.func) tag.func();
+ return false;
+ };
+ }
+ };
+
+ this.addWidget = () => {
+ const widget = {
+ name: this.$refs.widgetSelector.options[this.$refs.widgetSelector.selectedIndex].value,
+ id: uuid(),
+ place: 'left',
+ data: {}
+ };
+
+ this.I.client_settings.home.unshift(widget);
+
+ this.setWidget(widget, true);
+
+ this.saveHome();
+ };
+
+ this.saveHome = () => {
+ const data = [];
+
+ Array.from(this.$refs.left.children).forEach(el => {
+ const id = el.getAttribute('data-widget-id');
+ const widget = this.I.client_settings.home.find(w => w.id == id);
+ widget.place = 'left';
+ data.push(widget);
+ });
+
+ Array.from(this.$refs.right.children).forEach(el => {
+ const id = el.getAttribute('data-widget-id');
+ const widget = this.I.client_settings.home.find(w => w.id == id);
+ widget.place = 'right';
+ data.push(widget);
+ });
+
+ Array.from(this.$refs.maintop.children).forEach(el => {
+ const id = el.getAttribute('data-widget-id');
+ const widget = this.I.client_settings.home.find(w => w.id == id);
+ widget.place = 'main';
+ data.push(widget);
+ });
+
+ this.api('i/update_home', {
+ home: data
+ }).then(() => {
+ this.I.update();
+ });
+ };
+</script>