feat: add specific relay as a column

This commit is contained in:
Shusui MOYATANI
2024-02-22 03:00:15 +09:00
parent 9472738f90
commit 507796e849
2 changed files with 104 additions and 20 deletions

View File

@@ -1,10 +1,11 @@
import { Component, For } from 'solid-js';
import { Component, For, Switch, Match, createSignal, type JSX } from 'solid-js';
import Bell from 'heroicons/24/outline/bell.svg';
import GlobeAlt from 'heroicons/24/outline/globe-alt.svg';
import Heart from 'heroicons/24/outline/heart.svg';
import Home from 'heroicons/24/outline/home.svg';
import MagnifyingGlass from 'heroicons/24/outline/magnifying-glass.svg';
import Server from 'heroicons/24/outline/server.svg';
import User from 'heroicons/24/outline/user.svg';
// import BookmarkIcon from 'heroicons/24/outline/bookmark.svg';
// import ChatBubbleLeftRight from 'heroicons/24/outline/chat-bubble-left-right.svg';
@@ -16,6 +17,7 @@ import {
createNotificationColumn,
createPostsColumn,
createReactionsColumn,
createRelaysColumn,
createSearchColumn,
} from '@/core/column';
import useConfig from '@/core/useConfig';
@@ -23,17 +25,78 @@ import { useRequestCommand } from '@/hooks/useCommandBus';
import { useTranslation } from '@/i18n/useTranslation';
import usePubkey from '@/nostr/usePubkey';
import ensureNonNull from '@/utils/ensureNonNull';
import { isWebSocketUrl } from '@/utils/url';
type AddColumnProps = {
onClose: () => void;
};
type AddRelayColumnProps = {
addRelaysColumn: (relayUrls: string[]) => void;
};
const AddRelaysColumn: Component<AddRelayColumnProps> = (props) => {
const i18n = useTranslation();
const { config } = useConfig();
const [relayUrl, setRelayUrl] = createSignal<string>('');
const handleSubmit: JSX.EventHandler<HTMLFormElement, Event> = (ev) => {
ev.preventDefault();
const url = relayUrl();
if (!isWebSocketUrl(url)) {
window.alert('Invalid url');
return;
}
props.addRelaysColumn([url]);
};
return (
<div class="p-8">
<form class="flex gap-1" onSubmit={handleSubmit}>
<input
class="flex-1 rounded-md border-border bg-bg placeholder:text-fg-secondary focus:border-border focus:ring-primary"
type="text"
name="url"
placeholder="wss://..."
pattern="wss?:\/\/.*"
required
onChange={(ev) => setRelayUrl(ev.currentTarget.value)}
/>
<button
class="rounded border border-primary px-4 py-1 font-bold text-primary"
type="submit"
>
{i18n.t('column.addRelayColumn.add')}
</button>
</form>
<div class="flex flex-col items-start gap-1 pt-8">
<For each={config().relayUrls}>
{(url) => (
<button
type="button"
class="text-fg-secondary hover:text-fg"
onClick={() => props.addRelaysColumn([url])}
>
{url}
</button>
)}
</For>
</div>
</div>
);
};
const AddColumn: Component<AddColumnProps> = (props) => {
const i18n = useTranslation();
const pubkey = usePubkey();
const { saveColumn } = useConfig();
const request = useRequestCommand();
const [detailComponent, setDetailComponent] = createSignal<string | undefined>(undefined);
const finish = () => {
props.onClose();
request({ command: 'moveToLastColumn' }).catch((err) => console.error(err));
@@ -58,6 +121,11 @@ const AddColumn: Component<AddColumnProps> = (props) => {
finish();
};
const addRelaysColumn = (relayUrls: string[]) => {
saveColumn(createRelaysColumn({ relayUrls }));
finish();
};
const addSearchColumn = () => {
saveColumn(createSearchColumn({ query: '' }));
finish();
@@ -81,32 +149,37 @@ const AddColumn: Component<AddColumnProps> = (props) => {
{
name: () => i18n.t('column.home'),
icon: () => <Home />,
onClick: addFollowingColumn,
onSelect: addFollowingColumn,
},
{
name: () => i18n.t('column.notification'),
icon: () => <Bell />,
onClick: addNotificationColumn,
onSelect: addNotificationColumn,
},
{
name: () => i18n.t('column.relay'),
icon: () => <Server />,
onSelect: () => setDetailComponent('AddRelaysColumn'),
},
{
name: () => i18n.t('column.japanese'),
icon: () => <GlobeAlt />,
onClick: addJapanRelaysColumn,
onSelect: addJapanRelaysColumn,
},
{
name: () => i18n.t('column.search'),
icon: () => <MagnifyingGlass />,
onClick: addSearchColumn,
onSelect: addSearchColumn,
},
{
name: () => i18n.t('column.myPosts'),
icon: () => <User />,
onClick: addMyPostsColumn,
onSelect: addMyPostsColumn,
},
{
name: () => i18n.t('column.myReactions'),
icon: () => <Heart />,
onClick: addMyReactionsColumn,
onSelect: addMyReactionsColumn,
},
// TODO channel <ChatBubbleLeftRight />
// TODO bookmark <BookmarkIcon />
@@ -114,19 +187,27 @@ const AddColumn: Component<AddColumnProps> = (props) => {
return (
<BasicModal onClose={props.onClose}>
<div class="flex flex-wrap p-4">
<For each={menu}>
{(menuItem) => (
<button
class="flex basis-1/2 flex-col items-center gap-2 py-8 hover:text-primary sm:basis-1/4"
onClick={menuItem.onClick}
>
<span class="inline-block size-8">{menuItem.icon()}</span>
{menuItem.name()}
</button>
)}
</For>
</div>
<Switch
fallback={
<div class="flex flex-wrap p-4">
<For each={menu}>
{(menuItem) => (
<button
class="flex basis-1/2 flex-col items-center gap-2 py-8 hover:text-primary sm:basis-1/4"
onClick={menuItem.onSelect}
>
<span class="inline-block size-8">{menuItem.icon()}</span>
{menuItem.name()}
</button>
)}
</For>
</div>
}
>
<Match when={detailComponent() === 'AddRelaysColumn'}>
<AddRelaysColumn addRelaysColumn={addRelaysColumn} />
</Match>
</Switch>
</BasicModal>
);
};

View File

@@ -37,6 +37,9 @@ export default {
back: '戻る',
loadLatest: '最新の投稿を読み込む',
loadOld: '古い投稿を読み込む',
addRelayColumn: {
add: '追加',
},
config: {
columnWidth: 'カラム幅',
widest: '特大',