Skip to content

Commit 6a3fbcc

Browse files
authored
Merge pull request #8 from 420bytes/fix-links
2 parents 4076579 + 6676117 commit 6a3fbcc

File tree

16 files changed

+173
-146
lines changed

16 files changed

+173
-146
lines changed

components/Header.tsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Copyright 2023-2024 the Deno authors. All rights reserved. MIT license.
2+
import Button from '@/islands/Button.tsx';
23
import { SITE_NAME } from '@/utils/constants.ts';
34
import { User } from '@/utils/db.ts';
45
import { isStripeEnabled } from '@/utils/stripe.ts';
@@ -90,18 +91,10 @@ export default function Header(props: HeaderProps) {
9091
</a>
9192
)
9293
: (
93-
<a href='/signin' class='link-styles nav-item'>
94+
<Button href='/signin'>
9495
Sign in
95-
</a>
96+
</Button>
9697
)}
97-
<div class='p-px rounded-lg bg-gradient-to-tr from-secondary to-primary'>
98-
<a
99-
href='/submit'
100-
class='text-center text-white rounded-[7px] transition duration-300 px-4 py-2 block hover:bg-white hover:text-black hover:dark:bg-gray-900 hover:dark:!text-white'
101-
>
102-
Submit
103-
</a>
104-
</div>
10598
</nav>
10699
</header>
107100
);

