forked from FoundKeyGang/FoundKey
Implement #1098
This commit is contained in:
parent
83f2e906bb
commit
df8a2aea35
42 changed files with 823 additions and 511 deletions
|
@ -182,7 +182,12 @@ const endpoints: Endpoint[] = [
|
||||||
{
|
{
|
||||||
name: 'i/update_home',
|
name: 'i/update_home',
|
||||||
withCredential: true,
|
withCredential: true,
|
||||||
kind: 'account-write'
|
secure: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'i/update_mobile_home',
|
||||||
|
withCredential: true,
|
||||||
|
secure: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'i/change_password',
|
name: 'i/change_password',
|
||||||
|
|
|
@ -4,16 +4,7 @@
|
||||||
import $ from 'cafy';
|
import $ from 'cafy';
|
||||||
import User from '../../models/user';
|
import User from '../../models/user';
|
||||||
|
|
||||||
/**
|
module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
* Update myself
|
|
||||||
*
|
|
||||||
* @param {any} params
|
|
||||||
* @param {any} user
|
|
||||||
* @param {any} _
|
|
||||||
* @param {boolean} isSecure
|
|
||||||
* @return {Promise<any>}
|
|
||||||
*/
|
|
||||||
module.exports = async (params, user, _, isSecure) => new Promise(async (res, rej) => {
|
|
||||||
// Get 'home' parameter
|
// Get 'home' parameter
|
||||||
const [home, homeErr] = $(params.home).optional.array().each(
|
const [home, homeErr] = $(params.home).optional.array().each(
|
||||||
$().strict.object()
|
$().strict.object()
|
||||||
|
|
50
src/api/endpoints/i/update_mobile_home.ts
Normal file
50
src/api/endpoints/i/update_mobile_home.ts
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
* Module dependencies
|
||||||
|
*/
|
||||||
|
import $ from 'cafy';
|
||||||
|
import User from '../../models/user';
|
||||||
|
|
||||||
|
module.exports = async (params, user) => new Promise(async (res, rej) => {
|
||||||
|
// Get 'home' parameter
|
||||||
|
const [home, homeErr] = $(params.home).optional.array().each(
|
||||||
|
$().strict.object()
|
||||||
|
.have('name', $().string())
|
||||||
|
.have('id', $().string())
|
||||||
|
.have('data', $().object())).$;
|
||||||
|
if (homeErr) return rej('invalid home param');
|
||||||
|
|
||||||
|
// Get 'id' parameter
|
||||||
|
const [id, idErr] = $(params.id).optional.string().$;
|
||||||
|
if (idErr) return rej('invalid id param');
|
||||||
|
|
||||||
|
// Get 'data' parameter
|
||||||
|
const [data, dataErr] = $(params.data).optional.object().$;
|
||||||
|
if (dataErr) return rej('invalid data param');
|
||||||
|
|
||||||
|
if (home) {
|
||||||
|
await User.update(user._id, {
|
||||||
|
$set: {
|
||||||
|
'client_settings.mobile_home': home
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
res();
|
||||||
|
} else {
|
||||||
|
if (id == null && data == null) return rej('you need to set id and data params if home param unset');
|
||||||
|
|
||||||
|
const _home = user.client_settings.mobile_home || [];
|
||||||
|
const widget = _home.find(w => w.id == id);
|
||||||
|
|
||||||
|
if (widget == null) return rej('widget not found');
|
||||||
|
|
||||||
|
widget.data = data;
|
||||||
|
|
||||||
|
await User.update(user._id, {
|
||||||
|
$set: {
|
||||||
|
'client_settings.mobile_home': _home
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
res();
|
||||||
|
}
|
||||||
|
});
|
|
@ -8,6 +8,10 @@ export default function<T extends object>(data: {
|
||||||
props: {
|
props: {
|
||||||
widget: {
|
widget: {
|
||||||
type: Object
|
type: Object
|
||||||
|
},
|
||||||
|
isMobile: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -21,6 +25,7 @@ export default function<T extends object>(data: {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
if (this.widget.data == null) this.widget.data = {};
|
||||||
if (this.props) {
|
if (this.props) {
|
||||||
Object.keys(this.props).forEach(prop => {
|
Object.keys(this.props).forEach(prop => {
|
||||||
if (this.widget.data.hasOwnProperty(prop)) {
|
if (this.widget.data.hasOwnProperty(prop)) {
|
||||||
|
@ -30,12 +35,21 @@ export default function<T extends object>(data: {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$watch('props', newProps => {
|
this.$watch('props', newProps => {
|
||||||
|
if (this.isMobile) {
|
||||||
|
(this as any).api('i/update_mobile_home', {
|
||||||
|
id: this.id,
|
||||||
|
data: newProps
|
||||||
|
}).then(() => {
|
||||||
|
(this as any).os.i.client_settings.mobile_home.find(w => w.id == this.id).data = newProps;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
(this as any).api('i/update_home', {
|
(this as any).api('i/update_home', {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
data: newProps
|
data: newProps
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
(this as any).os.i.client_settings.home.find(w => w.id == this.id).data = newProps;
|
(this as any).os.i.client_settings.home.find(w => w.id == this.id).data = newProps;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
deep: true
|
deep: true
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,9 @@ export default async function(mios: MiOS) {
|
||||||
|
|
||||||
// Clear cache (serive worker)
|
// Clear cache (serive worker)
|
||||||
try {
|
try {
|
||||||
|
if (navigator.serviceWorker.controller) {
|
||||||
navigator.serviceWorker.controller.postMessage('clear');
|
navigator.serviceWorker.controller.postMessage('clear');
|
||||||
|
}
|
||||||
|
|
||||||
navigator.serviceWorker.getRegistrations().then(registrations => {
|
navigator.serviceWorker.getRegistrations().then(registrations => {
|
||||||
registrations.forEach(registration => registration.unregister());
|
registrations.forEach(registration => registration.unregister());
|
||||||
|
|
|
@ -21,6 +21,21 @@ import urlPreview from './url-preview.vue';
|
||||||
import twitterSetting from './twitter-setting.vue';
|
import twitterSetting from './twitter-setting.vue';
|
||||||
import fileTypeIcon from './file-type-icon.vue';
|
import fileTypeIcon from './file-type-icon.vue';
|
||||||
|
|
||||||
|
//#region widgets
|
||||||
|
import wAccessLog from './widgets/access-log.vue';
|
||||||
|
import wVersion from './widgets/version.vue';
|
||||||
|
import wRss from './widgets/rss.vue';
|
||||||
|
import wProfile from './widgets/profile.vue';
|
||||||
|
import wServer from './widgets/server.vue';
|
||||||
|
import wBroadcast from './widgets/broadcast.vue';
|
||||||
|
import wCalendar from './widgets/calendar.vue';
|
||||||
|
import wPhotoStream from './widgets/photo-stream.vue';
|
||||||
|
import wSlideshow from './widgets/slideshow.vue';
|
||||||
|
import wTips from './widgets/tips.vue';
|
||||||
|
import wDonation from './widgets/donation.vue';
|
||||||
|
import wNav from './widgets/nav.vue';
|
||||||
|
//#endregion
|
||||||
|
|
||||||
Vue.component('mk-signin', signin);
|
Vue.component('mk-signin', signin);
|
||||||
Vue.component('mk-signup', signup);
|
Vue.component('mk-signup', signup);
|
||||||
Vue.component('mk-forkit', forkit);
|
Vue.component('mk-forkit', forkit);
|
||||||
|
@ -41,3 +56,18 @@ Vue.component('mk-messaging-room', messagingRoom);
|
||||||
Vue.component('mk-url-preview', urlPreview);
|
Vue.component('mk-url-preview', urlPreview);
|
||||||
Vue.component('mk-twitter-setting', twitterSetting);
|
Vue.component('mk-twitter-setting', twitterSetting);
|
||||||
Vue.component('mk-file-type-icon', fileTypeIcon);
|
Vue.component('mk-file-type-icon', fileTypeIcon);
|
||||||
|
|
||||||
|
//#region widgets
|
||||||
|
Vue.component('mkw-nav', wNav);
|
||||||
|
Vue.component('mkw-calendar', wCalendar);
|
||||||
|
Vue.component('mkw-photo-stream', wPhotoStream);
|
||||||
|
Vue.component('mkw-slideshow', wSlideshow);
|
||||||
|
Vue.component('mkw-tips', wTips);
|
||||||
|
Vue.component('mkw-donation', wDonation);
|
||||||
|
Vue.component('mkw-broadcast', wBroadcast);
|
||||||
|
Vue.component('mkw-profile', wProfile);
|
||||||
|
Vue.component('mkw-server', wServer);
|
||||||
|
Vue.component('mkw-rss', wRss);
|
||||||
|
Vue.component('mkw-version', wVersion);
|
||||||
|
Vue.component('mkw-access-log', wAccessLog);
|
||||||
|
//#endregion
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mkw-access-log">
|
<div class="mkw-access-log">
|
||||||
<template v-if="props.design == 0">
|
<mk-widget-container :show-header="props.design == 0">
|
||||||
<p class="title">%fa:server%%i18n:desktop.tags.mk-access-log-home-widget.title%</p>
|
<template slot="header">%fa:server%%i18n:desktop.tags.mk-access-log-home-widget.title%</template>
|
||||||
</template>
|
|
||||||
<div ref="log">
|
<div :class="$style.logs" ref="log">
|
||||||
<p v-for="req in requests">
|
<p v-for="req in requests">
|
||||||
<span class="ip" :style="`color:${ req.fg }; background:${ req.bg }`">{{ req.ip }}</span>
|
<span :class="$style.ip" :style="`color:${ req.fg }; background:${ req.bg }`">{{ req.ip }}</span>
|
||||||
<b>{{ req.method }}</b>
|
<b>{{ req.method }}</b>
|
||||||
<span>{{ req.path }}</span>
|
<span>{{ req.path }}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</mk-widget-container>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -65,27 +66,8 @@ export default define({
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" module>
|
||||||
.mkw-access-log
|
.logs
|
||||||
overflow hidden
|
|
||||||
background #fff
|
|
||||||
border solid 1px rgba(0, 0, 0, 0.075)
|
|
||||||
border-radius 6px
|
|
||||||
|
|
||||||
> .title
|
|
||||||
z-index 1
|
|
||||||
margin 0
|
|
||||||
padding 0 16px
|
|
||||||
line-height 42px
|
|
||||||
font-size 0.9em
|
|
||||||
font-weight bold
|
|
||||||
color #888
|
|
||||||
box-shadow 0 1px rgba(0, 0, 0, 0.07)
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
> div
|
|
||||||
max-height 250px
|
max-height 250px
|
||||||
overflow auto
|
overflow auto
|
||||||
|
|
||||||
|
@ -98,11 +80,11 @@ export default define({
|
||||||
&:nth-child(odd)
|
&:nth-child(odd)
|
||||||
background rgba(0, 0, 0, 0.025)
|
background rgba(0, 0, 0, 0.025)
|
||||||
|
|
||||||
> .ip
|
|
||||||
margin-right 4px
|
|
||||||
padding 0 4px
|
|
||||||
|
|
||||||
> b
|
> b
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
|
||||||
|
.ip
|
||||||
|
margin-right 4px
|
||||||
|
padding 0 4px
|
||||||
|
|
||||||
</style>
|
</style>
|
|
@ -1,5 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mkw-broadcast" :data-found="broadcasts.length != 0" :data-melt="props.design == 1">
|
<div class="mkw-broadcast"
|
||||||
|
:data-found="broadcasts.length != 0"
|
||||||
|
:data-melt="props.design == 1"
|
||||||
|
:data-mobile="isMobile"
|
||||||
|
>
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<svg height="32" version="1.1" viewBox="0 0 32 32" width="32">
|
<svg height="32" version="1.1" viewBox="0 0 32 32" width="32">
|
||||||
<path class="tower" d="M16.04,11.24c1.79,0,3.239-1.45,3.239-3.24S17.83,4.76,16.04,4.76c-1.79,0-3.24,1.45-3.24,3.24 C12.78,9.78,14.24,11.24,16.04,11.24z M16.04,13.84c-0.82,0-1.66-0.2-2.4-0.6L7.34,29.98h2.98l1.72-2h8l1.681,2H24.7L18.42,13.24 C17.66,13.64,16.859,13.84,16.04,13.84z M16.02,14.8l2.02,7.2h-4L16.02,14.8z M12.04,25.98l2-2h4l2,2H12.04z"></path>
|
<path class="tower" d="M16.04,11.24c1.79,0,3.239-1.45,3.239-3.24S17.83,4.76,16.04,4.76c-1.79,0-3.24,1.45-3.24,3.24 C12.78,9.78,14.24,11.24,16.04,11.24z M16.04,13.84c-0.82,0-1.66-0.2-2.4-0.6L7.34,29.98h2.98l1.72-2h8l1.681,2H24.7L18.42,13.24 C17.66,13.64,16.859,13.84,16.04,13.84z M16.02,14.8l2.02,7.2h-4L16.02,14.8z M12.04,25.98l2-2h4l2,2H12.04z"></path>
|
||||||
|
@ -150,4 +154,8 @@ export default define({
|
||||||
display block
|
display block
|
||||||
font-size 0.7em
|
font-size 0.7em
|
||||||
|
|
||||||
|
&[data-mobile]
|
||||||
|
> p
|
||||||
|
color #fff
|
||||||
|
|
||||||
</style>
|
</style>
|
|
@ -2,6 +2,7 @@
|
||||||
<div class="mkw-calendar"
|
<div class="mkw-calendar"
|
||||||
:data-melt="props.design == 1"
|
:data-melt="props.design == 1"
|
||||||
:data-special="special"
|
:data-special="special"
|
||||||
|
:data-mobile="isMobile"
|
||||||
>
|
>
|
||||||
<div class="calendar" :data-is-holiday="isHoliday">
|
<div class="calendar" :data-is-holiday="isHoliday">
|
||||||
<p class="month-and-year">
|
<p class="month-and-year">
|
||||||
|
@ -66,6 +67,7 @@ export default define({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
func() {
|
func() {
|
||||||
|
if (this.isMobile) return;
|
||||||
if (this.props.design == 2) {
|
if (this.props.design == 2) {
|
||||||
this.props.design = 0;
|
this.props.design = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -119,6 +121,11 @@ export default define({
|
||||||
background transparent
|
background transparent
|
||||||
border none
|
border none
|
||||||
|
|
||||||
|
&[data-mobile]
|
||||||
|
border none
|
||||||
|
border-radius 8px
|
||||||
|
box-shadow 0 0 0 1px rgba(0, 0, 0, 0.2)
|
||||||
|
|
||||||
&:after
|
&:after
|
||||||
content ""
|
content ""
|
||||||
display block
|
display block
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mkw-donation">
|
<div class="mkw-donation" :data-mobile="isMobile">
|
||||||
<article>
|
<article>
|
||||||
<h1>%fa:heart%%i18n:desktop.tags.mk-donation-home-widget.title%</h1>
|
<h1>%fa:heart%%i18n:desktop.tags.mk-donation-home-widget.title%</h1>
|
||||||
<p>
|
<p>
|
||||||
|
@ -42,4 +42,17 @@ export default define({
|
||||||
font-size 0.8em
|
font-size 0.8em
|
||||||
color #999
|
color #999
|
||||||
|
|
||||||
|
&[data-mobile]
|
||||||
|
border none
|
||||||
|
background #ead8bb
|
||||||
|
border-radius 8px
|
||||||
|
box-shadow 0 0 0 1px rgba(0, 0, 0, 0.2)
|
||||||
|
|
||||||
|
> article
|
||||||
|
> h1
|
||||||
|
color #7b8871
|
||||||
|
|
||||||
|
> p
|
||||||
|
color #777d71
|
||||||
|
|
||||||
</style>
|
</style>
|
|
@ -1,6 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mkw-nav">
|
<div class="mkw-nav">
|
||||||
|
<mk-widget-container>
|
||||||
|
<div :class="$style.body">
|
||||||
<mk-nav/>
|
<mk-nav/>
|
||||||
|
</div>
|
||||||
|
</mk-widget-container>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -11,14 +15,12 @@ export default define({
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" module>
|
||||||
.mkw-nav
|
.body
|
||||||
padding 16px
|
padding 16px
|
||||||
font-size 12px
|
font-size 12px
|
||||||
color #aaa
|
color #aaa
|
||||||
background #fff
|
background #fff
|
||||||
border solid 1px rgba(0, 0, 0, 0.075)
|
|
||||||
border-radius 6px
|
|
||||||
|
|
||||||
a
|
a
|
||||||
color #999
|
color #999
|
104
src/web/app/common/views/components/widgets/photo-stream.vue
Normal file
104
src/web/app/common/views/components/widgets/photo-stream.vue
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
<template>
|
||||||
|
<div class="mkw-photo-stream" :class="$style.root" :data-melt="props.design == 2">
|
||||||
|
<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
|
||||||
|
<template slot="header">%fa:camera%%i18n:desktop.tags.mk-photo-stream-home-widget.title%</template>
|
||||||
|
|
||||||
|
<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
||||||
|
<div :class="$style.stream" v-if="!fetching && images.length > 0">
|
||||||
|
<div v-for="image in images" :key="image.id" :class="$style.img" :style="`background-image: url(${image.url}?thumbnail&size=256)`"></div>
|
||||||
|
</div>
|
||||||
|
<p :class="$style.empty" v-if="!fetching && images.length == 0">%i18n:desktop.tags.mk-photo-stream-home-widget.no-photos%</p>
|
||||||
|
</mk-widget-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import define from '../../../../common/define-widget';
|
||||||
|
export default define({
|
||||||
|
name: 'photo-stream',
|
||||||
|
props: () => ({
|
||||||
|
design: 0
|
||||||
|
})
|
||||||
|
}).extend({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
images: [],
|
||||||
|
fetching: true,
|
||||||
|
connection: null,
|
||||||
|
connectionId: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.connection = (this as any).os.stream.getConnection();
|
||||||
|
this.connectionId = (this as any).os.stream.use();
|
||||||
|
|
||||||
|
this.connection.on('drive_file_created', this.onDriveFileCreated);
|
||||||
|
|
||||||
|
(this as any).api('drive/stream', {
|
||||||
|
type: 'image/*',
|
||||||
|
limit: 9
|
||||||
|
}).then(images => {
|
||||||
|
this.images = images;
|
||||||
|
this.fetching = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.connection.off('drive_file_created', this.onDriveFileCreated);
|
||||||
|
(this as any).os.stream.dispose(this.connectionId);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onDriveFileCreated(file) {
|
||||||
|
if (/^image\/.+$/.test(file.type)) {
|
||||||
|
this.images.unshift(file);
|
||||||
|
if (this.images.length > 9) this.images.pop();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func() {
|
||||||
|
if (this.props.design == 2) {
|
||||||
|
this.props.design = 0;
|
||||||
|
} else {
|
||||||
|
this.props.design++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" module>
|
||||||
|
.root[data-melt]
|
||||||
|
.stream
|
||||||
|
padding 0
|
||||||
|
|
||||||
|
.img
|
||||||
|
border solid 4px transparent
|
||||||
|
border-radius 8px
|
||||||
|
|
||||||
|
.stream
|
||||||
|
display -webkit-flex
|
||||||
|
display -moz-flex
|
||||||
|
display -ms-flex
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
flex-wrap wrap
|
||||||
|
padding 8px
|
||||||
|
|
||||||
|
.img
|
||||||
|
flex 1 1 33%
|
||||||
|
width 33%
|
||||||
|
height 80px
|
||||||
|
background-position center center
|
||||||
|
background-size cover
|
||||||
|
border solid 2px transparent
|
||||||
|
border-radius 4px
|
||||||
|
|
||||||
|
.fetching
|
||||||
|
.empty
|
||||||
|
margin 0
|
||||||
|
padding 16px
|
||||||
|
text-align center
|
||||||
|
color #aaa
|
||||||
|
|
||||||
|
> [data-fa]
|
||||||
|
margin-right 4px
|
||||||
|
|
||||||
|
</style>
|
93
src/web/app/common/views/components/widgets/rss.vue
Normal file
93
src/web/app/common/views/components/widgets/rss.vue
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
<template>
|
||||||
|
<div class="mkw-rss" :data-mobile="isMobile">
|
||||||
|
<mk-widget-container :show-header="!props.compact">
|
||||||
|
<template slot="header">%fa:rss-square%RSS</template>
|
||||||
|
<button slot="func" title="設定" @click="setting">%fa:cog%</button>
|
||||||
|
|
||||||
|
<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
||||||
|
<div :class="$style.feed" v-else>
|
||||||
|
<a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a>
|
||||||
|
</div>
|
||||||
|
</mk-widget-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import define from '../../../../common/define-widget';
|
||||||
|
export default define({
|
||||||
|
name: 'rss',
|
||||||
|
props: () => ({
|
||||||
|
compact: false
|
||||||
|
})
|
||||||
|
}).extend({
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
url: 'http://news.yahoo.co.jp/pickup/rss.xml',
|
||||||
|
items: [],
|
||||||
|
fetching: true,
|
||||||
|
clock: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.fetch();
|
||||||
|
this.clock = setInterval(this.fetch, 60000);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
clearInterval(this.clock);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
func() {
|
||||||
|
this.props.compact = !this.props.compact;
|
||||||
|
},
|
||||||
|
fetch() {
|
||||||
|
fetch(`https://api.rss2json.com/v1/api.json?rss_url=${this.url}`, {
|
||||||
|
cache: 'no-cache'
|
||||||
|
}).then(res => {
|
||||||
|
res.json().then(feed => {
|
||||||
|
this.items = feed.items;
|
||||||
|
this.fetching = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setting() {
|
||||||
|
alert('not implemented yet');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" module>
|
||||||
|
.feed
|
||||||
|
padding 12px 16px
|
||||||
|
font-size 0.9em
|
||||||
|
|
||||||
|
> a
|
||||||
|
display block
|
||||||
|
padding 4px 0
|
||||||
|
color #666
|
||||||
|
border-bottom dashed 1px #eee
|
||||||
|
|
||||||
|
&:last-child
|
||||||
|
border-bottom none
|
||||||
|
|
||||||
|
.fetching
|
||||||
|
margin 0
|
||||||
|
padding 16px
|
||||||
|
text-align center
|
||||||
|
color #aaa
|
||||||
|
|
||||||
|
> [data-fa]
|
||||||
|
margin-right 4px
|
||||||
|
|
||||||
|
&[data-mobile]
|
||||||
|
.feed
|
||||||
|
padding 0
|
||||||
|
font-size 1em
|
||||||
|
|
||||||
|
> a
|
||||||
|
padding 8px 16px
|
||||||
|
|
||||||
|
&:nth-child(even)
|
||||||
|
background #e2e2e2
|
||||||
|
|
||||||
|
</style>
|
93
src/web/app/common/views/components/widgets/server.vue
Normal file
93
src/web/app/common/views/components/widgets/server.vue
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
<template>
|
||||||
|
<div class="mkw-server">
|
||||||
|
<mk-widget-container :show-header="props.design == 0" :naked="props.design == 2">
|
||||||
|
<template slot="header">%fa:server%%i18n:desktop.tags.mk-server-home-widget.title%</template>
|
||||||
|
<button slot="func" @click="toggle" title="%i18n:desktop.tags.mk-server-home-widget.toggle%">%fa:sort%</button>
|
||||||
|
|
||||||
|
<p :class="$style.fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
||||||
|
<template v-if="!fetching">
|
||||||
|
<x-cpu-memory v-show="props.view == 0" :connection="connection"/>
|
||||||
|
<x-cpu v-show="props.view == 1" :connection="connection" :meta="meta"/>
|
||||||
|
<x-memory v-show="props.view == 2" :connection="connection"/>
|
||||||
|
<x-disk v-show="props.view == 3" :connection="connection"/>
|
||||||
|
<x-uptimes v-show="props.view == 4" :connection="connection"/>
|
||||||
|
<x-info v-show="props.view == 5" :connection="connection" :meta="meta"/>
|
||||||
|
</template>
|
||||||
|
</mk-widget-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import define from '../../../../common/define-widget';
|
||||||
|
import XCpuMemory from './server.cpu-memory.vue';
|
||||||
|
import XCpu from './server.cpu.vue';
|
||||||
|
import XMemory from './server.memory.vue';
|
||||||
|
import XDisk from './server.disk.vue';
|
||||||
|
import XUptimes from './server.uptimes.vue';
|
||||||
|
import XInfo from './server.info.vue';
|
||||||
|
|
||||||
|
export default define({
|
||||||
|
name: 'server',
|
||||||
|
props: () => ({
|
||||||
|
design: 0,
|
||||||
|
view: 0
|
||||||
|
})
|
||||||
|
}).extend({
|
||||||
|
components: {
|
||||||
|
XCpuMemory,
|
||||||
|
XCpu,
|
||||||
|
XMemory,
|
||||||
|
XDisk,
|
||||||
|
XUptimes,
|
||||||
|
XInfo
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fetching: true,
|
||||||
|
meta: null,
|
||||||
|
connection: null,
|
||||||
|
connectionId: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
(this as any).os.getMeta().then(meta => {
|
||||||
|
this.meta = meta;
|
||||||
|
this.fetching = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.connection = (this as any).os.streams.serverStream.getConnection();
|
||||||
|
this.connectionId = (this as any).os.streams.serverStream.use();
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
(this as any).os.streams.serverStream.dispose(this.connectionId);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggle() {
|
||||||
|
if (this.props.view == 5) {
|
||||||
|
this.props.view = 0;
|
||||||
|
} else {
|
||||||
|
this.props.view++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
func() {
|
||||||
|
if (this.props.design == 2) {
|
||||||
|
this.props.design = 0;
|
||||||
|
} else {
|
||||||
|
this.props.design++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" module>
|
||||||
|
.fetching
|
||||||
|
margin 0
|
||||||
|
padding 16px
|
||||||
|
text-align center
|
||||||
|
color #aaa
|
||||||
|
|
||||||
|
> [data-fa]
|
||||||
|
margin-right 4px
|
||||||
|
|
||||||
|
</style>
|
|
@ -27,27 +27,19 @@ import friendsMaker from './friends-maker.vue';
|
||||||
import followers from './followers.vue';
|
import followers from './followers.vue';
|
||||||
import following from './following.vue';
|
import following from './following.vue';
|
||||||
import usersList from './users-list.vue';
|
import usersList from './users-list.vue';
|
||||||
import wNav from './widgets/nav.vue';
|
import widgetContainer from './widget-container.vue';
|
||||||
import wCalendar from './widgets/calendar.vue';
|
|
||||||
import wPhotoStream from './widgets/photo-stream.vue';
|
//#region widgets
|
||||||
import wSlideshow from './widgets/slideshow.vue';
|
|
||||||
import wTips from './widgets/tips.vue';
|
|
||||||
import wDonation from './widgets/donation.vue';
|
|
||||||
import wNotifications from './widgets/notifications.vue';
|
import wNotifications from './widgets/notifications.vue';
|
||||||
import wBroadcast from './widgets/broadcast.vue';
|
|
||||||
import wTimemachine from './widgets/timemachine.vue';
|
import wTimemachine from './widgets/timemachine.vue';
|
||||||
import wProfile from './widgets/profile.vue';
|
|
||||||
import wServer from './widgets/server.vue';
|
|
||||||
import wActivity from './widgets/activity.vue';
|
import wActivity from './widgets/activity.vue';
|
||||||
import wRss from './widgets/rss.vue';
|
|
||||||
import wTrends from './widgets/trends.vue';
|
import wTrends from './widgets/trends.vue';
|
||||||
import wVersion from './widgets/version.vue';
|
|
||||||
import wUsers from './widgets/users.vue';
|
import wUsers from './widgets/users.vue';
|
||||||
import wPolls from './widgets/polls.vue';
|
import wPolls from './widgets/polls.vue';
|
||||||
import wPostForm from './widgets/post-form.vue';
|
import wPostForm from './widgets/post-form.vue';
|
||||||
import wMessaging from './widgets/messaging.vue';
|
import wMessaging from './widgets/messaging.vue';
|
||||||
import wChannel from './widgets/channel.vue';
|
import wChannel from './widgets/channel.vue';
|
||||||
import wAccessLog from './widgets/access-log.vue';
|
//#endregion
|
||||||
|
|
||||||
Vue.component('mk-ui', ui);
|
Vue.component('mk-ui', ui);
|
||||||
Vue.component('mk-ui-notification', uiNotification);
|
Vue.component('mk-ui-notification', uiNotification);
|
||||||
|
@ -76,24 +68,16 @@ Vue.component('mk-friends-maker', friendsMaker);
|
||||||
Vue.component('mk-followers', followers);
|
Vue.component('mk-followers', followers);
|
||||||
Vue.component('mk-following', following);
|
Vue.component('mk-following', following);
|
||||||
Vue.component('mk-users-list', usersList);
|
Vue.component('mk-users-list', usersList);
|
||||||
Vue.component('mkw-nav', wNav);
|
Vue.component('mk-widget-container', widgetContainer);
|
||||||
Vue.component('mkw-calendar', wCalendar);
|
|
||||||
Vue.component('mkw-photo-stream', wPhotoStream);
|
//#region widgets
|
||||||
Vue.component('mkw-slideshow', wSlideshow);
|
|
||||||
Vue.component('mkw-tips', wTips);
|
|
||||||
Vue.component('mkw-donation', wDonation);
|
|
||||||
Vue.component('mkw-notifications', wNotifications);
|
Vue.component('mkw-notifications', wNotifications);
|
||||||
Vue.component('mkw-broadcast', wBroadcast);
|
|
||||||
Vue.component('mkw-timemachine', wTimemachine);
|
Vue.component('mkw-timemachine', wTimemachine);
|
||||||
Vue.component('mkw-profile', wProfile);
|
|
||||||
Vue.component('mkw-server', wServer);
|
|
||||||
Vue.component('mkw-activity', wActivity);
|
Vue.component('mkw-activity', wActivity);
|
||||||
Vue.component('mkw-rss', wRss);
|
|
||||||
Vue.component('mkw-trends', wTrends);
|
Vue.component('mkw-trends', wTrends);
|
||||||
Vue.component('mkw-version', wVersion);
|
|
||||||
Vue.component('mkw-users', wUsers);
|
Vue.component('mkw-users', wUsers);
|
||||||
Vue.component('mkw-polls', wPolls);
|
Vue.component('mkw-polls', wPolls);
|
||||||
Vue.component('mkw-post-form', wPostForm);
|
Vue.component('mkw-post-form', wPostForm);
|
||||||
Vue.component('mkw-messaging', wMessaging);
|
Vue.component('mkw-messaging', wMessaging);
|
||||||
Vue.component('mkw-channel', wChannel);
|
Vue.component('mkw-channel', wChannel);
|
||||||
Vue.component('mkw-access-log', wAccessLog);
|
//#endregion
|
||||||
|
|
72
src/web/app/desktop/views/components/widget-container.vue
Normal file
72
src/web/app/desktop/views/components/widget-container.vue
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
<template>
|
||||||
|
<div class="mk-widget-container" :class="{ naked }">
|
||||||
|
<header v-if="showHeader">
|
||||||
|
<div class="title"><slot name="header"></slot></div>
|
||||||
|
<slot name="func"></slot>
|
||||||
|
</header>
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
export default Vue.extend({
|
||||||
|
props: {
|
||||||
|
showHeader: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
naked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.mk-widget-container
|
||||||
|
background #fff
|
||||||
|
border solid 1px rgba(0, 0, 0, 0.075)
|
||||||
|
border-radius 6px
|
||||||
|
overflow hidden
|
||||||
|
|
||||||
|
&.naked
|
||||||
|
background transparent !important
|
||||||
|
border none !important
|
||||||
|
|
||||||
|
> header
|
||||||
|
> .title
|
||||||
|
z-index 1
|
||||||
|
margin 0
|
||||||
|
padding 0 16px
|
||||||
|
line-height 42px
|
||||||
|
font-size 0.9em
|
||||||
|
font-weight bold
|
||||||
|
color #888
|
||||||
|
box-shadow 0 1px rgba(0, 0, 0, 0.07)
|
||||||
|
|
||||||
|
> [data-fa]
|
||||||
|
margin-right 4px
|
||||||
|
|
||||||
|
&:empty
|
||||||
|
display none
|
||||||
|
|
||||||
|
> button
|
||||||
|
position absolute
|
||||||
|
z-index 2
|
||||||
|
top 0
|
||||||
|
right 0
|
||||||
|
padding 0
|
||||||
|
width 42px
|
||||||
|
font-size 0.9em
|
||||||
|
line-height 42px
|
||||||
|
color #ccc
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
color #aaa
|
||||||
|
|
||||||
|
&:active
|
||||||
|
color #999
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,122 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="mkw-photo-stream" :data-melt="props.design == 2">
|
|
||||||
<p class="title" v-if="props.design == 0">%fa:camera%%i18n:desktop.tags.mk-photo-stream-home-widget.title%</p>
|
|
||||||
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
|
||||||
<div class="stream" v-if="!fetching && images.length > 0">
|
|
||||||
<div v-for="image in images" :key="image.id" class="img" :style="`background-image: url(${image.url}?thumbnail&size=256)`"></div>
|
|
||||||
</div>
|
|
||||||
<p class="empty" v-if="!fetching && images.length == 0">%i18n:desktop.tags.mk-photo-stream-home-widget.no-photos%</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import define from '../../../../common/define-widget';
|
|
||||||
export default define({
|
|
||||||
name: 'photo-stream',
|
|
||||||
props: () => ({
|
|
||||||
design: 0
|
|
||||||
})
|
|
||||||
}).extend({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
images: [],
|
|
||||||
fetching: true,
|
|
||||||
connection: null,
|
|
||||||
connectionId: null
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.connection = (this as any).os.stream.getConnection();
|
|
||||||
this.connectionId = (this as any).os.stream.use();
|
|
||||||
|
|
||||||
this.connection.on('drive_file_created', this.onDriveFileCreated);
|
|
||||||
|
|
||||||
(this as any).api('drive/stream', {
|
|
||||||
type: 'image/*',
|
|
||||||
limit: 9
|
|
||||||
}).then(images => {
|
|
||||||
this.images = images;
|
|
||||||
this.fetching = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
this.connection.off('drive_file_created', this.onDriveFileCreated);
|
|
||||||
(this as any).os.stream.dispose(this.connectionId);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onDriveFileCreated(file) {
|
|
||||||
if (/^image\/.+$/.test(file.type)) {
|
|
||||||
this.images.unshift(file);
|
|
||||||
if (this.images.length > 9) this.images.pop();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func() {
|
|
||||||
if (this.props.design == 2) {
|
|
||||||
this.props.design = 0;
|
|
||||||
} else {
|
|
||||||
this.props.design++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
|
||||||
.mkw-photo-stream
|
|
||||||
background #fff
|
|
||||||
border solid 1px rgba(0, 0, 0, 0.075)
|
|
||||||
border-radius 6px
|
|
||||||
|
|
||||||
&[data-melt]
|
|
||||||
background transparent !important
|
|
||||||
border none !important
|
|
||||||
|
|
||||||
> .stream
|
|
||||||
padding 0
|
|
||||||
|
|
||||||
> .img
|
|
||||||
border solid 4px transparent
|
|
||||||
border-radius 8px
|
|
||||||
|
|
||||||
> .title
|
|
||||||
z-index 1
|
|
||||||
margin 0
|
|
||||||
padding 0 16px
|
|
||||||
line-height 42px
|
|
||||||
font-size 0.9em
|
|
||||||
font-weight bold
|
|
||||||
color #888
|
|
||||||
box-shadow 0 1px rgba(0, 0, 0, 0.07)
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
> .stream
|
|
||||||
display -webkit-flex
|
|
||||||
display -moz-flex
|
|
||||||
display -ms-flex
|
|
||||||
display flex
|
|
||||||
justify-content center
|
|
||||||
flex-wrap wrap
|
|
||||||
padding 8px
|
|
||||||
|
|
||||||
> .img
|
|
||||||
flex 1 1 33%
|
|
||||||
width 33%
|
|
||||||
height 80px
|
|
||||||
background-position center center
|
|
||||||
background-size cover
|
|
||||||
border solid 2px transparent
|
|
||||||
border-radius 4px
|
|
||||||
|
|
||||||
> .fetching
|
|
||||||
> .empty
|
|
||||||
margin 0
|
|
||||||
padding 16px
|
|
||||||
text-align center
|
|
||||||
color #aaa
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -1,111 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="mkw-rss">
|
|
||||||
<template v-if="!props.compact">
|
|
||||||
<p class="title">%fa:rss-square%RSS</p>
|
|
||||||
<button title="設定">%fa:cog%</button>
|
|
||||||
</template>
|
|
||||||
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
|
||||||
<div class="feed" v-else>
|
|
||||||
<a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import define from '../../../../common/define-widget';
|
|
||||||
export default define({
|
|
||||||
name: 'rss',
|
|
||||||
props: () => ({
|
|
||||||
compact: false
|
|
||||||
})
|
|
||||||
}).extend({
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
url: 'http://news.yahoo.co.jp/pickup/rss.xml',
|
|
||||||
items: [],
|
|
||||||
fetching: true,
|
|
||||||
clock: null
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.fetch();
|
|
||||||
this.clock = setInterval(this.fetch, 60000);
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
clearInterval(this.clock);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
func() {
|
|
||||||
this.props.compact = !this.props.compact;
|
|
||||||
},
|
|
||||||
fetch() {
|
|
||||||
fetch(`https://api.rss2json.com/v1/api.json?rss_url=${this.url}`, {
|
|
||||||
cache: 'no-cache'
|
|
||||||
}).then(res => {
|
|
||||||
res.json().then(feed => {
|
|
||||||
this.items = feed.items;
|
|
||||||
this.fetching = false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
|
||||||
.mkw-rss
|
|
||||||
background #fff
|
|
||||||
border solid 1px rgba(0, 0, 0, 0.075)
|
|
||||||
border-radius 6px
|
|
||||||
|
|
||||||
> .title
|
|
||||||
margin 0
|
|
||||||
padding 0 16px
|
|
||||||
line-height 42px
|
|
||||||
font-size 0.9em
|
|
||||||
font-weight bold
|
|
||||||
color #888
|
|
||||||
box-shadow 0 1px rgba(0, 0, 0, 0.07)
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
> button
|
|
||||||
position absolute
|
|
||||||
top 0
|
|
||||||
right 0
|
|
||||||
padding 0
|
|
||||||
width 42px
|
|
||||||
font-size 0.9em
|
|
||||||
line-height 42px
|
|
||||||
color #ccc
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
color #aaa
|
|
||||||
|
|
||||||
&:active
|
|
||||||
color #999
|
|
||||||
|
|
||||||
> .feed
|
|
||||||
padding 12px 16px
|
|
||||||
font-size 0.9em
|
|
||||||
|
|
||||||
> a
|
|
||||||
display block
|
|
||||||
padding 4px 0
|
|
||||||
color #666
|
|
||||||
border-bottom dashed 1px #eee
|
|
||||||
|
|
||||||
&:last-child
|
|
||||||
border-bottom none
|
|
||||||
|
|
||||||
> .fetching
|
|
||||||
margin 0
|
|
||||||
padding 16px
|
|
||||||
text-align center
|
|
||||||
color #aaa
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -1,131 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="mkw-server" :data-melt="props.design == 2">
|
|
||||||
<template v-if="props.design == 0">
|
|
||||||
<p class="title">%fa:server%%i18n:desktop.tags.mk-server-home-widget.title%</p>
|
|
||||||
<button @click="toggle" title="%i18n:desktop.tags.mk-server-home-widget.toggle%">%fa:sort%</button>
|
|
||||||
</template>
|
|
||||||
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
|
||||||
<template v-if="!fetching">
|
|
||||||
<x-cpu-memory v-show="props.view == 0" :connection="connection"/>
|
|
||||||
<x-cpu v-show="props.view == 1" :connection="connection" :meta="meta"/>
|
|
||||||
<x-memory v-show="props.view == 2" :connection="connection"/>
|
|
||||||
<x-disk v-show="props.view == 3" :connection="connection"/>
|
|
||||||
<x-uptimes v-show="props.view == 4" :connection="connection"/>
|
|
||||||
<x-info v-show="props.view == 5" :connection="connection" :meta="meta"/>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import define from '../../../../common/define-widget';
|
|
||||||
import XCpuMemory from './server.cpu-memory.vue';
|
|
||||||
import XCpu from './server.cpu.vue';
|
|
||||||
import XMemory from './server.memory.vue';
|
|
||||||
import XDisk from './server.disk.vue';
|
|
||||||
import XUptimes from './server.uptimes.vue';
|
|
||||||
import XInfo from './server.info.vue';
|
|
||||||
|
|
||||||
export default define({
|
|
||||||
name: 'server',
|
|
||||||
props: () => ({
|
|
||||||
design: 0,
|
|
||||||
view: 0
|
|
||||||
})
|
|
||||||
}).extend({
|
|
||||||
components: {
|
|
||||||
XCpuMemory,
|
|
||||||
XCpu,
|
|
||||||
XMemory,
|
|
||||||
XDisk,
|
|
||||||
XUptimes,
|
|
||||||
XInfo
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
fetching: true,
|
|
||||||
meta: null,
|
|
||||||
connection: null,
|
|
||||||
connectionId: null
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
(this as any).os.getMeta().then(meta => {
|
|
||||||
this.meta = meta;
|
|
||||||
this.fetching = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.connection = (this as any).os.streams.serverStream.getConnection();
|
|
||||||
this.connectionId = (this as any).os.streams.serverStream.use();
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
|
||||||
(this as any).os.streams.serverStream.dispose(this.connectionId);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggle() {
|
|
||||||
if (this.props.view == 5) {
|
|
||||||
this.props.view = 0;
|
|
||||||
} else {
|
|
||||||
this.props.view++;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
func() {
|
|
||||||
if (this.props.design == 2) {
|
|
||||||
this.props.design = 0;
|
|
||||||
} else {
|
|
||||||
this.props.design++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
|
||||||
.mkw-server
|
|
||||||
background #fff
|
|
||||||
border solid 1px rgba(0, 0, 0, 0.075)
|
|
||||||
border-radius 6px
|
|
||||||
|
|
||||||
&[data-melt]
|
|
||||||
background transparent !important
|
|
||||||
border none !important
|
|
||||||
|
|
||||||
> .title
|
|
||||||
z-index 1
|
|
||||||
margin 0
|
|
||||||
padding 0 16px
|
|
||||||
line-height 42px
|
|
||||||
font-size 0.9em
|
|
||||||
font-weight bold
|
|
||||||
color #888
|
|
||||||
box-shadow 0 1px rgba(0, 0, 0, 0.07)
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
> button
|
|
||||||
position absolute
|
|
||||||
z-index 2
|
|
||||||
top 0
|
|
||||||
right 0
|
|
||||||
padding 0
|
|
||||||
width 42px
|
|
||||||
font-size 0.9em
|
|
||||||
line-height 42px
|
|
||||||
color #ccc
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
color #aaa
|
|
||||||
|
|
||||||
&:active
|
|
||||||
color #999
|
|
||||||
|
|
||||||
> .fetching
|
|
||||||
margin 0
|
|
||||||
padding 16px
|
|
||||||
text-align center
|
|
||||||
color #aaa
|
|
||||||
|
|
||||||
> [data-fa]
|
|
||||||
margin-right 4px
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="root activity">
|
<div class="mk-activity">
|
||||||
<svg v-if="data" ref="canvas" viewBox="0 0 30 1" preserveAspectRatio="none">
|
<svg v-if="data" ref="canvas" viewBox="0 0 30 1" preserveAspectRatio="none">
|
||||||
<g v-for="(d, i) in data">
|
<g v-for="(d, i) in data">
|
||||||
<rect width="0.8" :height="d.postsH"
|
<rect width="0.8" :height="d.postsH"
|
||||||
|
@ -47,7 +47,7 @@ export default Vue.extend({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.root.activity
|
.mk-activity
|
||||||
max-width 600px
|
max-width 600px
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="mk-home">
|
|
||||||
<mk-timeline @loaded="onTlLoaded"/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import Vue from 'vue';
|
|
||||||
export default Vue.extend({
|
|
||||||
methods: {
|
|
||||||
onTlLoaded() {
|
|
||||||
this.$emit('loaded');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
|
||||||
.mk-home
|
|
||||||
|
|
||||||
> .mk-timeline
|
|
||||||
max-width 600px
|
|
||||||
margin 0 auto
|
|
||||||
padding 8px
|
|
||||||
|
|
||||||
@media (min-width 500px)
|
|
||||||
padding 16px
|
|
||||||
|
|
||||||
</style>
|
|
|
@ -1,7 +1,6 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
|
||||||
import ui from './ui.vue';
|
import ui from './ui.vue';
|
||||||
import home from './home.vue';
|
|
||||||
import timeline from './timeline.vue';
|
import timeline from './timeline.vue';
|
||||||
import posts from './posts.vue';
|
import posts from './posts.vue';
|
||||||
import imagesImage from './images-image.vue';
|
import imagesImage from './images-image.vue';
|
||||||
|
@ -19,9 +18,14 @@ import notificationPreview from './notification-preview.vue';
|
||||||
import usersList from './users-list.vue';
|
import usersList from './users-list.vue';
|
||||||
import userPreview from './user-preview.vue';
|
import userPreview from './user-preview.vue';
|
||||||
import userTimeline from './user-timeline.vue';
|
import userTimeline from './user-timeline.vue';
|
||||||
|
import activity from './activity.vue';
|
||||||
|
import widgetContainer from './widget-container.vue';
|
||||||
|
|
||||||
|
//#region widgets
|
||||||
|
import wActivity from './widgets/activity.vue';
|
||||||
|
//#endregion
|
||||||
|
|
||||||
Vue.component('mk-ui', ui);
|
Vue.component('mk-ui', ui);
|
||||||
Vue.component('mk-home', home);
|
|
||||||
Vue.component('mk-timeline', timeline);
|
Vue.component('mk-timeline', timeline);
|
||||||
Vue.component('mk-posts', posts);
|
Vue.component('mk-posts', posts);
|
||||||
Vue.component('mk-images-image', imagesImage);
|
Vue.component('mk-images-image', imagesImage);
|
||||||
|
@ -39,3 +43,9 @@ Vue.component('mk-notification-preview', notificationPreview);
|
||||||
Vue.component('mk-users-list', usersList);
|
Vue.component('mk-users-list', usersList);
|
||||||
Vue.component('mk-user-preview', userPreview);
|
Vue.component('mk-user-preview', userPreview);
|
||||||
Vue.component('mk-user-timeline', userTimeline);
|
Vue.component('mk-user-timeline', userTimeline);
|
||||||
|
Vue.component('mk-activity', activity);
|
||||||
|
Vue.component('mk-widget-container', widgetContainer);
|
||||||
|
|
||||||
|
//#region widgets
|
||||||
|
Vue.component('mkw-activity', wActivity);
|
||||||
|
//#endregion
|
||||||
|
|
|
@ -9,9 +9,7 @@
|
||||||
<h1>
|
<h1>
|
||||||
<slot>Misskey</slot>
|
<slot>Misskey</slot>
|
||||||
</h1>
|
</h1>
|
||||||
<button v-if="func" @click="func">
|
<slot name="func"></slot>
|
||||||
<slot name="funcIcon"></slot>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mk-ui">
|
<div class="mk-ui">
|
||||||
<x-header :func="func">
|
<x-header>
|
||||||
<template slot="funcIcon"><slot name="funcIcon"></slot></template>
|
<template slot="func"><slot name="func"></slot></template>
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
</x-header>
|
</x-header>
|
||||||
<x-nav :is-open="isDrawerOpening"/>
|
<x-nav :is-open="isDrawerOpening"/>
|
||||||
|
@ -23,7 +23,7 @@ export default Vue.extend({
|
||||||
XHeader,
|
XHeader,
|
||||||
XNav
|
XNav
|
||||||
},
|
},
|
||||||
props: ['title', 'func'],
|
props: ['title'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isDrawerOpening: false,
|
isDrawerOpening: false,
|
||||||
|
|
65
src/web/app/mobile/views/components/widget-container.vue
Normal file
65
src/web/app/mobile/views/components/widget-container.vue
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<template>
|
||||||
|
<div class="mk-widget-container" :class="{ naked }">
|
||||||
|
<header v-if="showHeader">
|
||||||
|
<div class="title"><slot name="header"></slot></div>
|
||||||
|
<slot name="func"></slot>
|
||||||
|
</header>
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
export default Vue.extend({
|
||||||
|
props: {
|
||||||
|
showHeader: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
naked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.mk-widget-container
|
||||||
|
background #eee
|
||||||
|
border-radius 8px
|
||||||
|
box-shadow 0 0 0 1px rgba(0, 0, 0, 0.2)
|
||||||
|
overflow hidden
|
||||||
|
|
||||||
|
&.naked
|
||||||
|
background transparent !important
|
||||||
|
border none !important
|
||||||
|
|
||||||
|
> header
|
||||||
|
> .title
|
||||||
|
margin 0
|
||||||
|
padding 8px 10px
|
||||||
|
font-size 15px
|
||||||
|
font-weight normal
|
||||||
|
color #465258
|
||||||
|
background #fff
|
||||||
|
border-radius 8px 8px 0 0
|
||||||
|
|
||||||
|
> [data-fa]
|
||||||
|
margin-right 6px
|
||||||
|
|
||||||
|
&:empty
|
||||||
|
display none
|
||||||
|
|
||||||
|
> button
|
||||||
|
position absolute
|
||||||
|
z-index 2
|
||||||
|
top 0
|
||||||
|
right 0
|
||||||
|
padding 0
|
||||||
|
width 42px
|
||||||
|
height 100%
|
||||||
|
font-size 15px
|
||||||
|
color #465258
|
||||||
|
|
||||||
|
</style>
|
23
src/web/app/mobile/views/components/widgets/activity.vue
Normal file
23
src/web/app/mobile/views/components/widgets/activity.vue
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<template>
|
||||||
|
<div class="mkw-activity">
|
||||||
|
<mk-widget-container>
|
||||||
|
<template slot="header">%fa:chart-bar%アクティビティ</template>
|
||||||
|
<div :class="$style.body">
|
||||||
|
<mk-activity :user="os.i"/>
|
||||||
|
</div>
|
||||||
|
</mk-widget-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import define from '../../../../common/define-widget';
|
||||||
|
|
||||||
|
export default define({
|
||||||
|
name: 'activity',
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" module>
|
||||||
|
.body
|
||||||
|
padding 8px
|
||||||
|
</style>
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<mk-ui :func="fn">
|
<mk-ui>
|
||||||
<span slot="header">
|
<span slot="header">
|
||||||
<template v-if="folder">%fa:R folder-open%{{ folder.name }}</template>
|
<template v-if="folder">%fa:R folder-open%{{ folder.name }}</template>
|
||||||
<template v-if="file"><mk-file-type-icon class="icon" :type="file.type"/>{{ file.name }}</template>
|
<template v-if="file"><mk-file-type-icon class="icon" :type="file.type"/>{{ file.name }}</template>
|
||||||
<template v-if="!folder && !file">%fa:cloud%%i18n:mobile.tags.mk-drive-page.drive%</template>
|
<template v-if="!folder && !file">%fa:cloud%%i18n:mobile.tags.mk-drive-page.drive%</template>
|
||||||
</span>
|
</span>
|
||||||
<template slot="funcIcon">%fa:ellipsis-h%</template>
|
<template slot="func"><button @click="fn">%fa:ellipsis-h%</button></template>
|
||||||
<mk-drive
|
<mk-drive
|
||||||
ref="browser"
|
ref="browser"
|
||||||
:init-folder="initFolder"
|
:init-folder="initFolder"
|
||||||
|
|
|
@ -1,24 +1,112 @@
|
||||||
<template>
|
<template>
|
||||||
<mk-ui :func="fn">
|
<mk-ui>
|
||||||
<span slot="header">%fa:home%%i18n:mobile.tags.mk-home.home%</span>
|
<span slot="header" @click="showTl = !showTl">
|
||||||
<template slot="funcIcon">%fa:pencil-alt%</template>
|
<template v-if="showTl">%fa:home%タイムライン</template>
|
||||||
<mk-home @loaded="onHomeLoaded"/>
|
<template v-else>%fa:home%ウィジェット</template>
|
||||||
|
<span style="margin-left:8px">
|
||||||
|
<template v-if="showTl">%fa:angle-down%</template>
|
||||||
|
<template v-else>%fa:angle-up%</template>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<template slot="func">
|
||||||
|
<button @click="fn" v-if="showTl">%fa:pencil-alt%</button>
|
||||||
|
<button @click="customizing = !customizing" v-else>%fa:cog%</button>
|
||||||
|
</template>
|
||||||
|
<main>
|
||||||
|
<div class="tl">
|
||||||
|
<mk-timeline @loaded="onLoaded" v-show="showTl"/>
|
||||||
|
</div>
|
||||||
|
<div class="widgets" v-if="!showTl">
|
||||||
|
<template v-if="customizing">
|
||||||
|
<header>
|
||||||
|
<select v-model="widgetAdderSelected">
|
||||||
|
<option value="profile">プロフィール</option>
|
||||||
|
<option value="calendar">カレンダー</option>
|
||||||
|
<option value="activity">アクティビティ</option>
|
||||||
|
<option value="rss">RSSリーダー</option>
|
||||||
|
<option value="photo-stream">フォトストリーム</option>
|
||||||
|
<option value="version">バージョン</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>
|
||||||
|
<p>移動するには「三」をドラッグします。削除するには「x」をタップします。</p>
|
||||||
|
</header>
|
||||||
|
<x-draggable
|
||||||
|
:list="widgets"
|
||||||
|
:options="{ handle: '.handle', animation: 150 }"
|
||||||
|
@sort="onWidgetSort"
|
||||||
|
>
|
||||||
|
<div v-for="widget in widgets" class="customize-container" :key="widget.id">
|
||||||
|
<header>
|
||||||
|
<span class="handle">%fa:bars%</span>{{ widget.name }}<button class="remove" @click="removeWidget(widget)">%fa:times%</button>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<component :is="`mkw-${widget.name}`" :widget="widget" :ref="widget.id" :is-mobile="true"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</x-draggable>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<component class="widget" v-for="widget in widgets" :is="`mkw-${widget.name}`" :key="widget.id" :widget="widget" :is-mobile="true" @chosen="warp"/>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
</mk-ui>
|
</mk-ui>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
|
import * as XDraggable from 'vuedraggable';
|
||||||
|
import * as uuid from 'uuid';
|
||||||
import Progress from '../../../common/scripts/loading';
|
import Progress from '../../../common/scripts/loading';
|
||||||
import getPostSummary from '../../../../../common/get-post-summary';
|
import getPostSummary from '../../../../../common/get-post-summary';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
|
components: {
|
||||||
|
XDraggable
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
connectionId: null,
|
||||||
unreadCount: 0
|
unreadCount: 0,
|
||||||
|
showTl: true,
|
||||||
|
widgets: [],
|
||||||
|
customizing: false,
|
||||||
|
widgetAdderSelected: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
created() {
|
||||||
|
if ((this as any).os.i.client_settings.mobile_home == null) {
|
||||||
|
Vue.set((this as any).os.i.client_settings, 'mobile_home', [{
|
||||||
|
name: 'calendar',
|
||||||
|
id: 'a'
|
||||||
|
}, {
|
||||||
|
name: 'activity',
|
||||||
|
id: 'b'
|
||||||
|
}, {
|
||||||
|
name: 'rss',
|
||||||
|
id: 'c'
|
||||||
|
}, {
|
||||||
|
name: 'photo-stream',
|
||||||
|
id: 'd'
|
||||||
|
}, {
|
||||||
|
name: 'donation',
|
||||||
|
id: 'e'
|
||||||
|
}, {
|
||||||
|
name: 'nav',
|
||||||
|
id: 'f'
|
||||||
|
}, {
|
||||||
|
name: 'version',
|
||||||
|
id: 'g'
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
this.widgets = (this as any).os.i.client_settings.mobile_home;
|
||||||
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
document.title = 'Misskey';
|
document.title = 'Misskey';
|
||||||
document.documentElement.style.background = '#313a42';
|
document.documentElement.style.background = '#313a42';
|
||||||
|
@ -40,7 +128,7 @@ export default Vue.extend({
|
||||||
fn() {
|
fn() {
|
||||||
(this as any).apis.post();
|
(this as any).apis.post();
|
||||||
},
|
},
|
||||||
onHomeLoaded() {
|
onLoaded() {
|
||||||
Progress.done();
|
Progress.done();
|
||||||
},
|
},
|
||||||
onStreamPost(post) {
|
onStreamPost(post) {
|
||||||
|
@ -54,7 +142,81 @@ export default Vue.extend({
|
||||||
this.unreadCount = 0;
|
this.unreadCount = 0;
|
||||||
document.title = 'Misskey';
|
document.title = 'Misskey';
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onWidgetSort() {
|
||||||
|
this.saveHome();
|
||||||
|
},
|
||||||
|
addWidget() {
|
||||||
|
const widget = {
|
||||||
|
name: this.widgetAdderSelected,
|
||||||
|
id: uuid(),
|
||||||
|
data: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.widgets.unshift(widget);
|
||||||
|
this.saveHome();
|
||||||
|
},
|
||||||
|
removeWidget(widget) {
|
||||||
|
this.widgets = this.widgets.filter(w => w.id != widget.id);
|
||||||
|
this.saveHome();
|
||||||
|
},
|
||||||
|
saveHome() {
|
||||||
|
(this as any).api('i/update_mobile_home', {
|
||||||
|
home: this.widgets
|
||||||
|
});
|
||||||
|
},
|
||||||
|
warp() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
main
|
||||||
|
|
||||||
|
> .tl
|
||||||
|
> .mk-timeline
|
||||||
|
max-width 600px
|
||||||
|
margin 0 auto
|
||||||
|
padding 8px
|
||||||
|
|
||||||
|
@media (min-width 500px)
|
||||||
|
padding 16px
|
||||||
|
|
||||||
|
> .widgets
|
||||||
|
margin 0 auto
|
||||||
|
max-width 500px
|
||||||
|
|
||||||
|
> header
|
||||||
|
padding 8px
|
||||||
|
background #fff
|
||||||
|
|
||||||
|
.widget
|
||||||
|
margin 8px
|
||||||
|
|
||||||
|
.customize-container
|
||||||
|
margin 8px
|
||||||
|
background #fff
|
||||||
|
|
||||||
|
> header
|
||||||
|
line-height 32px
|
||||||
|
background #eee
|
||||||
|
|
||||||
|
> .handle
|
||||||
|
padding 0 8px
|
||||||
|
|
||||||
|
> .remove
|
||||||
|
position absolute
|
||||||
|
top 0
|
||||||
|
right 0
|
||||||
|
padding 0 8px
|
||||||
|
line-height 32px
|
||||||
|
|
||||||
|
> div
|
||||||
|
padding 8px
|
||||||
|
|
||||||
|
> *
|
||||||
|
pointer-events none
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<mk-ui :func="fn">
|
<mk-ui>
|
||||||
<span slot="header">%fa:R bell%%i18n:mobile.tags.mk-notifications-page.notifications%</span>
|
<span slot="header">%fa:R bell%%i18n:mobile.tags.mk-notifications-page.notifications%</span>
|
||||||
<span slot="funcIcon">%fa:check%</span>
|
<template slot="func"><button @click="fn">%fa:check%</button></template>
|
||||||
<mk-notifications @fetched="onFetched"/>
|
<mk-notifications @fetched="onFetched"/>
|
||||||
</mk-ui>
|
</mk-ui>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<mk-ui>
|
<mk-ui>
|
||||||
<span slot="header" v-if="!fetching">%fa:user% {{ user.name }}</span>
|
<span slot="header" v-if="!fetching">%fa:user% {{ user.name }}</span>
|
||||||
<template slot="funcIcon">%fa:pencil-alt%</template>
|
|
||||||
<main v-if="!fetching">
|
<main v-if="!fetching">
|
||||||
<header>
|
<header>
|
||||||
<div class="banner" :style="user.banner_url ? `background-image: url(${user.banner_url}?thumbnail&size=1024)` : ''"></div>
|
<div class="banner" :style="user.banner_url ? `background-image: url(${user.banner_url}?thumbnail&size=1024)` : ''"></div>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<section class="activity">
|
<section class="activity">
|
||||||
<h2>%fa:chart-bar%%i18n:mobile.tags.mk-user-overview.activity%</h2>
|
<h2>%fa:chart-bar%%i18n:mobile.tags.mk-user-overview.activity%</h2>
|
||||||
<div>
|
<div>
|
||||||
<x-activity :user="user"/>
|
<mk-activity :user="user"/>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="frequently-replied-users">
|
<section class="frequently-replied-users">
|
||||||
|
@ -41,15 +41,13 @@ import XPosts from './home.posts.vue';
|
||||||
import XPhotos from './home.photos.vue';
|
import XPhotos from './home.photos.vue';
|
||||||
import XFriends from './home.friends.vue';
|
import XFriends from './home.friends.vue';
|
||||||
import XFollowersYouKnow from './home.followers-you-know.vue';
|
import XFollowersYouKnow from './home.followers-you-know.vue';
|
||||||
import XActivity from './home.activity.vue';
|
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XPosts,
|
XPosts,
|
||||||
XPhotos,
|
XPhotos,
|
||||||
XFriends,
|
XFriends,
|
||||||
XFollowersYouKnow,
|
XFollowersYouKnow
|
||||||
XActivity
|
|
||||||
},
|
},
|
||||||
props: ['user']
|
props: ['user']
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue