Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 41 additions & 4 deletions src/components/ColumnItem.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,48 @@
import { type Component, type JSX } from 'solid-js';
import { createEffect, type Component, type JSX } from 'solid-js';

import useCursor, {
useColumnCursor,
useTimelineCursor,
ItemCursorContext,
} from '@/hooks/useCursor';

type ColumnItemProps = {
itemId: string;
children: JSX.Element;
};

const ColumnItem: Component<ColumnItemProps> = (props) => (
<div class="block shrink-0 overflow-hidden border-b border-border p-1">{props.children}</div>
);
const ColumnItem: Component<ColumnItemProps> = (props) => {
let containerRef: HTMLDivElement | undefined;

const { cursor, setCursor } = useCursor();
const { columnCursor } = useColumnCursor();
const { timelineCursor } = useTimelineCursor();

const selected = () =>
cursor().columnId === columnCursor.columnId &&
cursor().timelineId === timelineCursor.timelineId &&
cursor().itemId === props.itemId;

createEffect(() => {
if (selected()) {
containerRef?.scrollIntoView(false);
}
});

return (
<ItemCursorContext.Provider value={{ itemId: props.itemId }}>
<div
ref={containerRef}
class="block shrink-0 overflow-hidden border border-border p-1"
classList={{
'border-border': !selected(),
'border-primary': selected(),
}}
>
{props.children}
</div>
</ItemCursorContext.Provider>
);
};

export default ColumnItem;
7 changes: 2 additions & 5 deletions src/components/column/BookmarkColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import { useTranslation } from '@/i18n/useTranslation';
import useParameterizedReplaceableEvent from '@/nostr/useParameterizedReplaceableEvent';

type BookmarkColumnDisplayProps = {
columnIndex: number;
lastColumn: boolean;
column: BookmarkColumnType;
};