deno.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"lock": false,
3+
"nodeModulesDir": true,
34
"tasks": {
45
"init:stripe": "deno run --allow-read --allow-env --allow-net --env tasks/init_stripe.ts",
56
"db:dump": "deno run --allow-read --allow-env tasks/db_dump.ts",
@@ -24,7 +25,8 @@
2425
"@/": "./",
2526
"$fresh/": "https://deno.land/x/[email protected]/",
2627
"$gfm": "https://deno.land/x/[email protected]/mod.ts",
27-
"$flowbite/": "https://deno.land/x/[email protected]/",
28+
"react": "npm:@preact/compat",
29+
"react-dom": "npm:@preact/compat",
2830
"preact": "https://esm.sh/[email protected]",
2931
"preact/": "https://esm.sh/[email protected]/",
3032
"preact-render-to-string": "https://esm.sh/*[email protected]",
@@ -42,7 +44,9 @@
4244
"axios-web": "https://esm.sh/[email protected]?target=es2022",
4345
"zod": "https://esm.sh/[email protected]",
4446
"open-props": "https://esm.sh/[email protected]",
45-
"open-props/": "https://esm.sh/[email protected]/"
47+
"open-props/": "https://esm.sh/[email protected]/",
48+
"$components": "https://esm.sh/[email protected]",
49+
"$inject-css/": "https://deno.land/x/[email protected]/"
4650
},
4751
"exclude": ["cov/", "_fresh/", "**/_fresh/*"],
4852
"lint": {

fresh.config.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// Copyright 2023-2024 the Deno authors. All rights reserved. MIT license.
2-
import kvOAuthPlugin from '@/plugins/kv_oauth.ts';
3-
import sessionPlugin from '@/plugins/session.ts';
2+
import tailwindPlugin from '$fresh/plugins/tailwind.ts';
3+
import { FreshConfig } from '$fresh/src/server/types.ts';
4+
import { InjectCSSPlugin } from '$inject-css/index.ts';
45
import errorHandling from '@/plugins/error_handling.ts';
6+
import kvOAuthPlugin from '@/plugins/kv_oauth.ts';
57
import securityHeaders from '@/plugins/security_headers.ts';
8+
import sessionPlugin from '@/plugins/session.ts';
69
import welcomePlugin from '@/plugins/welcome.ts';
7-
import { FlowbitePlugin } from '$flowbite/index.ts';
8-
import { ga4Plugin } from 'https://deno.land/x/[email protected]/mod.ts';
9-
import { FreshConfig } from '$fresh/src/server/types.ts';
10-
import tailwindPlugin from '$fresh/plugins/tailwind.ts';
1110
import { kvInsightsPlugin } from 'https://deno.land/x/[email protected]/mod.ts';
11+
import { ga4Plugin } from 'https://deno.land/x/[email protected]/mod.ts';
1212

1313
export default {
1414
plugins: [
@@ -17,7 +17,7 @@ export default {
1717
kvOAuthPlugin,
1818
sessionPlugin,
1919
tailwindPlugin(),
20-
FlowbitePlugin(),
20+
InjectCSSPlugin(),
2121
kvInsightsPlugin(),
2222
errorHandling,
2323
securityHeaders,

fresh.gen.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import * as $submit from './routes/submit.tsx';
3434
import * as $terms_and_conditions_index from './routes/terms-and-conditions/index.tsx';
3535
import * as $users_login_ from './routes/users/[login].tsx';
3636
import * as $welcome from './routes/welcome.tsx';
37+
import * as $Button from './islands/Button.tsx';
3738
import * as $Chart from './islands/Chart.tsx';
3839
import * as $Iframely from './islands/Iframely.tsx';
3940
import * as $ItemsList from './islands/ItemsList.tsx';
@@ -77,6 +78,7 @@ const manifest = {
7778
'./routes/welcome.tsx': $welcome,
7879
},
7980
islands: {
81+
'./islands/Button.tsx': $Button,
8082
'./islands/Chart.tsx': $Chart,
8183
'./islands/Iframely.tsx': $Iframely,
8284
'./islands/ItemsList.tsx': $ItemsList,

islands/Button.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { IS_BROWSER } from '$fresh/runtime.ts';
2+
import { JSX } from 'preact';
3+
import { useCallback } from 'preact/hooks';
4+
5+
export function Button(props: JSX.HTMLAttributes<HTMLButtonElement>) {
6+
const ignoreProps = ['href', 'children'];
7+
const nextProps = Object.fromEntries(Object.entries(props).filter(([key]) => !ignoreProps.includes(key)));
8+
9+
const handleOnClickHref = useCallback(({ href }: { href: string }) => {
10+
return location.replace(href);
11+
}, []);
12+
13+
return (
14+
<button
15+
disabled={!IS_BROWSER || props.disabled}
16+
class='default'
17+
{...props.href && { onClick: () => handleOnClickHref({ href: props.href as string }) }}
18+
{...nextProps}
19+
>
20+
{props.children}
21+
</button>
22+
);
23+
}
24+
25+
export default Button;

islands/Iframely.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ export default function Iframely(props: IframelyProps) {
2222
encodeURIComponent(
2323
props.url,
2424
)
25-
}&api_key=${KEY}&iframe=1&omit_script=1&ssl=1&card=small`,
25+
}&api_key=${KEY}`.concat(`&iframe=1`).concat(`&omit_script=1`).concat(`&omit_css=true`).concat(`&ssl=1`).concat(
26+
`&iframe=card`,
27+
),
2628
)
2729
.then((res) => res.json())
2830
.then(

islands/ItemsList.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright 2023-2024 the Deno authors. All rights reserved. MIT license.
2-
import { Signal, useComputed, useSignal } from '@preact/signals';
3-
import { useEffect } from 'preact/hooks';
2+
import GitHubAvatarImg from '@/components/GitHubAvatarImg.tsx';
43
import { type Item } from '@/utils/db.ts';
5-
import IconInfo from 'tabler_icons_tsx/info-circle.tsx';
4+
import { timeAgo } from '@/utils/display.ts';
65
import { fetchValues } from '@/utils/http.ts';
6+
import { Signal, useComputed, useSignal } from '@preact/signals';
7+
import { useEffect } from 'preact/hooks';
78
import { decodeTime } from 'std/ulid/mod.ts';
8-
import { timeAgo } from '@/utils/display.ts';
9-
import GitHubAvatarImg from '@/components/GitHubAvatarImg.tsx';
9+
import IconInfo from 'tabler_icons_tsx/info-circle.tsx';
1010

1111
async function fetchVotedItems() {
1212
const url = '/api/me/votes';
@@ -45,7 +45,7 @@ function VoteButton(props: VoteButtonProps) {
4545
}
4646

4747
return (
48-
<button onClick={onClick} class='hover:text-primary'>
48+
<button onClick={onClick}>
4949
5050
</button>
5151
);
@@ -180,7 +180,7 @@ export default function ItemsList(props: ItemsListProps) {
180180
})
181181
: <EmptyItemsList />}
182182
{cursorSig.value !== '' && (
183-
<button onClick={loadMoreItems} class='link-styles'>
183+
<button onClick={loadMoreItems}>
184184
{isLoadingSig.value ? 'Loading...' : 'Load more'}
185185
</button>
186186
)}

islands/ListView.tsx

Lines changed: 34 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import IFramely from '@/islands/Iframely.tsx';
1+
import Button from '@/islands/Button.tsx';
2+
import Iframely from '@/islands/Iframely.tsx';
23
import type { FeedList, FeedListItem } from '@/shared/api.ts';
34
import axios from 'axios-web';
45
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
@@ -103,43 +104,30 @@ export default function ListView(props: {
103104
);
104105

105106
return (
106-
<div class='w-full'>
107-
<div class='flex flex-col pb-4 gap-4'>
108-
<div class='flex flex-row items-center gap-2'>
109-
<div
110-
class={`inline-block h-2 w-2 ${busy ? 'bg-yellow-600' : 'bg-primary'}`}
111-
style={{ borderRadius: '50%' }}
112-
>
113-
</div>
114-
<span class='text-sm opacity-50'>
115-
Share this page to collaborate with others.
116-
</span>
117-
</div>
118-
<div class='flex'>
119-
<input
120-
class='w-full px-3 py-2 mr-4 border rounded'
121-
placeholder='Paste a link to post and expand'
122-
ref={addTodoInput}
123-
/>
124-
<div class='p-px rounded-lg bg-gradient-to-tr from-secondary to-primary'>
125-
<button
126-
onClick={addTodo}
127-
disabled={adding}
128-
class='text-center text-white rounded-[7px] transition duration-300 px-4 py-2 block hover:bg-white hover:text-black hover:dark:bg-gray-900 hover:dark:!text-white'
129-
>
130-
Add
131-
</button>
132-
</div>
133-
</div>
107+
<div class='w-full p-4'>
108+
<div class='flex'>
109+
<input
110+
class='w-full px-3 py-2 mr-4 border rounded'
111+
placeholder='Paste a link to post and expand'
112+
ref={addTodoInput}
113+
/>
114+
<Button
115+
onClick={addTodo}
116+
disabled={adding}
117+
>
118+
Add
119+
</Button>
134120
</div>
135121
<div class='my-4'>
136-
{data.items.map((item) => (
137-
<ListItem
138-
key={item.id! + ':' + item.versionstamp!}
139-
item={item}
140-
save={saveTodo}
141-
/>
142-
))}
122+
<ol class='relative border-s border-gray-200 dark:border-gray-700'>
123+
{data.items.map((item) => (
124+
<ListItem
125+
key={item.id! + ':' + item.versionstamp!}
126+
item={item}
127+
save={saveTodo}
128+
/>
129+
))}
130+
</ol>
143131
</div>
144132
<div class='py-2 text-sm border-t border-gray-300 opacity-50'>
145133
<p>Initial data fetched in {props.latency}ms</p>
@@ -175,8 +163,11 @@ function ListItem({
175163
save(item, null, null);
176164
}, [item]);
177165

166+
const postCreatedTimestamp = new globalThis.Date(item.createdAt!);
167+
const timestamp = `${postCreatedTimestamp.toLocaleDateString()}${postCreatedTimestamp.toLocaleTimeString()}`;
168+
178169
return (
179-
<div class='flex items-center' {...{ 'data-item-id': item.id! }}>
170+
<li class='mb-10 ms-4' {...{ 'data-item-id': item.id! }} key={item.id!}>
180171
{editing && (
181172
<>
182173
<input
@@ -185,15 +176,13 @@ function ListItem({
185176
defaultValue={item.url}
186177
/>
187178
<button
188-
class='p-2 mr-2 rounded disabled:opacity-50'
189179
title='Save'
190180
onClick={doSave}
191181
disabled={busy}
192182
>
193183
💾
194184
</button>
195185
<button
196-
class='p-2 rounded disabled:opacity-50'
197186
title='Cancel'
198187
onClick={cancelEdit}
199188
disabled={busy}
@@ -204,23 +193,14 @@ function ListItem({
204193
)}
205194
{!editing && (
206195
<>
207-
<div class='flex flex-col w-full font-mono'>
208-
<IFramely url={String(item.url || item.text)} />
209-
<p class='text-xs leading-loose opacity-50'>
210-
{new Date(item.createdAt).toISOString()} | **updated on {new Date(item.updatedAt).toISOString()}**
211-
</p>
212-
</div>
213-
<button
214-
class='p-2 disabled:opacity-50'
215-
title='Delete'
216-
onClick={doDelete}
217-
disabled={busy}
218-
>
219-
🗑️
220-
</button>
196+
<div class='absolute w-3 h-3 bg-gray-200 rounded-full mt-1.5 -start-1.5 border border-white dark:border-gray-900 dark:bg-gray-700' />
197+
<time class='text-sm font-normal leading-none text-gray-400 dark:text-gray-500'>{timestamp}</time>
198+
<div class='mt-2' />
199+
<Iframely url={String(item.url || item.text)} />
200+
<Button onClick={doDelete} class='mt-4'>delete</Button>
221201
</>
222202
)}
223-
</div>
203+
</li>
224204
);
225205
}
226206

islands/UsersTable.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// Copyright 2023-2024 the Deno authors. All rights reserved. MIT license.
2-
import { useSignal } from '@preact/signals';
3-
import { useEffect } from 'preact/hooks';
4-
import type { User } from '@/utils/db.ts';
52
import GitHubAvatarImg from '@/components/GitHubAvatarImg.tsx';
6-
import { fetchValues } from '@/utils/http.ts';
73
import { PremiumBadge } from '@/components/PremiumBadge.tsx';
4+
import type { User } from '@/utils/db.ts';
5+
import { fetchValues } from '@/utils/http.ts';
6+
import { useSignal } from '@preact/signals';
7+
import { useEffect } from 'preact/hooks';
88

99
const TH_STYLES = 'p-4 text-left';
1010
const TD_STYLES = 'p-4';
@@ -85,7 +85,6 @@ export default function UsersTable(props: UsersTableProps) {
8585
{cursorSig.value !== '' && (
8686
<button
8787
onClick={loadMoreUsers}
88-
class='p-4 link-styles'
8988
>
9089
{isLoadingSig.value ? 'Loading...' : 'Load more'}
9190
</button>

routes/_app.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// Copyright 2023-2024 the Deno authors. All rights reserved. MIT license.
2-
import Header from '@/components/Header.tsx';
2+
import { defineApp } from '$fresh/server.ts';
33
import Footer from '@/components/Footer.tsx';
4+
import Header from '@/components/Header.tsx';
45
import type { State } from '@/plugins/session.ts';
5-
import { defineApp } from '$fresh/server.ts';
66

77
export default defineApp<State>((_, ctx) => {
88
if (ctx.url.pathname.startsWith('/kv-')) {
@@ -23,6 +23,7 @@ export default defineApp<State>((_, ctx) => {
2323
<Footer />
2424
</div>
2525
</div>
26+
<script async src='//cdn.iframe.ly/embed.js'></script>
2627
</body>
2728
</html>
2829
);

0 commit comments

Comments
 (0)