Merge branch 'develop' into sw-notification-action

This commit is contained in:
tamaina
2021-08-05 02:59:56 +09:00
42 changed files with 271 additions and 81 deletions

View File

@@ -10,6 +10,7 @@
<span class="separator" v-if="folder != null"><i class="fas fa-angle-right"></i></span>
<span class="folder current" v-if="folder != null">{{ folder.name }}</span>
</div>
<button @click="showMenu" class="menu _button"><i class="fas fa-ellipsis-h"></i></button>
</nav>
<div class="main" :class="{ uploading: uploadings.length > 0, fetching }"
ref="main"
@@ -627,8 +628,12 @@ export default defineComponent({
}];
},
onContextmenu(e) {
os.contextMenu(this.getMenu(), e);
showMenu(ev) {
os.modalMenu(this.getMenu(), ev.currentTarget || ev.target);
},
onContextmenu(ev) {
os.contextMenu(this.getMenu(), ev);
},
}
});
@@ -641,7 +646,7 @@ export default defineComponent({
height: 100%;
> nav {
display: block;
display: flex;
z-index: 2;
width: 100%;
padding: 0 8px;
@@ -696,6 +701,10 @@ export default defineComponent({
}
}
}
> .menu {
margin-left: auto;
}
}
> .main {

View File

@@ -107,6 +107,7 @@ export default defineComponent({
padding: 32px;
max-width: 800px;
margin: 0 auto;
background: var(--panel);
&.max-width_500px {
padding: 16px;

View File

@@ -1,14 +1,38 @@
<template>
<div>
<main class="_section">
<div class="_content">
<ul>
<li v-for="doc in docs" :key="doc.path">
<MkA :to="`/docs/${doc.path}`">{{ doc.title }}</MkA>
</li>
</ul>
<div class="vtaihdtm">
<div class="search">
<MkInput v-model:value="query" :debounce="true" type="search"><template #icon><i class="fas fa-search"></i></template><span>{{ $ts.search }}</span></MkInput>
</div>
<MkFolder>
<template #header>{{ $ts._docs.generalTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('general/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</main>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.features }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('features/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
<MkFolder>
<template #header>{{ $ts._docs.advancedTopics }}</template>
<div class="docs">
<MkA v-for="doc in docs.filter(doc => doc.path.startsWith('advanced/'))" :key="doc.path" :to="`/docs/${doc.path}`" class="doc">
<div class="title">{{ doc.title }}</div>
<div class="summary">{{ doc.summary }}</div>
<div class="read">{{ $ts._docs.continueReading }}</div>
</MkA>
</div>
</MkFolder>
</div>
</template>
@@ -16,8 +40,15 @@
import { defineComponent } from 'vue';
import { url, lang } from '@client/config';
import * as symbols from '@client/symbols';
import MkFolder from '@client/components/ui/folder.vue';
import MkInput from '@client/components/ui/input.vue';
export default defineComponent({
components: {
MkFolder,
MkInput,
},
data() {
return {
[symbols.PAGE_INFO]: {
@@ -25,6 +56,15 @@ export default defineComponent({
icon: 'fas fa-question-circle'
},
docs: [],
query: null,
}
},
watch: {
query() {
fetch(`${url}/docs.json?lang=${lang}&q=${this.query}`).then(res => res.json()).then(docs => {
this.docs = docs;
});
}
},
@@ -35,3 +75,48 @@ export default defineComponent({
},
});
</script>
<style lang="scss" scoped>
.vtaihdtm {
background: var(--panel);
> .search {
padding: 8px;
}
.docs {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
grid-gap: 12px;
margin: var(--margin);
> .doc {
display: inline-block;
padding: 16px;
border: solid 1px var(--divider);
border-radius: 6px;
&:hover {
border: solid 1px var(--accent);
text-decoration: none;
}
> .title {
font-weight: bold;
}
> .summary {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.9em;
}
> .read {
color: var(--link);
font-size: 0.9em;
}
}
}
}
</style>

View File

@@ -20,7 +20,6 @@ export default defineComponent({
[symbols.PAGE_INFO]: {
title: computed(() => this.folder ? this.folder.name : this.$ts.drive),
icon: 'fas fa-cloud',
menu: () => this.$refs.drive.getMenu()
},
folder: null,
};

View File

@@ -167,13 +167,13 @@ export default defineComponent({
},
async resetPassword() {
os.apiWithDialog('admin/reset-password', {
const { password } = await os.api('admin/reset-password', {
userId: this.user.id,
}, undefined, ({ password }) => {
os.dialog({
type: 'success',
text: this.$t('newPasswordIs', { password })
});
});
os.dialog({
type: 'success',
text: this.$t('newPasswordIs', { password })
});
},

View File

@@ -237,8 +237,8 @@ import Progress from '@client/scripts/loading';
import { parseAcct } from '@/misc/acct';
import { getScrollPosition } from '@client/scripts/scroll';
import { getUserMenu } from '@client/scripts/get-user-menu';
import number from '../../filters/number';
import { userPage, acct as getAcct } from '../../filters/user';
import number from '@client/filters/number';
import { userPage, acct as getAcct } from '@client/filters/user';
import * as os from '@client/os';
import * as symbols from '@client/symbols';
@@ -282,7 +282,6 @@ export default defineComponent({
share: {
title: this.user.name,
},
menu: () => getUserMenu(this.user),
} : null),
user: null,
error: null,

View File

@@ -31,7 +31,7 @@ export const router = createRouter({
{ path: '/docs', component: page('docs') },
{ path: '/theme-editor', component: page('theme-editor') },
{ path: '/advanced-theme-editor', component: page('advanced-theme-editor') },
{ path: '/docs/:doc', component: page('doc'), props: route => ({ doc: route.params.doc }) },
{ path: '/docs/:doc(.*)', component: page('doc'), props: route => ({ doc: route.params.doc }) },
{ path: '/explore', component: page('explore') },
{ path: '/explore/tags/:tag', props: true, component: page('explore') },
{ path: '/search', component: page('search') },

View File

@@ -94,7 +94,11 @@ export default (opts) => ({
for (let i = 0; i < items.length; i++) {
const item = items[i];
markRaw(item);
if (i === 3) item._shouldInsertAd_ = true;
if (this.pagination.reversed) {
if (i === items.length - 2) item._shouldInsertAd_ = true;
} else {
if (i === 3) item._shouldInsertAd_ = true;
}
}
if (!this.pagination.noPaging && (items.length > (this.pagination.limit || 10))) {
items.pop();
@@ -133,7 +137,11 @@ export default (opts) => ({
for (let i = 0; i < items.length; i++) {
const item = items[i];
markRaw(item);
if (i === 10) item._shouldInsertAd_ = true;
if (this.pagination.reversed) {
if (i === items.length - 9) item._shouldInsertAd_ = true;
} else {
if (i === 10) item._shouldInsertAd_ = true;
}
}
if (items.length > SECOND_FETCH_LIMIT) {
items.pop();

View File

@@ -239,8 +239,7 @@ hr {
._panel {
background: var(--panel);
border-radius: var(--radius);
//border: var(--panelBorder);
box-shadow: var(--panelShadow);
border: var(--panelBorder);
overflow: clip;
}
@@ -357,7 +356,7 @@ hr {
._flat_ {
--root-margin: 0px;
--baseContentWidth: 100%;
--panelShadow: none;
--panelBorder: none;
._block {
//border-top: solid 0.5px var(--divider);

View File

@@ -26,8 +26,7 @@
panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
panelBorder: 'rgba(0, 0, 0, 0)',
panelShadow: '" 0 8px 24px rgba(0, 0, 0, 0.12)',
panelBorder: '" solid 1px var(--divider)',
acrylicPanel: ':alpha<0.5<@panel',
shadow: 'rgba(0, 0, 0, 0.3)',
header: ':alpha<0.7<@panel',

View File

@@ -26,8 +26,7 @@
panelHeaderBg: ':lighten<3<@panel',
panelHeaderFg: '@fg',
panelHeaderDivider: 'rgba(0, 0, 0, 0)',
panelBorder: 'rgba(0, 0, 0, 0)',
panelShadow: '" 0 8px 24px rgb(21 43 75 / 8%)',
panelBorder: '" solid 1px var(--divider)',
acrylicPanel: ':alpha<0.5<@panel',
shadow: 'rgba(0, 0, 0, 0.1)',
header: ':alpha<0.7<@panel',

View File

@@ -39,8 +39,7 @@
navHoverFg: ':lighten<17<@fg',
dateLabelFg: '@fg',
inputBorder: '#959da2',
panelBorder: 'rgba(0, 0, 0, 0)',
panelShadow: '" 0 8px 24px rgba(0, 0, 0, 0.12)',
panelBorder: '" solid 1px var(--divider)',
accentDarken: ':darken<10<@accent',
acrylicPanel: ':alpha<0.5<@panel',
navIndicator: '@accent',

View File

@@ -11,7 +11,6 @@
panel: '#131313',
panelHeaderBg: '@panel',
panelHeaderDivider: '@divider',
panelShadow: '" 0 8px 24px rgb(0 0 0 / 25%)',
shadow: 'rgba(255, 255, 255, 0.05)',
modalBg: 'rgba(255, 255, 255, 0.1)',
messageBg: '#1d1d1d',

View File

@@ -13,7 +13,6 @@
fgHighlighted: '#fff',
divider: 'rgba(255, 255, 255, 0.14)',
panel: '#2d2d2d',
panelShadow: '" 0 8px 24px rgb(0 0 0 / 25%)',
panelHeaderBg: '@panel',
panelHeaderDivider: '@divider',
header: ':alpha<0.7<@panel',

View File

@@ -13,7 +13,6 @@
fgHighlighted: '#fff',
divider: 'rgba(255, 255, 255, 0.14)',
panel: 'rgb(41, 43, 41)',
panelShadow: '" 0 8px 24px rgb(0 0 0 / 25%)',
infoFg: '@fg',
infoBg: '#333c3b',
navBg: '#141714',

View File

@@ -14,7 +14,6 @@
header: ':alpha<0.7<@panel',
navBg: '#fff',
panel: '#fff',
panelShadow: '" 0 8px 24px rgb(21 43 75 / 8%)',
panelHeaderDivider: '@divider',
messageBg: '#dedede',
},

View File

@@ -42,8 +42,7 @@
navHoverFg: ':darken<17<@fg',
dateLabelFg: '@fg',
inputBorder: '#dae0e4',
panelBorder: 'rgba(0, 0, 0, 0)',
panelShadow: '" 0 8px 24px rgb(21 43 75 / 8%)',
panelBorder: '" solid 1px var(--divider)',
accentDarken: ':darken<10<@accent',
acrylicPanel: ':alpha<0.5<@panel',
navIndicator: '@accent',

View File

@@ -1,17 +1,23 @@
<script lang="ts">
import { defineComponent, h, TransitionGroup } from 'vue';
import { defineComponent, h, PropType, TransitionGroup } from 'vue';
import MkAd from '@client/components/global/ad.vue';
export default defineComponent({
props: {
items: {
type: Array,
type: Array as PropType<{ id: string; createdAt: string; _shouldInsertAd_: boolean; }[]>,
required: true,
},
reversed: {
type: Boolean,
required: false,
default: false
}
},
ad: {
type: Boolean,
required: false,
default: false
},
},
methods: {
@@ -66,7 +72,15 @@ export default defineComponent({
return [el, separator];
} else {
return el;
if (this.ad && item._shouldInsertAd_) {
return [h(MkAd, {
class: 'a', // advertiseの意(ブロッカー対策)
key: item.id + ':ad',
prefer: ['horizontal', 'horizontal-big'],
}), el];
} else {
return el;
}
}
}));
},

View File

@@ -55,6 +55,7 @@
<MkA to="/my/favorites" class="item"><i class="fas fa-star icon"></i>{{ $ts.favorites }}</MkA>
</div>
</div>
<MkAd class="a" prefer="square"/>
</div>
<footer class="footer">
<div class="left">
@@ -64,7 +65,7 @@
</div>
<div class="right">
<button class="_button item search" @click="search" v-tooltip="$ts.search">
<i class="fas fa-search"></i>
<i class="fas fa-search icon"></i>
</button>
<MkA class="item" to="/settings" v-tooltip="$ts.settings"><i class="fas fa-cog icon"></i></MkA>
</div>
@@ -351,7 +352,7 @@ export default defineComponent({
flex-direction: column;
width: 250px;
height: 100vh;
border-right: solid 0.5px var(--divider);
border-right: solid 4px var(--divider);
> .header, > .footer {
$padding: 8px;
@@ -373,7 +374,7 @@ export default defineComponent({
> .left, > .right {
> .item, > .menu {
display: inline-block;
display: inline-flex;
vertical-align: middle;
height: ($header-height - ($padding * 2));
width: ($header-height - ($padding * 2));
@@ -387,11 +388,6 @@ export default defineComponent({
}
> .icon {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
}
@@ -503,6 +499,10 @@ export default defineComponent({
}
}
}
> .a {
margin: 12px;
}
}
}
@@ -596,7 +596,7 @@ export default defineComponent({
> .side {
width: 350px;
border-left: solid 0.5px var(--divider);
border-left: solid 4px var(--divider);
&.widgets.sideViewOpening {
@media (max-width: 1400px) {

View File

@@ -16,7 +16,7 @@
</MkButton>
</div>
<XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed">
<XList ref="notes" :items="notes" v-slot="{ item: note }" :direction="reversed ? 'up' : 'down'" :reversed="reversed" :ad="true">
<XNote :note="note" @update:note="updated(note, $event)" :key="note._featuredId_ || note._prId_ || note.id"/>
</XList>

View File

@@ -5,7 +5,7 @@
<XHeader class="title" :info="pageInfo" :with-back="false" :center="false"/>
<button class="_button" @click="close()"><i class="fas fa-times"></i></button>
</header>
<component :is="component" v-bind="props" :ref="changePage"/>
<component :is="component" v-bind="props" :ref="changePage" class="_flat_"/>
</div>
</template>

View File

@@ -64,7 +64,7 @@ export default defineComponent({
<style lang="scss" scoped>
.wtdtxvec {
--margin: 8px;
--panelShadow: none;
--panelBorder: none;
padding: 0 var(--margin);
}

View File

@@ -143,7 +143,7 @@ export default defineComponent({
},
attachSticky(ref) {
const sticky = new StickySidebar(this.$refs[ref], this.$store.state.menuDisplay === 'top' ? 1 : 16, this.$store.state.menuDisplay === 'top' ? 60 : 0); // TODO: ヘッダーの高さを60pxと決め打ちしているのを直す
const sticky = new StickySidebar(this.$refs[ref], this.$store.state.menuDisplay === 'top' ? 0 : 16, this.$store.state.menuDisplay === 'top' ? 60 : 0); // TODO: ヘッダーの高さを60pxと決め打ちしているのを直す
window.addEventListener('scroll', () => {
sticky.calc(window.scrollY);
}, { passive: true });
@@ -230,8 +230,6 @@ export default defineComponent({
$widgets-hide-threshold: 1200px;
$nav-icon-only-width: 78px; // TODO: どこかに集約したい
--panelShadow: 0 0 0 1px var(--divider);
// ほんとは単に 100vh と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
min-height: calc(var(--vh, 1vh) * 100);
box-sizing: border-box;
@@ -290,7 +288,6 @@ export default defineComponent({
width: 750px;
margin: 0 16px 0 0;
background: var(--bg);
box-shadow: 0 0 0 1px var(--divider);
border-radius: 0;
--margin: 12px;
@@ -321,7 +318,7 @@ export default defineComponent({
}
> .widgets {
//--panelShadow: none;
//--panelBorder: none;
width: 300px;
margin-top: 16px;
@@ -342,14 +339,13 @@ export default defineComponent({
--globalHeaderHeight: 60px; // TODO: 60pxと決め打ちしているのを直す
> .main {
margin-top: 1px;
margin-top: 0;
border-radius: var(--radius);
box-shadow: 0 0 0 1px var(--divider);
}
> .widgets {
--stickyTop: var(--globalHeaderHeight);
margin-top: 1px;
margin-top: 0;
}
}

View File

@@ -9,7 +9,6 @@
## リモート投稿へのリアクションについて
リアクションはMisskeyオリジナルの機能であるため、リモートインスタンスがMisskeyでない限りは、ほとんどの場合「Like」としてアクティビティが送信されます。一般的にはLikeは「お気に入り」として実装されているようです。
また、相手がMisskeyであったとしても、カスタム絵文字リアクションは伝わらず、自動的に「👍」等にフォールバックされます。
## リモートからのリアクションについて
リモートから「Like」アクティビティを受信したとき、Misskeyでは「👍」のリアクションとして解釈されます。

View File

@@ -0,0 +1,43 @@
# Misskeyについて
Misskeyはオープンソースの分散型マイクロブログプラットフォームプロジェクトです。
開発はsyuiloによって2014年から開始されました。
## 分散型とは何か?
分散(distributed)型とは、非中央集権(decentralized)とも呼ばれ、コミュニティが多数のサーバーに分散して存在し、それらが相互に通信することでコンテンツ共有ネットワークを形成していることが特徴のサービスです。
単一のサーバーしか存在しない、もしくは複数存在しても互いに独立している場合は中央集権なサービスと言われ、例えばTwitterやFacebookなどほとんどのサービスがそれに該当します。
## 常にオープンソース
Misskeyはこれまでもこれからも、オープンソースであり続けます。オープンソースとは、ソフトウェアのソースコード(プログラム)が公開されていることです。ソースコードの修正や再配布が可能であることを定義に含めることもあります。
Misskeyのすべてのソースコードは公開されていて、誰でも自由に閲覧、使用、修正、改変、再配布をすることができます。
オープンソースは、自分で好きなように変えたり、有害な処理が含まれていないことを確認することができたり、誰でも開発に参加できるなどの、様々なメリットがあります。
上述の分散型を実現するためにも、オープンソースであるということは必要不可欠な要素です。
再び引き合いに出しますが、TwitterやFacebookなどの利益を得ているほとんどのサービスはオープンソースではありません。
Misskeyのソースコードは、[GitHub上で公開されています。](https://github.com/misskey-dev)
## 開発に参加する、開発を支援する
Misskeyの開発に貢献するにはいろいろな方法があります。
### 機能を追加したり、バグを修正する
ソフトウェアエンジニアのスキルをお持ちの方であれば、ソースコードを編集する形でプロジェクトに貢献することができます。
### 議論に参加する
新しい機能、または既存の機能について意見を述べたり、不具合を報告したりすることでも貢献できます。
そのようなディスカッションは[GitHub](https://github.com/misskey-dev)上か、[フォーラム](https://forum.misskey.io/)等で行われます。
### テキストを翻訳する
Misskeyは様々な言語に対応しています(i18n -internationalizationの略- と呼ばれます)。元の言語は基本的に日本語ですが、有志によって他の言語へと翻訳されています。
その翻訳作業に加わっていただくことでもMisskeyに貢献できます。
Misskeyは[Crowdinというサービスを使用して翻訳の管理を行っています。](https://crowdin.com/project/misskey)
### 感想を投稿する
不具合報告等だけではなく、Misskeyの良い点、楽しい点といったポジティブな意見もぜひ共有してください。開発の励みになり、それは間接的ですがプロジェクトへの貢献です。
### 寄付をする
Misskeyはビジネスではなく、利用は無料であるため、収益は皆様からの寄付のみです。(インスタンスによっては広告収入を得ているような場合もありますが、それは運営者の収入であり開発者への収入にはなりません)
寄付をしていただければ、今後も開発を続けることが可能になり、プロジェクトへの貢献になります。
寄付は[Patreon](https://www.patreon.com/syuilo)で受け付けています。
## クレジット
Misskeyの開発者や、Misskeyに寄付をしてくださった方の一覧は[こちら](/about-misskey)で見ることができます。

View File

@@ -121,14 +121,22 @@ router.get('/api.json', async ctx => {
router.get('/docs.json', async ctx => {
const lang = ctx.query.lang;
const query = ctx.query.q;
if (!Object.keys(locales).includes(lang)) {
ctx.body = [];
return;
}
const paths = glob.sync(__dirname + `/../../../src/docs/${lang}/*.md`);
const docs: { path: string; title: string; }[] = [];
const dirPath = `${__dirname}/../../../src/docs/${lang}`.replace(/\\/g, '/');
const paths = glob.sync(`${dirPath}/**/*.md`);
const docs: { path: string; title: string; summary: string; }[] = [];
for (const path of paths) {
const md = fs.readFileSync(path, { encoding: 'utf8' });
if (query && query.length > 0) {
// TODO: カタカナをひらがなにして比較するなどしたい
if (!md.includes(query)) continue;
}
const parsed = markdown.parse(md, {});
if (parsed.length === 0) return;
@@ -147,9 +155,22 @@ router.get('/docs.json', async ctx => {
}
}
const firstParagrapfTokens = [];
while (buf[0].type !== 'paragraph_open') {
buf.shift();
}
buf.shift();
while (buf[0].type as string !== 'paragraph_close') {
const token = buf.shift();
if (token) {
firstParagrapfTokens.push(token);
}
}
docs.push({
path: path.split('/').pop()!.split('.')[0],
title: markdown.renderer.render(headingTokens, {}, {})
path: path.replace(`${dirPath}/`, '').split('.')[0],
title: markdown.renderer.render(headingTokens, {}, {}),
summary: markdown.renderer.render(firstParagrapfTokens, {}, {}),
});
}