mirror of
https://github.com/luminous-devs/lume.git
synced 2024-09-29 16:30:55 +00:00
feat: update default column list
This commit is contained in:
parent
dae4b1d52b
commit
e93aedb703
BIN
apps/desktop/public/columns/antenas.jpg
Normal file
BIN
apps/desktop/public/columns/antenas.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 112 KiB |
BIN
apps/desktop/public/columns/antenas@2x.jpg
Normal file
BIN
apps/desktop/public/columns/antenas@2x.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 428 KiB |
BIN
apps/desktop/public/columns/group.jpg
Normal file
BIN
apps/desktop/public/columns/group.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
BIN
apps/desktop/public/columns/group@2x.jpg
Normal file
BIN
apps/desktop/public/columns/group@2x.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 416 KiB |
BIN
apps/desktop/public/columns/topic.jpg
Normal file
BIN
apps/desktop/public/columns/topic.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 103 KiB |
BIN
apps/desktop/public/columns/topic@2x.jpg
Normal file
BIN
apps/desktop/public/columns/topic@2x.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 381 KiB |
@ -1,7 +1,4 @@
|
||||
/* Vidstack */
|
||||
@import '@vidstack/react/player/styles/default/theme.css';
|
||||
@import '@vidstack/react/player/styles/default/layouts/video.css';
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
@ -82,6 +82,7 @@ export function HomeScreen() {
|
||||
}}
|
||||
>
|
||||
{columns.map((column) => renderItem(column))}
|
||||
<div className="w-[420px]" />
|
||||
</VList>
|
||||
<div className="absolute bottom-3 right-3">
|
||||
<div className="flex items-center gap-1 p-1 bg-black/50 dark:bg-white/30 backdrop-blur-xl rounded-xl">
|
||||
|
@ -42,7 +42,7 @@ export function ColumnProvider({ children }: { children: ReactNode }) {
|
||||
column.title,
|
||||
column.content,
|
||||
);
|
||||
if (result) setColumns((prev) => [...prev, column]);
|
||||
if (result) setColumns((prev) => [...prev, result]);
|
||||
}, []);
|
||||
|
||||
const removeColumn = useCallback(async (id: number) => {
|
||||
|
@ -11,7 +11,7 @@ export function LinkPreview({ url }: { url: string }) {
|
||||
|
||||
if (status === "pending") {
|
||||
return (
|
||||
<div className="flex flex-col w-full my-1 rounded-lg bg-neutral-100 dark:bg-neutral-900">
|
||||
<div className="flex flex-col w-full my-1 rounded-lg overflow-hidden bg-neutral-100 dark:bg-neutral-900">
|
||||
<div className="w-full h-48 animate-pulse bg-neutral-300 dark:bg-neutral-700" />
|
||||
<div className="flex flex-col gap-2 px-3 py-3">
|
||||
<div className="w-2/3 h-3 rounded animate-pulse bg-neutral-300 dark:bg-neutral-700" />
|
||||
|
@ -46,21 +46,17 @@ export function AntenasForm({ id }: { id: number }) {
|
||||
</div>
|
||||
<div className="flex flex-col h-full gap-5 px-3 pt-2 overflow-y-auto">
|
||||
<div className="flex flex-col gap-1">
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="select-none text-neutral-950 data-[disabled]:opacity-50 font-medium mb-1 dark:text-white"
|
||||
>
|
||||
<label htmlFor="name" className="font-medium">
|
||||
Name
|
||||
</label>
|
||||
<span className="relative block w-full before:absolute before:inset-px before:rounded-[calc(theme(borderRadius.lg)-1px)] before:bg-white before:shadow dark:before:hidden after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-inset after:ring-transparent sm:after:focus-within:ring-2 sm:after:focus-within:ring-blue-500 has-[[data-disabled]]:opacity-50 before:has-[[data-disabled]]:bg-neutral-950/5 before:has-[[data-disabled]]:shadow-none before:has-[[data-invalid]]:shadow-red-500/10">
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
placeholder="Nostrichs..."
|
||||
className="relative block w-full appearance-none rounded-lg px-[calc(theme(spacing[3.5])-1px)] py-[calc(theme(spacing[2.5])-1px)] sm:px-[calc(theme(spacing[3])-1px)] sm:py-[calc(theme(spacing[1.5])-1px)] focus:ring-0 text-base/6 text-neutral-950 placeholder:text-neutral-500 sm:text-sm/6 dark:text-white border border-neutral-950/10 data-[hover]:border-neutral-950/20 dark:border-white/10 dark:data-[hover]:border-white/20 bg-transparent dark:bg-white/5 focus:outline-none data-[invalid]:border-red-500 data-[invalid]:data-[hover]:border-red-500 data-[invalid]:dark:border-red-500 data-[invalid]:data-[hover]:dark:border-red-500 data-[disabled]:border-neutral-950/20 dark:data-[hover]:data-[disabled]:border-white/15 data-[disabled]:dark:border-white/15 data-[disabled]:dark:bg-white/[2.5%]"
|
||||
className="px-2 border border-neutral-100 dark:border-neutral-900 bg-neutral-50 rounded-lg h-10 dark:bg-neutral-950 placeholder:text-neutral-600 focus:border-blue-500 focus:shadow-none focus:ring-0"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label
|
||||
@ -69,17 +65,15 @@ export function AntenasForm({ id }: { id: number }) {
|
||||
>
|
||||
Source
|
||||
</label>
|
||||
<span className="relative block w-full before:absolute before:inset-px before:rounded-[calc(theme(borderRadius.lg)-1px)] before:bg-white before:shadow dark:before:hidden after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-inset after:ring-transparent sm:after:focus-within:ring-2 sm:after:focus-within:ring-blue-500 has-[[data-disabled]]:opacity-50 before:has-[[data-disabled]]:bg-neutral-950/5 before:has-[[data-disabled]]:shadow-none before:has-[[data-invalid]]:shadow-red-500/10">
|
||||
<select
|
||||
name="source"
|
||||
value={source}
|
||||
onChange={(e) => setSource(e.target.value)}
|
||||
className="relative block w-full appearance-none rounded-lg px-[calc(theme(spacing[3.5])-1px)] py-[calc(theme(spacing[2.5])-1px)] sm:px-[calc(theme(spacing[3])-1px)] sm:py-[calc(theme(spacing[1.5])-1px)] focus:ring-0 text-base/6 text-neutral-950 placeholder:text-neutral-500 sm:text-sm/6 dark:text-white border border-neutral-950/10 data-[hover]:border-neutral-950/20 dark:border-white/10 dark:data-[hover]:border-white/20 bg-transparent dark:bg-white/5 focus:outline-none data-[invalid]:border-red-500 data-[invalid]:data-[hover]:border-red-500 data-[invalid]:dark:border-red-500 data-[invalid]:data-[hover]:dark:border-red-500 data-[disabled]:border-neutral-950/20 dark:data-[hover]:data-[disabled]:border-white/15 data-[disabled]:dark:border-white/15 data-[disabled]:dark:bg-white/[2.5%]"
|
||||
className="px-2 w-full border border-neutral-100 dark:border-neutral-900 bg-neutral-50 rounded-lg dark:bg-neutral-950 placeholder:text-neutral-600 focus:border-blue-500 focus:shadow-none focus:ring-0"
|
||||
>
|
||||
<option value="contacts">Contacts</option>
|
||||
<option value="global">Global</option>
|
||||
</select>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label
|
||||
@ -89,7 +83,6 @@ export function AntenasForm({ id }: { id: number }) {
|
||||
Hashtags to listen to
|
||||
</label>
|
||||
<div className="flex items-center justify-between gap-2 mb-1">
|
||||
<span className="relative block flex-1 before:absolute before:inset-px before:rounded-[calc(theme(borderRadius.lg)-1px)] before:bg-white before:shadow dark:before:hidden after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-inset after:ring-transparent sm:after:focus-within:ring-2 sm:after:focus-within:ring-blue-500 has-[[data-disabled]]:opacity-50 before:has-[[data-disabled]]:bg-neutral-950/5 before:has-[[data-disabled]]:shadow-none before:has-[[data-invalid]]:shadow-red-500/10">
|
||||
<input
|
||||
name="name"
|
||||
value={hashtag}
|
||||
@ -98,9 +91,8 @@ export function AntenasForm({ id }: { id: number }) {
|
||||
if (event.key === "Enter") addHashtag();
|
||||
}}
|
||||
placeholder="#nostr..."
|
||||
className="relative block w-full appearance-none rounded-lg px-[calc(theme(spacing[3.5])-1px)] py-[calc(theme(spacing[2.5])-1px)] sm:px-[calc(theme(spacing[3])-1px)] sm:py-[calc(theme(spacing[1.5])-1px)] focus:ring-0 text-base/6 text-neutral-950 placeholder:text-neutral-500 sm:text-sm/6 dark:text-white border border-neutral-950/10 data-[hover]:border-neutral-950/20 dark:border-white/10 dark:data-[hover]:border-white/20 bg-transparent dark:bg-white/5 focus:outline-none data-[invalid]:border-red-500 data-[invalid]:data-[hover]:border-red-500 data-[invalid]:dark:border-red-500 data-[invalid]:data-[hover]:dark:border-red-500 data-[disabled]:border-neutral-950/20 dark:data-[hover]:data-[disabled]:border-white/15 data-[disabled]:dark:border-white/15 data-[disabled]:dark:bg-white/[2.5%]"
|
||||
className="px-2 w-full border border-neutral-100 dark:border-neutral-900 bg-neutral-50 rounded-lg h-10 dark:bg-neutral-950 placeholder:text-neutral-600 focus:border-blue-500 focus:shadow-none focus:ring-0"
|
||||
/>
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => addHashtag()}
|
||||
@ -127,7 +119,7 @@ export function AntenasForm({ id }: { id: number }) {
|
||||
type="button"
|
||||
onClick={submit}
|
||||
disabled={hashtags.length < 1}
|
||||
className="inline-flex items-center justify-center h-10 px-4 font-semibold text-white transform bg-blue-500 rounded-lg active:translate-y-1 hover:bg-blue-600 focus:outline-none disabled:opacity-50"
|
||||
className="w-full inline-flex items-center justify-center h-10 px-4 font-semibold text-white transform bg-blue-500 rounded-lg active:translate-y-1 hover:bg-blue-600 focus:outline-none disabled:opacity-50"
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { Column } from "@lume/ark";
|
||||
import { Column, useColumnContext } from "@lume/ark";
|
||||
import { ColumnIcon } from "@lume/icons";
|
||||
import { IColumn } from "@lume/types";
|
||||
import { TOPICS } from "@lume/utils";
|
||||
import { COL_TYPES } from "@lume/utils";
|
||||
|
||||
export function Default({ column }: { column: IColumn }) {
|
||||
const { addColumn } = useColumnContext();
|
||||
|
||||
return (
|
||||
<Column.Root>
|
||||
<Column.Header
|
||||
@ -11,32 +13,86 @@ export function Default({ column }: { column: IColumn }) {
|
||||
title="Add columns"
|
||||
icon={<ColumnIcon className="size-4" />}
|
||||
/>
|
||||
<div className="h-full px-3 mt-3 overflow-y-auto scrollbar-none">
|
||||
<div className="flex flex-col gap-5">
|
||||
<div>
|
||||
<h1 className="text-lg font-semibold leading-tight">Topics</h1>
|
||||
<p className="text-neutral-600 dark:text-neutral-400">
|
||||
Discover content based on your interests.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{TOPICS.sort((a, b) => a.title.localeCompare(b.title)).map(
|
||||
(topic, index) => (
|
||||
<div
|
||||
key={topic + index.toString()}
|
||||
className="flex flex-col w-full px-3 rounded-lg bg-neutral-100"
|
||||
>
|
||||
<div className="rounded-md h-9 w-9 shrink-0">
|
||||
<div className="h-full px-3 mt-3 flex flex-col gap-3 overflow-y-auto scrollbar-none">
|
||||
<div className="flex flex-col rounded-xl overflow-hidden">
|
||||
<div className="h-[100px] w-full">
|
||||
<img
|
||||
src={`/${topic.title.toLowerCase()}.jpg`}
|
||||
alt={topic.title}
|
||||
className="rounded-md h-9 w-9"
|
||||
src="/columns/topic.jpg"
|
||||
srcSet="/columns/topic@2x.jpg 2x"
|
||||
alt="topic"
|
||||
className="w-full h-auto object-cover"
|
||||
/>
|
||||
</div>
|
||||
<p className="font-medium">{topic.title}</p>
|
||||
<div className="h-16 shrink-0 px-3 flex items-center justify-between bg-neutral-50 dark:bg-neutral-950">
|
||||
<div>
|
||||
<h1 className="font-semibold">Topic</h1>
|
||||
<p className="max-w-[18rem] truncate text-sm text-neutral-500 dark:text-neutral-600">
|
||||
Explore all content based on your interest.
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
addColumn({ kind: COL_TYPES.topic, title: "", content: "" });
|
||||
}}
|
||||
className="shrink-0 w-16 h-8 rounded-lg text-sm font-semibold bg-neutral-100 dark:bg-neutral-900 text-blue-500 hover:bg-neutral-200 dark:hover:bg-neutral-800 inline-flex items-center justify-center"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col rounded-xl overflow-hidden">
|
||||
<div className="h-[100px] w-full">
|
||||
<img
|
||||
src="/columns/group.jpg"
|
||||
srcSet="/columns/group@2x.jpg 2x"
|
||||
alt="group"
|
||||
className="w-full h-auto object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div className="h-16 shrink-0 px-3 flex items-center justify-between bg-neutral-50 dark:bg-neutral-950">
|
||||
<div>
|
||||
<h1 className="font-semibold">Group Feeds</h1>
|
||||
<p className="max-w-[18rem] truncate text-sm text-neutral-500 dark:text-neutral-600">
|
||||
Collective of people you're interested in.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
addColumn({ kind: COL_TYPES.group, title: "", content: "" });
|
||||
}}
|
||||
className="shrink-0 w-16 h-8 rounded-lg text-sm font-semibold bg-neutral-100 dark:bg-neutral-900 text-blue-500 hover:bg-neutral-200 dark:hover:bg-neutral-800 inline-flex items-center justify-center"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col rounded-xl overflow-hidden">
|
||||
<div className="h-[100px] w-full">
|
||||
<img
|
||||
src="/columns/antenas.jpg"
|
||||
srcSet="/columns/antenas@2x.jpg 2x"
|
||||
alt="antenas"
|
||||
className="w-full h-auto object-cover"
|
||||
/>
|
||||
</div>
|
||||
<div className="h-16 shrink-0 px-3 flex items-center justify-between bg-neutral-50 dark:bg-neutral-950">
|
||||
<div>
|
||||
<h1 className="font-semibold">Antenas</h1>
|
||||
<p className="max-w-[18rem] truncate text-sm text-neutral-500 dark:text-neutral-600">
|
||||
Keep track to specific content.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
addColumn({ kind: COL_TYPES.antenas, title: "", content: "" });
|
||||
}}
|
||||
className="shrink-0 w-16 h-8 rounded-lg text-sm font-semibold bg-neutral-100 dark:bg-neutral-900 text-blue-500 hover:bg-neutral-200 dark:hover:bg-neutral-800 inline-flex items-center justify-center"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,7 +7,7 @@ export function GroupForm({ id }: { id: number }) {
|
||||
const ark = useArk();
|
||||
const { updateColumn, removeColumn } = useColumnContext();
|
||||
|
||||
const [title, setTitle] = useState<string>(`Group-${id}`);
|
||||
const [title, setTitle] = useState<string>("Just a new group");
|
||||
const [users, setUsers] = useState<Array<string>>([]);
|
||||
|
||||
// toggle follow state
|
||||
@ -36,7 +36,7 @@ export function GroupForm({ id }: { id: number }) {
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex flex-col gap-5 px-3 pt-2 overflow-y-auto">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="font-medium text-neutral-700 dark:text-neutral-300"
|
||||
@ -48,7 +48,7 @@ export function GroupForm({ id }: { id: number }) {
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
placeholder="Nostrichs..."
|
||||
className="px-3 rounded-lg border-neutral-200 dark:border-neutral-900 h-11 placeholder:text-neutral-500 focus:border-blue-500 focus:ring focus:ring-blue-200 dark:placeholder:text-neutral-400 dark:focus:ring-blue-800"
|
||||
className="px-2 border border-neutral-100 dark:border-neutral-900 bg-neutral-50 rounded-lg h-10 dark:bg-neutral-950 placeholder:text-neutral-600 focus:border-blue-500 focus:shadow-none focus:ring-0"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
@ -64,7 +64,7 @@ export function GroupForm({ id }: { id: number }) {
|
||||
key={item}
|
||||
type="button"
|
||||
onClick={() => toggleUser(item)}
|
||||
className="inline-flex items-center justify-between px-3 py-2 rounded-lg bg-neutral-50 dark:bg-neutral-950 hover:bg-neutral-100 dark:hover:bg-neutral-900"
|
||||
className="inline-flex items-center justify-between px-3 py-2 rounded-xl bg-neutral-50 dark:bg-neutral-950 hover:bg-neutral-100 dark:hover:bg-neutral-900"
|
||||
>
|
||||
<User pubkey={item} variant="simple" />
|
||||
{users.includes(item) ? (
|
||||
|
@ -341,13 +341,12 @@ export class LumeStorage {
|
||||
|
||||
if (insert) {
|
||||
const columns: Array<IColumn> = await this.#db.select(
|
||||
"SELECT * FROM columns ORDER BY id DESC LIMIT 1;",
|
||||
"SELECT * FROM columns WHERE id = $1 ORDER BY id DESC LIMIT 1;",
|
||||
[insert.lastInsertId],
|
||||
);
|
||||
if (columns.length < 1) console.error("get created widget failed");
|
||||
if (!columns.length) console.error("get created widget failed");
|
||||
return columns[0];
|
||||
}
|
||||
|
||||
console.error("create widget failed");
|
||||
}
|
||||
|
||||
public async updateColumn(id: number, title: string, content: string) {
|
||||
|
Loading…
Reference in New Issue
Block a user