デザイン調整

This commit is contained in:
Xeltica 2022-01-27 21:12:58 +09:00
parent 7c833c3568
commit bc0eeb5461
12 changed files with 193 additions and 160 deletions

View File

@ -15,7 +15,7 @@ html
meta(name='twitter:site' content='@Xeltica')
meta(name='twitter:creator' content='@Xeltica')
link(rel="stylesheet" href="https://koruri.chillout.chat/koruri.css")
link(rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.5.0/font/bootstrap-icons.css")
link(rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css")
style.
.loading {
display: flex;

View File

@ -59,7 +59,7 @@ const AppInner : React.VFC = () => {
</div>
) : (
<div className="container">
{$location.pathname !== '/' && <Header hasTopLink />}
{$location.pathname !== '/' && <Header hasTopLink className="xarticle mb-2" />}
<Switch>
<Route exact path="/" component={IndexPage} />
<Route exact path="/ranking" component={RankingPage} />

View File

@ -30,32 +30,34 @@ export const AccountsPage: React.VFC = () => {
<Skeleton />
</div>
) : (
<article className="fade">
<div>
<strong>{t('_accounts.switchAccount')}</strong>
</div>
<div className="menu large fluid mb-2">
{
accounts.length === accountTokens.length ? (
accounts.map(account => (
<button className="item fluid" style={{display: 'flex', flexDirection: 'row', alignItems: 'center'}} onClick={() => switchAccount(account.misshaiToken)}>
<i className="icon bi bi-chevron-right" />
<article className="card fade">
<div className="body">
<div>
<strong>{t('_accounts.switchAccount')}</strong>
</div>
<div className="menu large fluid mb-2">
{
accounts.length === accountTokens.length ? (
accounts.map(account => (
<button className="item fluid" style={{display: 'flex', flexDirection: 'row', alignItems: 'center'}} onClick={() => switchAccount(account.misshaiToken)}>
<i className="icon bi bi-chevron-right" />
@{account.username}@{account.host}
<button className="btn flat text-danger" style={{marginLeft: 'auto'}} onClick={e => {
const filteredAccounts = accounts.filter(ac => ac.id !== account.id);
dispatch(setAccounts(filteredAccounts));
e.stopPropagation();
}}>
<i className="bi bi-trash"/>
<button className="btn flat text-danger" style={{marginLeft: 'auto'}} onClick={e => {
const filteredAccounts = accounts.filter(ac => ac.id !== account.id);
dispatch(setAccounts(filteredAccounts));
e.stopPropagation();
}}>
<i className="bi bi-trash"/>
</button>
</button>
</button>
))
) : (
<div className="item">...</div>
)
}
))
) : (
<div className="item">...</div>
)
}
</div>
<LoginForm />
</div>
<LoginForm />
</article>
);
};

View File

@ -24,7 +24,7 @@ export const AnnouncementList: React.VFC = () => {
return (
<>
<h2 className="mb-0">{t('announcements')}</h2>
<h1 className="mb-0">{t('announcements')}</h1>
<div className="large menu fade">
{announcements.map(a => (
<Link className="item fluid" key={a.id} to={`/announcements/${a.id}`}>

View File

@ -0,0 +1,17 @@
.misshaiPageLayout {
display: flex;
flex-wrap: wrap;
gap: var(--margin);
> .misshaiData {
flex: 1 0 300px;
}
> .misshaiRanking {
flex: 5 0 300px;
}
> .alertModeSetting {
flex: 1 0 300px;
}
> .templateSetting {
flex: 5 0 300px;
}
}

View File

@ -10,10 +10,11 @@ import { $post, $put } from '../misc/api';
import { useGetScoreQuery, useGetSessionQuery } from '../services/session';
import { showModal } from '../store/slices/screen';
import { AnnouncementList } from './AnnouncementList';
import { Card } from './Card';
import { Ranking } from './Ranking';
import { Skeleton } from './Skeleton';
import './MisshaiPage.scss';
const variables = [
'notesCount',
'followingCount',
@ -174,7 +175,7 @@ export const MisshaiPage: React.VFC = () => {
const defaultTemplate = t('_template.default');
return session.isLoading || score.isLoading ? (
return session.isLoading || score.isLoading || !session.data || !score.data ? (
<div className="vstack">
<Skeleton width="100%" height="1rem" />
<Skeleton width="100%" height="1rem" />
@ -182,23 +183,16 @@ export const MisshaiPage: React.VFC = () => {
<Skeleton width="100%" height="160px" />
</div>
) : (
<div className="fade vstack">
{session.data && (
<section>
<p>{t('welcomeBack', {acct: `@${session.data.username}@${session.data.host}`})}</p>
<p>
<strong>
{t('_missHai.rating')}{': '}
</strong>
{session.data.rating}
</p>
</section>
)}
<AnnouncementList />
{score.data && (
<>
<section>
<h2>{t('_missHai.data')}</h2>
<div className="vstack">
<section className="card announcement">
<div className="body">
<AnnouncementList />
</div>
</section>
<div className="misshaiPageLayout">
<section className="card misshaiData">
<div className="body">
<h1>{t('_missHai.data')}</h1>
<table className="table fluid">
<thead>
<tr>
@ -225,88 +219,104 @@ export const MisshaiPage: React.VFC = () => {
</tr>
</tbody>
</table>
</section>
<section>
<h2>{t('_missHai.ranking')}</h2>
<p>
<strong>
{t('_missHai.rating')}{': '}
</strong>
{session.data.rating}
</p>
</div>
</section>
<section className="card misshaiRanking">
<div className="body">
<h1>{t('_missHai.ranking')}</h1>
<Ranking limit={limit} />
{limit && <button className="btn link" onClick={() => setLimit(undefined)}>{t('_missHai.showAll')}</button>}
</section>
<section className="vstack mt-2">
<Card bodyClassName="vstack">
<h1>{t('alertMode')}</h1>
<div>
{
alertModes.map((mode) => (
<label key={mode} className="input-check">
<input type="radio" checked={mode === draft.alertMode} onChange={() => {
updateSetting({ alertMode: mode });
}} />
<span>{t(`_alertMode.${mode}`)}</span>
</label>
))
}
</div>
{ draft.alertMode === 'notification' && (
<div className="alert bg-danger mt-2">
<i className="icon bi bi-exclamation-circle"></i>
{t('_alertMode.notificationWarning')}
</div>
)}
{ draft.alertMode === 'note' && (
<>
<h2>{t('visibility')}</h2>
<div>
{
availableVisibilities.map((visibility) => (
<label key={visibility} className="input-check">
<input type="radio" checked={visibility === draft.visibility} onChange={() => {
updateSetting({ visibility });
}} />
<span>{t(`_visibility.${visibility}`)}</span>
</label>
))
}
</div>
<label className="input-check mt-2">
<input type="checkbox" checked={draft.localOnly} onChange={(e) => {
updateSetting({ localOnly: e.target.checked });
</div>
</section>
</div>
<div className="misshaiPageLayout">
<section className="card alertModeSetting">
<div className="body">
<h1 className="mb-2">{t('alertMode')}</h1>
<div className="vstack">
{
alertModes.map((mode) => (
<label key={mode} className="input-check">
<input type="radio" checked={mode === draft.alertMode} onChange={() => {
updateSetting({ alertMode: mode });
}} />
<span>{t('localOnly')}</span>
<span>{t(`_alertMode.${mode}`)}</span>
</label>
</>
)}
</Card>
<Card bodyClassName="vstack">
<h1>{t('template')}</h1>
<p>{t('_template.description')}</p>
<div className="hstack dense">
<button className="btn" onClick={onClickInsertVariables}>
<i className="bi bi-braces" />&nbsp;
{t('_template.insertVariables')}
</button>
<button className="btn link text-info" onClick={onClickInsertVariablesHelp}>
<i className="bi bi-question-circle" />
</button>
))
}
</div>
{ draft.alertMode === 'notification' && (
<div className="alert bg-danger mt-2">
<i className="icon bi bi-exclamation-circle"></i>
{t('_alertMode.notificationWarning')}
</div>
<textarea ref={templateTextarea} className="input-field" value={draft.template ?? defaultTemplate} placeholder={defaultTemplate} style={{height: 228}} onChange={(e) => {
dispatchDraft({ template: e.target.value });
}} />
<small className="text-dimmed">{t('_template.description2')}</small>
<div className="hstack" style={{justifyContent: 'flex-end'}}>
<button className="btn danger" onClick={() => dispatchDraft({ template: null })}>{t('resetToDefault')}</button>
<button className="btn primary" onClick={() => {
updateSettingWithDialog({ template: draft.template === '' ? null : draft.template });
}}>{t('save')}</button>
</div>
</Card>
<Card bodyClassName="vstack">
<button className="btn block" onClick={onClickSendAlert} disabled={draft.alertMode === 'nothing'}>{t('sendAlert')}</button>
<p className="text-dimmed">{t(draft.alertMode === 'nothing' ? 'sendAlertDisabled' : 'sendAlertDescription')}</p>
</Card>
</section>
</>
)}
)}
{ draft.alertMode === 'note' && (
<>
<h2 className="mt-2 mb-1">{t('visibility')}</h2>
<div className="vstack">
{
availableVisibilities.map((visibility) => (
<label key={visibility} className="input-check">
<input type="radio" checked={visibility === draft.visibility} onChange={() => {
updateSetting({ visibility });
}} />
<span>{t(`_visibility.${visibility}`)}</span>
</label>
))
}
</div>
<label className="input-check mt-2">
<input type="checkbox" checked={draft.localOnly} onChange={(e) => {
updateSetting({ localOnly: e.target.checked });
}} />
<span>{t('localOnly')}</span>
</label>
</>
)}
</div>
</section>
<section className="card templateSetting">
<div className="body">
<h1>{t('template')}</h1>
<p>{t('_template.description')}</p>
<div className="hstack dense mb-2">
<button className="btn" onClick={onClickInsertVariables}>
<i className="bi bi-braces" />&nbsp;
{t('_template.insertVariables')}
</button>
<button className="btn link text-info" onClick={onClickInsertVariablesHelp}>
<i className="bi bi-question-circle" />
</button>
</div>
<textarea ref={templateTextarea} className="input-field" value={draft.template ?? defaultTemplate} placeholder={defaultTemplate} style={{height: 228}} onChange={(e) => {
dispatchDraft({ template: e.target.value });
}} />
<small className="text-dimmed">{t('_template.description2')}</small>
<div className="hstack mt-2" style={{justifyContent: 'flex-end'}}>
<button className="btn danger" onClick={() => dispatchDraft({ template: null })}>{t('resetToDefault')}</button>
<button className="btn primary" onClick={() => {
updateSettingWithDialog({ template: draft.template === '' ? null : draft.template });
}}>{t('save')}</button>
</div>
</div>
</section>
</div>
<section className="list-form mt-2">
<button className="item" onClick={onClickSendAlert} disabled={draft.alertMode === 'nothing'}>
<i className="icon bi bi-send" />
<div className="body">
<h1>{t('sendAlert')}</h1>
<p className="desc">{t(draft.alertMode === 'nothing' ? 'sendAlertDisabled' : 'sendAlertDescription')}</p>
</div>
</button>
</section>
</div>
);
};

View File

@ -1,11 +1,9 @@
import React, { ChangeEventHandler, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import ReactCrop, { Crop } from 'react-image-crop';
import 'react-image-crop/dist/ReactCrop.css';
export const NekomimiPage: React.VFC = () => {
const {t} = useTranslation();
const [blobUrl, setBlobUrl] = useState<string | null>(null);
const [image, setImage] = useState<HTMLImageElement | null>(null);
const [crop, setCrop] = useState<Partial<Crop>>({unit: '%', width: 100, aspect: 1 / 1});

View File

@ -129,7 +129,7 @@ export const SettingPage: React.VFC = () => {
</div>
</button>
<button className="item text-danger" onClick={onClickDeleteAccount}>
<i className="icon bi bi-trash-fill" />
<i className="icon bi bi-trash" />
<div className="body">
<h1>{t('deleteAccount')}</h1>
<p className="desc">{t('deleteAccountDescription')}</p>

View File

@ -54,15 +54,17 @@
"title": "プロ仕様のツールキット",
"description": "Misskey Toolsでは、Misskeyのために設計された、Misskeyをより楽しめるツールを取り揃えています。",
"misshaiAlertTitle": "ミス廃アラート",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を以下のように定期投稿できます。",
"misshaiAlertDescription": "Misskeyにのめり込んでいませんかミス廃アラートを使えば、毎日のMisskeyでの活動量を定期投稿できます。",
"misshaiRankingDescription": "ミス廃ランキングでは、Misskeyでの活動を数値化し、ランキング表示します。",
"catAdjusterDescription": "CATモードの猫耳がアイコンに合わなくてお悩みのあなたへ。かわいいアイコンを猫耳に合わせてトリミングできます。",
"nextFeaturesTitle": "今後も追加予定。",
"nextFeaturesDescription": "これだけではありません。今後もアップデートで様々な機能を追加します!"
},
"_nav": {
"misshai": "ミス廃",
"accounts": "アカウント",
"settings": "設定"
"settings": "設定",
"catAdjuster": "ねこみみ"
},
"_missHai": {
"ranking": "ミス廃ランキング",
@ -157,5 +159,8 @@
"no": "キャンセル",
"success": "アカウントを解除しました。トップ画面に戻ります。",
"failure": "アカウントを解除できませんでした。"
},
"_catAdjuster": {
"title": "ねこみみアジャスター"
}
}

View File

@ -14,8 +14,6 @@ import { useGetSessionQuery } from '../services/session';
import { AdminPage } from '../components/AdminPage';
import { $get } from '../misc/api';
import { NekomimiPage } from '../components/NekomimiPage';
import { CurrentUser } from '../components/CurrentUser';
import { Card } from '../components/Card';
export const IndexSessionPage: React.VFC = () => {
const [selectedTab, setSelectedTab] = useState<string>('misshai');
@ -59,7 +57,7 @@ export const IndexSessionPage: React.VFC = () => {
<Tab items={items} selected={selectedTab} onSelect={setSelectedTab}/>
</div>
</div>
<article className="xarticle mt-2">
<article className="xarticle mt-4">
{component}
</article>
</>

View File

@ -1,4 +1,4 @@
import React, { useMemo } from 'react';
import React from 'react';
import { Link } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
@ -8,49 +8,42 @@ import { AnnouncementList } from '../components/AnnouncementList';
export const IndexWelcomePage: React.VFC = () => {
const {t} = useTranslation();
const example = useMemo(() => (
t('_template.default')
.replace('{notesCount}', '32000')
.replace('{notesDelta}', '+190')
.replace('{followingCount}', '510')
.replace('{followingDelta}', '+3')
.replace('{followersCount}', '1020')
.replace('{followersDelta}', '-1')
.replace('{url}', 'https://misskey.tools')
), []);
return (
<>
<Header>
<Header className="xarticle mb-4">
<article className="mt-4">
<p>{t('description1')}</p>
<p>{t('description2')}</p>
</article>
<LoginForm />
</Header>
<article className="xarticle">
<AnnouncementList />
<article className="xarticle card">
<div className="body">
<AnnouncementList />
</div>
</article>
<hr />
<article className="xarticle vstack pa-2">
<header>
<h2>{t('_welcome.title')}</h2>
<p>{t('_welcome.description')}</p>
</header>
<article>
<h3>{t('_welcome.misshaiAlertTitle')}</h3>
<p>{t('_welcome.misshaiAlertDescription')}</p>
<div className="card ma-2 shadow-2" style={{maxWidth: 360}}>
<div className="body">
<pre>{example}</pre>
</div>
<div className="row">
<article className="col-4 col-12-sm">
<h3><i className="bi bi-megaphone-fill"/> {t('_welcome.misshaiAlertTitle')}</h3>
<p>{t('_welcome.misshaiAlertDescription')}</p>
</article>
<article className="col-4 col-12-sm">
<h3><i className="bi bi-bar-chart-fill"/> {t('_missHai.ranking')}</h3>
<p>{t('_welcome.misshaiRankingDescription')}</p>
<Link to="/ranking">{t('_missHai.showRanking')}</Link>
</article>
<div className="col-4 col-12-sm">
<h3><i className="bi bi-crop"/> {t('_catAdjuster.title')}</h3>
<p>{t('_welcome.catAdjusterDescription')}</p>
</div>
</article>
<article>
<h3 className="mb-1">{t('_missHai.ranking')}</h3>
<p>{t('_welcome.misshaiRankingDescription')}</p>
<Link to="/ranking">{t('_missHai.showRanking')}</Link>
</article>
<article>
</div>
<article className="mt-5">
<h3>{t('_welcome.nextFeaturesTitle')}</h3>
<p>{t('_welcome.nextFeaturesDescription')}</p>
</article>

View File

@ -1,12 +1,22 @@
body {
--primary: rgb(134, 179, 0);
--max-width: 1024px;
font-family: "Koruri", sans-serif;
font-feature-settings: "pkna";
}
hr {
height: 4px;
background: var(--dimmed);
border: none;
margin: 64px auto;
width: 50%;
max-width: 400px;
}
.xarticle {
margin: auto;
max-width: 1024px;
max-width: var(--max-width);
}
.fade {