Merge branch 'develop' into sw-notification-action

This commit is contained in:
tamaina
2021-07-17 21:39:17 +09:00
41 changed files with 1016 additions and 679 deletions

View File

@@ -9,6 +9,8 @@ import { unisonReload, reloadChannel } from '@client/scripts/unison-reload';
type Account = {
id: string;
token: string;
isModerator: boolean;
isAdmin: boolean;
};
const data = localStorage.getItem('account');

View File

@@ -1,8 +1,8 @@
<template>
<div class="hoawjimk">
<div class="mk-media-list">
<XBanner v-for="media in mediaList.filter(media => !previewable(media))" :media="media" :key="media.id"/>
<div v-if="mediaList.filter(media => previewable(media)).length > 0" class="gird-container">
<div :data-count="mediaList.filter(media => previewable(media)).length">
<div v-if="mediaList.filter(media => previewable(media)).length > 0" class="gird-container" ref="gridOuter">
<div :data-count="mediaList.filter(media => previewable(media)).length" :style="gridInnerStyle">
<template v-for="media in mediaList">
<XVideo :video="media" :key="media.id" v-if="media.type.startsWith('video')"/>
<XImage :image="media" :key="media.id" v-else-if="media.type.startsWith('image')" :raw="raw"/>
@@ -33,16 +33,57 @@ export default defineComponent({
default: false
},
},
data() {
return {
gridInnerStyle: {},
sizeWaiting: false
}
},
mounted() {
this.size();
window.addEventListener('resize', this.size);
},
beforeUnmount() {
window.removeEventListener('resize', this.size);
},
activated() {
this.size();
},
methods: {
previewable(file) {
return file.type.startsWith('video') || file.type.startsWith('image');
},
size() {
// for Safari bug
if (this.sizeWaiting) return;
this.sizeWaiting = true;
window.requestAnimationFrame(() => {
this.sizeWaiting = false;
if (this.$refs.gridOuter) {
let height = 287;
const parent = this.$parent.$el;
if (this.$refs.gridOuter.clientHeight) {
height = this.$refs.gridOuter.clientHeight;
} else if (parent) {
height = parent.getBoundingClientRect().width * 9 / 16;
}
this.gridInnerStyle = { height: `${height}px` };
} else {
this.gridInnerStyle = {};
}
});
}
},
});
</script>
<style lang="scss" scoped>
.hoawjimk {
.mk-media-list {
> .gird-container {
position: relative;
width: 100%;

View File

@@ -61,7 +61,7 @@ import * as mfm from 'mfm-js';
import { host, url } from '@client/config';
import { erase, unique } from '../../prelude/array';
import { extractMentions } from '@/misc/extract-mentions';
import getAcct from '@/misc/acct/render';
import { getAcct } from '@/misc/acct';
import { formatTimeString } from '@/misc/format-time-string';
import { Autocomplete } from '@client/scripts/autocomplete';
import { noteVisibilities } from '../../types';

View File

@@ -29,7 +29,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import MkFollowButton from './follow-button.vue';
import { userPage } from '../filters/user';

View File

@@ -33,7 +33,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import MkFollowButton from './follow-button.vue';
import { userPage } from '../filters/user';
import * as os from '@client/os';

View File

@@ -1,4 +1,4 @@
import getAcct from '@/misc/acct/render';
import { getAcct } from '@/misc/acct';
import getUserName from '@/misc/get-user-name';
import { url } from '@client/config';

View File

@@ -77,18 +77,6 @@ console.info(`Misskey v${version}`);
window.onerror = null;
window.onunhandledrejection = null;
// 後方互換性のため。
// TODO: そのうち消す
if ((typeof ColdDeviceStorage.get('lightTheme') === 'string') || (typeof ColdDeviceStorage.get('darkTheme') === 'string')) {
ColdDeviceStorage.set('lightTheme', require('@client/themes/l-light.json5'));
ColdDeviceStorage.set('darkTheme', require('@client/themes/d-dark.json5'));
}
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://use.fontawesome.com/releases/v5.15.3/css/all.css';
document.head.appendChild(link);
// TODOここまで
if (_DEV_) {
console.warn('Development mode!!!');

View File

@@ -6,7 +6,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import * as os from '@client/os';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
export default defineComponent({
created() {

View File

@@ -63,7 +63,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import MkButton from '@client/components/ui/button.vue';
import MkInput from '@client/components/ui/input.vue';
import MkSelect from '@client/components/ui/select.vue';

View File

@@ -38,7 +38,7 @@
<script lang="ts">
import { defineAsyncComponent, defineComponent } from 'vue';
import getAcct from '@/misc/acct/render';
import { getAcct } from '@/misc/acct';
import MkButton from '@client/components/ui/button.vue';
import { acct } from '../../filters/user';
import * as os from '@client/os';

View File

@@ -40,7 +40,7 @@ import { computed, defineComponent } from 'vue';
import XList from '@client/components/date-separated-list.vue';
import XMessage from './messaging-room.message.vue';
import XForm from './messaging-room.form.vue';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import { isBottom, onScrollBottom, scroll } from '@client/scripts/scroll';
import * as os from '@client/os';
import { popout } from '@client/scripts/popout';

View File

@@ -52,7 +52,7 @@ import MkInput from '@client/components/ui/input.vue';
import MkTextarea from '@client/components/ui/textarea.vue';
import MkSelect from '@client/components/ui/select.vue';
import MkSwitch from '@client/components/ui/switch.vue';
import getAcct from '@/misc/acct/render';
import { getAcct } from '@/misc/acct';
import * as os from '@client/os';
export default defineComponent({

View File

@@ -52,7 +52,7 @@
<script lang="ts">
import { computed, defineComponent } from 'vue';
import { Room } from '@client/scripts/room/room';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import XPreview from './preview.vue';
const storeItems = require('@client/scripts/room/furnitures.json5');
import { query as urlQuery } from '../../../prelude/url';

View File

@@ -0,0 +1,72 @@
<template>
<FormBase>
<FormInfo warn>{{ $ts.customCssWarn }}</FormInfo>
<FormTextarea v-model:value="localCustomCss" manual-save tall class="_monospace" style="tab-size: 2;">
<span>{{ $ts.local }}</span>
</FormTextarea>
</FormBase>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import FormTextarea from '@client/components/form/textarea.vue';
import FormSelect from '@client/components/form/select.vue';
import FormRadios from '@client/components/form/radios.vue';
import FormBase from '@client/components/form/base.vue';
import FormGroup from '@client/components/form/group.vue';
import FormLink from '@client/components/form/link.vue';
import FormButton from '@client/components/form/button.vue';
import FormInfo from '@client/components/form/info.vue';
import * as os from '@client/os';
import { ColdDeviceStorage } from '@client/store';
import { unisonReload } from '@client/scripts/unison-reload';
import * as symbols from '@client/symbols';
import { defaultStore } from '@client/store';
export default defineComponent({
components: {
FormTextarea,
FormSelect,
FormRadios,
FormBase,
FormGroup,
FormLink,
FormButton,
FormInfo,
},
emits: ['info'],
data() {
return {
[symbols.PAGE_INFO]: {
title: this.$ts.customCss,
icon: 'fas fa-code'
},
localCustomCss: localStorage.getItem('customCss')
}
},
mounted() {
this.$emit('info', this[symbols.PAGE_INFO]);
this.$watch('localCustomCss', this.apply);
},
methods: {
async apply() {
localStorage.setItem('customCss', this.localCustomCss);
const { canceled } = await os.dialog({
type: 'info',
text: this.$ts.reloadToApplySetting,
showCancelButton: true
});
if (canceled) return;
unisonReload();
}
}
});
</script>

View File

@@ -78,6 +78,8 @@
</FormSelect>
<FormLink to="/settings/deck">{{ $ts.deck }}</FormLink>
<FormLink to="/settings/custom-css"><template #icon><i class="fas fa-code"></i></template>{{ $ts.customCss }}</FormLink>
</FormBase>
</template>

View File

@@ -123,6 +123,7 @@ export default defineComponent({
case 'theme/manage': return defineAsyncComponent(() => import('./theme.manage.vue'));
case 'sidebar': return defineAsyncComponent(() => import('./sidebar.vue'));
case 'sounds': return defineAsyncComponent(() => import('./sounds.vue'));
case 'custom-css': return defineAsyncComponent(() => import('./custom-css.vue'));
case 'deck': return defineAsyncComponent(() => import('./deck.vue'));
case 'plugin': return defineAsyncComponent(() => import('./plugin.vue'));
case 'plugin/install': return defineAsyncComponent(() => import('./plugin.install.vue'));

View File

@@ -29,6 +29,7 @@ import * as os from '@client/os';
import { sidebarDef } from '@client/sidebar';
import { defaultStore } from '@client/store';
import * as symbols from '@client/symbols';
import { unisonReload } from '@client/scripts/unison-reload';
export default defineComponent({
components: {
@@ -106,7 +107,7 @@ export default defineComponent({
});
if (canceled) return;
location.reload();
unisonReload();
}
},
});

View File

@@ -234,7 +234,7 @@ import MkRemoteCaution from '@client/components/remote-caution.vue';
import MkTab from '@client/components/tab.vue';
import MkInfo from '@client/components/ui/info.vue';
import Progress from '@client/scripts/loading';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import { getScrollPosition } from '@client/scripts/scroll';
import { getUserMenu } from '@client/scripts/get-user-menu';
import number from '../../filters/number';

View File

@@ -1,4 +1,4 @@
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import { host as localHost } from '@client/config';
export async function genSearchQuery(v: any, q: string) {

View File

@@ -1,7 +1,7 @@
import { i18n } from '@client/i18n';
import copyToClipboard from '@client/scripts/copy-to-clipboard';
import { host } from '@client/config';
import getAcct from '@/misc/acct/render';
import { getAcct } from '@/misc/acct';
import * as os from '@client/os';
import { userActions } from '@client/store';
import { router } from '@client/router';

View File

@@ -1,4 +1,4 @@
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import { i18n } from '@client/i18n';
import * as os from '@client/os';

View File

@@ -1,5 +1,6 @@
import * as os from '@client/os';
import { i18n } from '@client/i18n';
import { defaultStore } from '@client/store';
export function selectFile(src: any, label: string | null, multiple = false) {
return new Promise((res, rej) => {
@@ -8,7 +9,7 @@ export function selectFile(src: any, label: string | null, multiple = false) {
input.type = 'file';
input.multiple = multiple;
input.onchange = () => {
const promises = Array.from(input.files).map(file => os.upload(file));
const promises = Array.from(input.files).map(file => os.upload(file, defaultStore.state.uploadFolder));
Promise.all(promises).then(driveFiles => {
res(multiple ? driveFiles : driveFiles[0]);
@@ -57,6 +58,7 @@ export function selectFile(src: any, label: string | null, multiple = false) {
os.api('drive/files/upload-from-url', {
url: url,
folderId: defaultStore.state.uploadFolder,
marker
});

View File

@@ -37,7 +37,7 @@ export const defaultStore = markRaw(new Storage('base', {
},
uploadFolder: {
where: 'account',
default: null
default: null as string | null
},
pastedFileName: {
where: 'account',

View File

@@ -55,7 +55,7 @@ import * as mfm from 'mfm-js';
import { host, url } from '@client/config';
import { erase, unique } from '../../../prelude/array';
import { extractMentions } from '@/misc/extract-mentions';
import getAcct from '@/misc/acct/render';
import { getAcct } from '@/misc/acct';
import { formatTimeString } from '@/misc/format-time-string';
import { Autocomplete } from '@client/scripts/autocomplete';
import * as os from '@client/os';

14
src/misc/acct.ts Normal file
View File

@@ -0,0 +1,14 @@
export type Acct = {
username: string;
host: string | null;
};
export const getAcct = (user: Acct) => {
return user.host == null ? user.username : `${user.username}@${user.host}`;
};
export const parseAcct = (acct: string): Acct => {
if (acct.startsWith('@')) acct = acct.substr(1);
const split = acct.split('@', 2);
return { username: split[0], host: split[1] || null };
};

View File

@@ -1,7 +0,0 @@
import Acct from './type';
export default (acct: string): Acct => {
if (acct.startsWith('@')) acct = acct.substr(1);
const split = acct.split('@', 2);
return { username: split[0], host: split[1] || null };
};

View File

@@ -1,5 +0,0 @@
import Acct from './type';
export default (user: Acct) => {
return user.host == null ? user.username : `${user.username}@${user.host}`;
};

View File

@@ -1,6 +0,0 @@
type Acct = {
username: string;
host: string | null;
};
export default Acct;

View File

@@ -2,9 +2,9 @@ import { Antenna } from '../models/entities/antenna';
import { Note } from '../models/entities/note';
import { User } from '../models/entities/user';
import { UserListJoinings, UserGroupJoinings } from '../models';
import parseAcct from './acct/parse';
import { getFullApAccount } from './convert-host';
import { PackedNote } from '../models/repositories/note';
import { parseAcct } from '@/misc/acct';
/**
* noteUserFollowers / antennaUserFollowing はどちらか一方が指定されていればよい

View File

@@ -2,7 +2,7 @@ import * as Bull from 'bull';
import { queueLogger } from '../../logger';
import follow from '../../../services/following/create';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import { resolveUser } from '../../../remote/resolve-user';
import { downloadTextFile } from '@/misc/download-text-file';
import { isSelfHost, toPuny } from '@/misc/convert-host';

View File

@@ -1,7 +1,7 @@
import * as Bull from 'bull';
import { queueLogger } from '../../logger';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import { resolveUser } from '../../../remote/resolve-user';
import { pushUserToUserList } from '../../../services/user-list/push';
import { downloadTextFile } from '@/misc/download-text-file';

View File

@@ -1,7 +1,7 @@
import define from '../define';
import { Users } from '../../../models';
import { fetchMeta } from '@/misc/fetch-meta';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import { User } from '../../../models/entities/user';
export const meta = {

View File

@@ -1,7 +1,7 @@
import * as Limiter from 'ratelimiter';
import { redisClient } from '../../db/redis';
import { IEndpoint } from './endpoints';
import getAcct from '@/misc/acct/render';
import { getAcct } from '@/misc/acct';
import { User } from '../../models/entities/user';
import Logger from '../../services/logger';

View File

@@ -107,6 +107,13 @@
document.documentElement.style.backgroundImage = `url(${wallpaper})`;
}
const customCss = localStorage.getItem('customCss');
if (customCss && customCss.length > 0) {
const style = document.createElement('style');
style.innerHTML = customCss;
head.appendChild(style);
}
// eslint-disable-next-line no-inner-declarations
function renderError(code, details) {
document.documentElement.innerHTML = `

View File

@@ -18,7 +18,7 @@ import { fetchMeta } from '@/misc/fetch-meta';
import { genOpenapiSpec } from '../api/openapi/gen-spec';
import config from '@/config';
import { Users, Notes, Emojis, UserProfiles, Pages, Channels, Clips, GalleryPosts } from '../../models';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
import { getNoteSummary } from '@/misc/get-note-summary';
import { getConnection } from 'typeorm';
import { redisClient } from '../../db/redis';

View File

@@ -1,8 +1,7 @@
import * as Router from '@koa/router';
import config from '@/config';
import parseAcct from '@/misc/acct/parse';
import Acct from '@/misc/acct/type';
import { parseAcct, Acct } from '@/misc/acct';
import { links } from './nodeinfo';
import { escapeAttribute, escapeValue } from '../prelude/xml';
import { Users } from '../models';

View File

@@ -3,15 +3,17 @@ import { User } from '../models/entities/user';
import { sendEmail } from './send-email';
import * as locales from '../../locales/';
import { I18n } from '@/misc/i18n';
import { getAcct } from '@/misc/acct';
// TODO: locale ファイルをクライアント用とサーバー用で分けたい
async function follow(userId: User['id'], args: {}) {
async function follow(userId: User['id'], follower: User) {
const userProfile = await UserProfiles.findOneOrFail({ userId: userId });
if (!userProfile.email || !userProfile.emailNotificationTypes.includes('follow')) return;
const locale = locales[userProfile.lang || 'ja-JP'];
const i18n = new I18n(locale);
sendEmail(userProfile.email, i18n.t('_email._follow.title'), 'test', 'test');
// TODO: render user information html
sendEmail(userProfile.email, i18n.t('_email._follow.title'), `${follower.name} (@${getAcct(follower)})`, `${follower.name} (@${getAcct(follower)})`);
}
async function receiveFollowRequest(userId: User['id'], args: {}) {

View File

@@ -1,5 +1,5 @@
import { initDb } from '@/db/postgre';
import parseAcct from '@/misc/acct/parse';
import { parseAcct } from '@/misc/acct';
async function main(acct: string): Promise<any> {
await initDb();