mirror of
https://github.com/andrigamerita/simpkey
synced 2025-06-05 22:09:26 +02:00
RN, Reply, Reactなど
This commit is contained in:
@ -9,6 +9,7 @@ export interface User {
|
|||||||
carefulBot: boolean;
|
carefulBot: boolean;
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
description: string | null;
|
description: string | null;
|
||||||
|
clientData?: { reactions: string[] };
|
||||||
fields: { name: string, value: string }[];
|
fields: { name: string, value: string }[];
|
||||||
followersCount: number;
|
followersCount: number;
|
||||||
followingCount: number;
|
followingCount: number;
|
||||||
|
104
src/router.ts
104
src/router.ts
@ -1,6 +1,6 @@
|
|||||||
import { Context, DefaultState } from 'koa';
|
import { Context, DefaultState } from 'koa';
|
||||||
import Router from 'koa-router';
|
import Router from 'koa-router';
|
||||||
import { signIn, api, i } from './misskey';
|
import { signIn, api, i, notesShow } from './misskey';
|
||||||
import { Note } from './models/Note';
|
import { Note } from './models/Note';
|
||||||
import { die } from './die';
|
import { die } from './die';
|
||||||
|
|
||||||
@ -72,6 +72,7 @@ router.get('/stl', async ctx => {
|
|||||||
await timeline(ctx, host, 'notes/hybrid-timeline', 'ソーシャルタイムライン', token);
|
await timeline(ctx, host, 'notes/hybrid-timeline', 'ソーシャルタイムライン', token);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/gtl', async ctx => {
|
router.get('/gtl', async ctx => {
|
||||||
const token = ctx.cookies.get('i');
|
const token = ctx.cookies.get('i');
|
||||||
const host = ctx.cookies.get('host');
|
const host = ctx.cookies.get('host');
|
||||||
@ -88,6 +89,70 @@ router.get('/gtl', async ctx => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/renote', async ctx => {
|
||||||
|
const token = ctx.cookies.get('i');
|
||||||
|
const host = ctx.cookies.get('host');
|
||||||
|
if (!token || !host) {
|
||||||
|
await die(ctx, 'ログインしてください');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx.query.noteId) {
|
||||||
|
await die(ctx, 'noteId required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const note = await notesShow(host, ctx.query.noteId);
|
||||||
|
await ctx.render('renote', { note });
|
||||||
|
} catch(e) {
|
||||||
|
await die(ctx, e.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/reply', async ctx => {
|
||||||
|
const token = ctx.cookies.get('i');
|
||||||
|
const host = ctx.cookies.get('host');
|
||||||
|
if (!token || !host) {
|
||||||
|
await die(ctx, 'ログインしてください');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx.query.noteId) {
|
||||||
|
await die(ctx, 'noteId required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const note = await notesShow(host, ctx.query.noteId);
|
||||||
|
await ctx.render('reply', { note });
|
||||||
|
} catch(e) {
|
||||||
|
await die(ctx, e.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/react', async ctx => {
|
||||||
|
const token = ctx.cookies.get('i');
|
||||||
|
const host = ctx.cookies.get('host');
|
||||||
|
if (!token || !host) {
|
||||||
|
await die(ctx, 'ログインしてください');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx.query.noteId) {
|
||||||
|
await die(ctx, 'noteId required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const note = await notesShow(host, ctx.query.noteId);
|
||||||
|
const myself = await i(host, token);
|
||||||
|
await ctx.render('react', { note, reactions: myself.clientData?.reactions });
|
||||||
|
} catch(e) {
|
||||||
|
await die(ctx, e.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.post('/', async ctx => {
|
router.post('/', async ctx => {
|
||||||
const {
|
const {
|
||||||
host,
|
host,
|
||||||
@ -121,15 +186,36 @@ router.post('/action/:action', async ctx => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const action = ctx.params.action as string;
|
const action = ctx.params.action as string;
|
||||||
switch (action) {
|
try {
|
||||||
case 'create-note': {
|
switch (action) {
|
||||||
const { text } = ctx.request.body;
|
case 'create-note': {
|
||||||
if (!text) await die(ctx, 'テキストがありません');
|
const { text, renoteId, replyId } = ctx.request.body;
|
||||||
await api(host, 'notes/create', { text, i });
|
const opts = { i } as Record<string, string>;
|
||||||
break;
|
if (text) opts.text = text;
|
||||||
|
if (renoteId) opts.renoteId = renoteId;
|
||||||
|
if (replyId) opts.replyId = replyId;
|
||||||
|
await api(host, 'notes/create', opts);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'react': {
|
||||||
|
const { noteId, reaction, customReaction } = ctx.request.body;
|
||||||
|
if (!noteId) throw new Error('noteId required');
|
||||||
|
if (!reaction) throw new Error('絵文字が指定されていません');
|
||||||
|
await api(host, 'notes/reactions/create', { i, noteId, reaction: reaction === 'custom' ? customReaction : reaction });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'unreact': {
|
||||||
|
const { noteId } = ctx.request.body;
|
||||||
|
if (!noteId) throw new Error('noteId required');
|
||||||
|
await api(host, 'notes/reactions/delete', { i, noteId });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
await die(ctx, e.message);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
ctx.redirect('/');
|
||||||
ctx.redirect('back', '/');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/logout', ctx => {
|
router.post('/logout', ctx => {
|
||||||
|
@ -2,7 +2,7 @@ mixin avatar(user)
|
|||||||
img.avatar(src=user.avatarUrl, alt="avatar for " + user.username style="width: 64px; height: 64px; border-radius: 50%")&attributes(attributes)
|
img.avatar(src=user.avatarUrl, alt="avatar for " + user.username style="width: 64px; height: 64px; border-radius: 50%")&attributes(attributes)
|
||||||
|
|
||||||
mixin note-header(note)
|
mixin note-header(note)
|
||||||
div.header&attributes(attributes)
|
header&attributes(attributes)
|
||||||
span.name= getUserName(note.user)
|
span.name= getUserName(note.user)
|
||||||
span.acct(style="color: gray")= getAcct(note.user)
|
span.acct(style="color: gray")= getAcct(note.user)
|
||||||
|
|
||||||
@ -32,6 +32,27 @@ mixin note(note)
|
|||||||
.reactions
|
.reactions
|
||||||
each val, key in note.reactions
|
each val, key in note.reactions
|
||||||
span(class=(key === note.myReaction ? 'my reaction' : 'reaction'))=`${key} ${val}`
|
span(class=(key === note.myReaction ? 'my reaction' : 'reaction'))=`${key} ${val}`
|
||||||
|
footer
|
||||||
|
|[
|
||||||
|
a(href="/reply?noteId=" + note.id) リプライ
|
||||||
|
|] [
|
||||||
|
a(href="/renote?noteId=" + note.id) リノート
|
||||||
|
|]
|
||||||
|
if !note.myReaction
|
||||||
|
| [
|
||||||
|
a(href="/react?noteId=" + note.id) リアクション
|
||||||
|
| ]
|
||||||
|
else
|
||||||
|
form(action="action/unreact", method="post" style="display: inline")
|
||||||
|
input(type="hidden", name="noteId", value=note.id)
|
||||||
|
button(type="submit") リアクション解除
|
||||||
|
|
||||||
|
mixin post-form(url, placeholder, buttonText)
|
||||||
|
form(action=url, method="post")
|
||||||
|
textarea(name="text", placeholder=placeholder style="max-width: 100%; min-width: 100%; height: 6em; margin-bottom: 8px")
|
||||||
|
button(type="submit")= buttonText
|
||||||
|
block
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
html
|
html
|
||||||
|
16
src/views/react.pug
Normal file
16
src/views/react.pug
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
extends _base
|
||||||
|
|
||||||
|
block content
|
||||||
|
h2 このノートにリアクションを押しますか?
|
||||||
|
+note(note)
|
||||||
|
form(action="action/react", method="post")
|
||||||
|
each val in reactions
|
||||||
|
div: label
|
||||||
|
input(type="radio", name="reaction" value=val)
|
||||||
|
!= val
|
||||||
|
div: label
|
||||||
|
input(type="radio", name="reaction", value="custom")
|
||||||
|
input(type="text", name="customReaction")
|
||||||
|
input(type="hidden", name="noteId", value=note.id)
|
||||||
|
|
||||||
|
button(type="submit") リアクションを押す
|
7
src/views/renote.pug
Normal file
7
src/views/renote.pug
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
extends _base
|
||||||
|
|
||||||
|
block content
|
||||||
|
h2 このノートをリノートしますか?
|
||||||
|
+note(note)
|
||||||
|
+post-form('action/create-note', "コメント(省略可能)", "リノート")
|
||||||
|
input(type="hidden", name="renoteId", value=note.id)
|
7
src/views/reply.pug
Normal file
7
src/views/reply.pug
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
extends _base
|
||||||
|
|
||||||
|
block content
|
||||||
|
h2 このノートに返信しますか?
|
||||||
|
+note(note)
|
||||||
|
+post-form('action/create-note', "何と返そうか?", "返信")
|
||||||
|
input(type="hidden", name="replyId", value=note.id)
|
@ -5,20 +5,22 @@ block content
|
|||||||
p: b=getUserName(user)
|
p: b=getUserName(user)
|
||||||
|
|
|
|
||||||
span(style="color: gray")= getAcct(user)
|
span(style="color: gray")= getAcct(user)
|
||||||
form(action="/action/create-note", method="post")
|
+post-form("/action/create-note", "今なにしてる?", "ノート")
|
||||||
textarea(name="text", placeholder="今何してる?" style="max-width: 100%; min-width: 100%; height: 6em; margin-bottom: 8px")
|
|
||||||
button(type="submit") ノート
|
|
||||||
hr
|
hr
|
||||||
div
|
div
|
||||||
|
|[
|
||||||
a(href="/") ホーム
|
a(href="/") ホーム
|
||||||
| ・
|
|] [
|
||||||
a(href="/ltl") ローカル
|
a(href="/ltl") ローカル
|
||||||
| ・
|
|] [
|
||||||
a(href="/stl") ソーシャル
|
a(href="/stl") ソーシャル
|
||||||
| ・
|
|] [
|
||||||
a(href="/gtl") グローバル
|
a(href="/gtl") グローバル
|
||||||
| ・
|
|] [
|
||||||
|
a(href="/notifications") 通知
|
||||||
|
|] [
|
||||||
a(href="/settings") 設定
|
a(href="/settings") 設定
|
||||||
|
|]
|
||||||
h2= timelineName
|
h2= timelineName
|
||||||
each note in timeline
|
each note in timeline
|
||||||
+note(note)
|
+note(note)
|
||||||
|
Reference in New Issue
Block a user