mirror of
https://github.com/andrigamerita/simpkey
synced 2025-06-05 22:09:26 +02:00
ユーザーページ
This commit is contained in:
@ -23,6 +23,15 @@ export function usersShow(host: string, userId: string): Promise<User> {
|
|||||||
return api<User>(host, 'users/show', { userId });
|
return api<User>(host, 'users/show', { userId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function usersShowByName(host: string, username: string, userHost?: string): Promise<User> {
|
||||||
|
const opts: Record<string, string> = {};
|
||||||
|
opts.username = username;
|
||||||
|
if (userHost) {
|
||||||
|
opts.host = userHost;
|
||||||
|
}
|
||||||
|
return api<User>(host, 'users/show', opts);
|
||||||
|
}
|
||||||
|
|
||||||
export function notesShow(host: string, noteId: string): Promise<Note> {
|
export function notesShow(host: string, noteId: string): Promise<Note> {
|
||||||
return api<Note>(host, 'notes/show', { noteId });
|
return api<Note>(host, 'notes/show', { noteId });
|
||||||
}
|
}
|
@ -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, notesShow } from './misskey';
|
import { signIn, api, i, notesShow, usersShowByName } from './misskey';
|
||||||
import { Note } from './models/Note';
|
import { Note } from './models/Note';
|
||||||
import { die } from './die';
|
import { die } from './die';
|
||||||
|
|
||||||
@ -21,11 +21,11 @@ for (const [ name, title ] of staticRouting) {
|
|||||||
|
|
||||||
async function timeline(ctx: Context, host: string, endpoint: string, timelineName: string, token: string) {
|
async function timeline(ctx: Context, host: string, endpoint: string, timelineName: string, token: string) {
|
||||||
const user = await i(host, token);
|
const user = await i(host, token);
|
||||||
const timeline = await api<Note[]>(host, endpoint, { i: token });
|
const notes = await api<Note[]>(host, endpoint, { i: token });
|
||||||
|
|
||||||
await ctx.render('timeline', {
|
await ctx.render('timeline', {
|
||||||
title: timelineName + ' - Simpkey',
|
title: timelineName + ' - Simpkey',
|
||||||
user, timeline, timelineName
|
user, notes, timelineName
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ router.get('/notifications', async ctx => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/renote', async ctx => {
|
router.get('/renote/:noteId', 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');
|
||||||
if (!token || !host) {
|
if (!token || !host) {
|
||||||
@ -110,20 +110,15 @@ router.get('/renote', async ctx => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.query.noteId) {
|
|
||||||
await die(ctx, 'noteId required');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const note = await notesShow(host, ctx.query.noteId);
|
const note = await notesShow(host, ctx.params.noteId);
|
||||||
await ctx.render('renote', { note });
|
await ctx.render('renote', { note });
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
await die(ctx, e.message);
|
await die(ctx, e.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/reply', async ctx => {
|
router.get('/reply/:noteId', 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');
|
||||||
if (!token || !host) {
|
if (!token || !host) {
|
||||||
@ -131,20 +126,15 @@ router.get('/reply', async ctx => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.query.noteId) {
|
|
||||||
await die(ctx, 'noteId required');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const note = await notesShow(host, ctx.query.noteId);
|
const note = await notesShow(host, ctx.params.noteId);
|
||||||
await ctx.render('reply', { note });
|
await ctx.render('reply', { note });
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
await die(ctx, e.message);
|
await die(ctx, e.message);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/react', async ctx => {
|
router.get('/react/:noteId', 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');
|
||||||
if (!token || !host) {
|
if (!token || !host) {
|
||||||
@ -152,13 +142,8 @@ router.get('/react', async ctx => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.query.noteId) {
|
|
||||||
await die(ctx, 'noteId required');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const note = await notesShow(host, ctx.query.noteId);
|
const note = await notesShow(host, ctx.params.noteId);
|
||||||
const myself = await i(host, token);
|
const myself = await i(host, token);
|
||||||
await ctx.render('react', { note, reactions: myself.clientData?.reactions });
|
await ctx.render('react', { note, reactions: myself.clientData?.reactions });
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
@ -166,6 +151,23 @@ router.get('/react', async ctx => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/@:acct', async ctx => {
|
||||||
|
const i = ctx.cookies.get('i');
|
||||||
|
const host = ctx.cookies.get('host');
|
||||||
|
if (!i || !host) {
|
||||||
|
await die(ctx, 'ログインしてください');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const acct = ctx.params.acct.split('@');
|
||||||
|
const username = acct[0];
|
||||||
|
const remoteHost = acct[1];
|
||||||
|
|
||||||
|
const user = await usersShowByName(host, username, remoteHost);
|
||||||
|
const notes = await api<Note[]>(host, 'users/notes', { i, userId: user.id });
|
||||||
|
await ctx.render('user', { user, notes });
|
||||||
|
});
|
||||||
|
|
||||||
router.post('/', async ctx => {
|
router.post('/', async ctx => {
|
||||||
const {
|
const {
|
||||||
host,
|
host,
|
||||||
|
@ -4,14 +4,24 @@ mixin avatar(user)
|
|||||||
|
|
||||||
mixin note-header(note)
|
mixin note-header(note)
|
||||||
header&attributes(attributes)
|
header&attributes(attributes)
|
||||||
span.name= getUserName(note.user)
|
a(href="/" + getAcct(note.user))
|
||||||
span.acct(style="color: gray")= getAcct(note.user)
|
span.name= getUserName(note.user)
|
||||||
|
span.acct(style="color: gray")= getAcct(note.user)
|
||||||
|
|
||||||
mixin sub-note(note)
|
mixin sub-note(note)
|
||||||
.sub-note
|
.sub-note
|
||||||
+avatar(note.user)
|
+avatar(note.user)
|
||||||
+note-header(note)
|
+note-header(note)
|
||||||
p= note.text
|
p
|
||||||
|
if note.cw
|
||||||
|
details
|
||||||
|
summary !{note.cw} (!{note.text.length}文字)
|
||||||
|
!= note.text
|
||||||
|
else
|
||||||
|
!= note.text
|
||||||
|
aside
|
||||||
|
span.visibility= getVisibility(note)
|
||||||
|
a.date(href="/notes/" + note.id)= new Date(note.createdAt).toLocaleString()
|
||||||
|
|
||||||
mixin note(note)
|
mixin note(note)
|
||||||
if note.reply
|
if note.reply
|
||||||
@ -37,19 +47,19 @@ mixin note(note)
|
|||||||
+sub-note(note.renote)
|
+sub-note(note.renote)
|
||||||
aside
|
aside
|
||||||
span.visibility= getVisibility(note)
|
span.visibility= getVisibility(note)
|
||||||
span.date= new Date(note.createdAt).toLocaleString()
|
a.date(href="/notes/" + note.id)= new Date(note.createdAt).toLocaleString()
|
||||||
.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
|
footer
|
||||||
|[
|
|[
|
||||||
a(href="/reply?noteId=" + note.id) リプライ
|
a(href="/reply/" + note.id) リプライ !{note.repliesCount}
|
||||||
|] [
|
|] [
|
||||||
a(href="/renote?noteId=" + note.id) リノート
|
a(href="/renote/" + note.id) リノート !{note.renoteCount}
|
||||||
|]
|
|]
|
||||||
if !note.myReaction
|
if !note.myReaction
|
||||||
| [
|
| [
|
||||||
a(href="/react?noteId=" + note.id) リアクション
|
a(href="/react/" + note.id) リアクション
|
||||||
| ]
|
| ]
|
||||||
else
|
else
|
||||||
form(action="action/unreact", method="post" style="display: inline")
|
form(action="action/unreact", method="post" style="display: inline")
|
||||||
@ -77,3 +87,36 @@ mixin nav()
|
|||||||
|] [
|
|] [
|
||||||
a(href="/settings") 設定
|
a(href="/settings") 設定
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
mixin user-header(user, detail = false)
|
||||||
|
+avatar(user)
|
||||||
|
.name: b=getUserName(user)
|
||||||
|
|
|
||||||
|
span(style="color: gray")= getAcct(user)
|
||||||
|
if detail
|
||||||
|
if user.description
|
||||||
|
.description= user.description
|
||||||
|
if user.birthday
|
||||||
|
.birthday 🎂 !{user.birthday}
|
||||||
|
if user.location
|
||||||
|
.birthday 📍!{user.location}
|
||||||
|
if user.sex
|
||||||
|
.sex 性別: !{user.sex}
|
||||||
|
if user.sex
|
||||||
|
.sex 性別: !{user.sex}
|
||||||
|
dl
|
||||||
|
each field in user.fields
|
||||||
|
dt= field.name
|
||||||
|
dd= field.value
|
||||||
|
|
||||||
|
.count
|
||||||
|
a.notes(href="/" + getAcct(user)) !{user.notesCount} ノート
|
||||||
|
|
|
||||||
|
a.following(href="/" + getAcct(user) + "/following") !{user.followingCount} フォロー
|
||||||
|
|
|
||||||
|
a.followers(href="/" + getAcct(user) + "/followers") !{user.followersCount} フォロワー
|
||||||
|
|
||||||
|
mixin timeline(notes)
|
||||||
|
each note in notes
|
||||||
|
hr
|
||||||
|
+note(note)
|
@ -3,7 +3,7 @@ extends _base
|
|||||||
block content
|
block content
|
||||||
h2 このノートにリアクションを押しますか?
|
h2 このノートにリアクションを押しますか?
|
||||||
+sub-note(note)
|
+sub-note(note)
|
||||||
form(action="action/react", method="post")
|
form(action="/action/react", method="post")
|
||||||
each val in reactions
|
each val in reactions
|
||||||
div: label
|
div: label
|
||||||
input(type="radio", name="reaction" value=val)
|
input(type="radio", name="reaction" value=val)
|
||||||
|
@ -3,5 +3,5 @@ extends _base
|
|||||||
block content
|
block content
|
||||||
h2 このノートをリノートしますか?
|
h2 このノートをリノートしますか?
|
||||||
+sub-note(note)
|
+sub-note(note)
|
||||||
+post-form('action/create-note', "コメント(省略可能)", "リノート")
|
+post-form('/action/create-note', "コメント(省略可能)", "リノート")
|
||||||
input(type="hidden", name="renoteId", value=note.id)
|
input(type="hidden", name="renoteId", value=note.id)
|
@ -3,5 +3,5 @@ extends _base
|
|||||||
block content
|
block content
|
||||||
h2 このノートに返信しますか?
|
h2 このノートに返信しますか?
|
||||||
+sub-note(note)
|
+sub-note(note)
|
||||||
+post-form('action/create-note', "何と返そうか?", "返信")
|
+post-form('/action/create-note', "何と返そうか?", "返信")
|
||||||
input(type="hidden", name="replyId", value=note.id)
|
input(type="hidden", name="replyId", value=note.id)
|
@ -4,12 +4,8 @@ block header
|
|||||||
+nav
|
+nav
|
||||||
|
|
||||||
block content
|
block content
|
||||||
p: b=getUserName(user)
|
+user-header(user)
|
||||||
|
|
|
||||||
span(style="color: gray")= getAcct(user)
|
|
||||||
+post-form("/action/create-note", "今なにしてる?", "ノート")
|
+post-form("/action/create-note", "今なにしてる?", "ノート")
|
||||||
hr
|
hr
|
||||||
h2= timelineName
|
h2= timelineName
|
||||||
each note in timeline
|
+timeline(notes)
|
||||||
hr
|
|
||||||
+note(note)
|
|
6
src/views/user.pug
Normal file
6
src/views/user.pug
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
extends _base
|
||||||
|
|
||||||
|
block content
|
||||||
|
+user-header(user, true)
|
||||||
|
hr
|
||||||
|
+timeline(notes)
|
Reference in New Issue
Block a user