Expand All @@ -31,17 +29,16 @@ const BookmarkColumn: Component<BookmarkColumnDisplayProps> = (props) => {

return (
<Column
columnId={props.column.id}
header={
<BasicColumnHeader
name={props.column.name ?? i18n.t('column.bookmark')}
icon={<BookmarkIcon />}
settings={() => <ColumnSettings column={props.column} columnIndex={props.columnIndex} />}
settings={() => <ColumnSettings column={props.column} />}
onClose={() => removeColumn(props.column.id)}
/>
}
width={props.column.width}
columnIndex={props.columnIndex}
lastColumn={props.lastColumn}
>
<Show when={event()} keyed>
{(ev) => <Bookmark event={ev} />}
Expand Down
1 change: 1 addition & 0 deletions src/components/column/ChannelColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const ChannelColumn: Component<ChannelColumnProps> = (props) => {

return (
<Column
columnId={props.column.id}
header={
<BasicColumnHeader
name={props.column.name ?? i18n.t('column.channel')}
Expand Down
104 changes: 58 additions & 46 deletions src/components/column/Column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import ArrowLeft from 'heroicons/24/outline/arrow-left.svg';

import TimelineContentDisplay from '@/components/timeline/TimelineContentDisplay';
import { TimelineContext, useTimelineState } from '@/components/timeline/TimelineContext';
import useConfig from '@/core/useConfig';
import { useHandleCommand } from '@/hooks/useCommandBus';
import { ColumnCursorContext } from '@/hooks/useCursor';
import { useTranslation } from '@/i18n/useTranslation';

export type ColumnProps = {
columnId: string;
timelineRef?: (el: HTMLDivElement) => void;
columnIndex: number;
lastColumn: boolean;
width: 'widest' | 'wide' | 'medium' | 'narrow' | null | undefined;
header: JSX.Element;
children: JSX.Element;
Expand All @@ -20,14 +21,19 @@ const Column: Component<ColumnProps> = (props) => {
let columnDivRef: HTMLDivElement | undefined;

const timelineState = useTimelineState();
const { config } = useConfig();
const i18n = useTranslation();

const width = () => props.width ?? 'medium';

useHandleCommand(() => ({
commandType: 'moveToColumn',
handler: (command) => {
if (command.command === 'moveToColumn' && command.columnIndex === props.columnIndex) {
if (
command.columnIndex >= 0 &&
command.columnIndex < config().columns.length &&
config().columns[command.columnIndex].id === props.columnId
) {
columnDivRef?.scrollIntoView({ behavior: 'smooth', inline: 'center' });
}
},
Expand All @@ -36,57 +42,63 @@ const Column: Component<ColumnProps> = (props) => {
useHandleCommand(() => ({
commandType: 'moveToLastColumn',
handler: () => {
if (props.lastColumn) {
const lastColumn = config().columns[config().columns.length - 1];
if (lastColumn.id === props.columnId) {
columnDivRef?.scrollIntoView({ behavior: 'smooth' });
}
},
}));

return (
<TimelineContext.Provider value={timelineState}>
<div
ref={columnDivRef}
class="flex w-[80vw] shrink-0 snap-center snap-always flex-col border-r border-border sm:snap-align-none"
classList={{
'sm:w-[500px]': width() === 'widest',
'sm:w-[360px]': width() === 'wide',
'sm:w-[320px]': width() === 'medium',
'sm:w-[280px]': width() === 'narrow',
}}
>
<Show
when={timelineState.timelineState.content}
keyed
fallback={
<>
<div class="shrink-0 border-b border-border">{props.header}</div>
<div ref={props.timelineRef} class="scrollbar flex flex-col overflow-y-scroll pb-16">
{props.children}
</div>
</>
}
<ColumnCursorContext.Provider value={{ columnId: props.columnId }}>
<TimelineContext.Provider value={timelineState}>
<div
ref={columnDivRef}
class="flex w-[80vw] shrink-0 snap-center snap-always flex-col border-r border-border sm:snap-align-none"
classList={{
'sm:w-[500px]': width() === 'widest',
'sm:w-[360px]': width() === 'wide',
'sm:w-[320px]': width() === 'medium',
'sm:w-[280px]': width() === 'narrow',
}}
>
{(timeline) => (
<>
<div class="flex shrink-0 items-center border-b border-border px-2">
<button
class="flex w-full items-center gap-1"
onClick={() => timelineState?.clearTimeline()}
<Show
when={timelineState.timelineState.content}
keyed
fallback={
<>
<div class="shrink-0 border-b border-border">{props.header}</div>
<div
ref={props.timelineRef}
class="scrollbar flex flex-col overflow-y-scroll pb-16"
>
<div class="inline-block size-4">
<ArrowLeft />
</div>
<div>{i18n.t('column.back')}</div>
</button>
</div>
<div class="scrollbar flex max-h-full flex-col overflow-y-scroll scroll-smooth pb-16">
<TimelineContentDisplay timelineContent={timeline} />
</div>
</>
)}
</Show>
</div>
</TimelineContext.Provider>
{props.children}
</div>
</>
}
>
{(timeline) => (
<>
<div class="flex shrink-0 items-center border-b border-border px-2">
<button
class="flex w-full items-center gap-1"
onClick={() => timelineState?.clearTimeline()}
>
<div class="inline-block size-4">
<ArrowLeft />
</div>
<div>{i18n.t('column.back')}</div>
</button>
</div>
<div class="scrollbar flex max-h-full flex-col overflow-y-scroll scroll-smooth pb-16">
<TimelineContentDisplay timelineContent={timeline} />
</div>
</>
)}
</Show>
</div>
</TimelineContext.Provider>
</ColumnCursorContext.Provider>
);
};

Expand Down
23 changes: 7 additions & 16 deletions src/components/column/ColumnSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ import Trash from 'heroicons/24/outline/trash.svg';

import { ColumnType } from '@/core/column';
import useConfig from '@/core/useConfig';
import { useRequestCommand } from '@/hooks/useCommandBus';
import useCursor from '@/hooks/useCursor';
import { useTranslation } from '@/i18n/useTranslation';

type ColumnSettingsProps = {
column: ColumnType;
columnIndex: number;
};

type ColumnSettingsSectionProps = {
Expand All @@ -29,15 +28,15 @@ const ColumnSettingsSection: Component<ColumnSettingsSectionProps> = (props) =>
const ColumnSettings: Component<ColumnSettingsProps> = (props) => {
const i18n = useTranslation();
const { saveColumn, removeColumn, moveColumn } = useConfig();
const request = useRequestCommand();
const { setCursor } = useCursor();

const setColumnWidth = (width: ColumnType['width']) => {
saveColumn({ ...props.column, width });
};

const move = (index: number) => {
moveColumn(props.column.id, index);
request({ command: 'moveToColumn', columnIndex: index }).catch((err) => console.error(err));
const move = (diff: number) => {
moveColumn(props.column.id, diff);
setCursor({ columnId: props.column.id });
};

return (
Expand All @@ -63,20 +62,12 @@ const ColumnSettings: Component<ColumnSettingsProps> = (props) => {
</div>
</ColumnSettingsSection>
<div class="flex h-10 items-center gap-2">
<button
class="py-4 pl-2"
title={i18n.t('column.config.moveLeft')}
onClick={() => move(props.columnIndex - 1)}
>
<button class="py-4 pl-2" title={i18n.t('column.config.moveLeft')} onClick={() => move(-1)}>
<span class="inline-block size-4">
<ChevronLeft />
</span>
</button>
<button
class="py-4 pr-2"
title={i18n.t('column.config.moveRight')}
onClick={() => move(props.columnIndex + 1)}
>
<button class="py-4 pr-2" title={i18n.t('column.config.moveRight')} onClick={() => move(1)}>
<span class="inline-block size-4">
<ChevronRight />
</span>
Expand Down
Loading