+11
-34
README.md
+11
-34
README.md
···
1
-
# sv
1
+
## nucleus
2
2
3
-
Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
3
+
a WIP replies timeline only (eg. it only shows replies to your posts and your own posts) appview-less (it does not use the bluesky appview, but rather uses [microcosm](https://www.microcosm.blue/) services) bluesky client. it is implemented in SvelteKit and uses [atcute](https://tangled.org/@mary.my.id/atcute).
4
4
5
-
## Creating a project
5
+

6
6
7
-
If you're seeing this, you've probably already done this step. Congrats!
7
+
### todos
8
8
9
-
```sh
10
-
# create a new project in the current directory
11
-
npx sv create
12
-
13
-
# create a new project in my-app
14
-
npx sv create my-app
15
-
```
16
-
17
-
## Developing
18
-
19
-
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
20
-
21
-
```sh
22
-
npm run dev
23
-
24
-
# or start the server and open the app in a new browser tab
25
-
npm run dev -- --open
26
-
```
27
-
28
-
## Building
29
-
30
-
To create a production version of your app:
31
-
32
-
```sh
33
-
npm run build
34
-
```
35
-
36
-
You can preview the production build with `npm run preview`.
37
-
38
-
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
9
+
- [ ] properly implement auth (current state is just for deving) (we want oauth only)
10
+
- [ ] implement popouts for showing full chains instead of expanding in the timeline
11
+
- [ ] implement moderation (mutes, muted words etc., use blocks from `app.bsky.graph.block`)
12
+
- [ ] profile view popout
13
+
- [ ] consider showing posts that mention / quote the user..
14
+
- [ ] notifications when replied to (and mentioned and quoted?)
15
+
- [ ] basic filtering settings for the timeline (dont show self posts and if we implement mentioned / quoted add toggles for those as well)
resources/screenshot.png
resources/screenshot.png
This is a binary file and will not be displayed.
+19
-9
src/components/PostComposer.svelte
+19
-9
src/components/PostComposer.svelte
···
81
81
let isFocused = $state(false);
82
82
let textareaEl: HTMLTextAreaElement | undefined = $state();
83
83
84
+
const unfocus = () => {
85
+
isFocused = false;
86
+
quoting = undefined;
87
+
replying = undefined;
88
+
};
89
+
84
90
const doPost = () => {
85
91
if (postText.length === 0 || postText.length > 300) return;
86
92
···
89
95
onPostSent(res.value);
90
96
postText = '';
91
97
info = 'posted!';
92
-
isFocused = false;
93
-
quoting = undefined;
94
-
replying = undefined;
98
+
unfocus();
95
99
setTimeout(() => (info = ''), 1000 * 0.8);
96
100
} else {
97
101
// todo: add a way to clear error
···
112
116
<div class="min-h-16"></div>
113
117
{/if}
114
118
119
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
115
120
<div
121
+
onmousedown={(e) => {
122
+
if (isFocused) {
123
+
e.preventDefault();
124
+
}
125
+
}}
116
126
class="flex max-w-full rounded-sm border-2 shadow-lg transition-all duration-300"
117
127
class:min-h-16={!isFocused}
118
128
class:items-center={!isFocused}
···
153
163
bind:this={textareaEl}
154
164
bind:value={postText}
155
165
onfocus={() => (isFocused = true)}
156
-
onblur={() => {
157
-
isFocused = false;
158
-
quoting = undefined;
159
-
replying = undefined;
160
-
}}
166
+
onblur={unfocus}
161
167
onkeydown={(event) => {
168
+
if (event.key === 'Escape') unfocus();
162
169
if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) doPost();
163
170
}}
164
171
placeholder="what's on your mind?"
···
188
195
{postText.length} / 300
189
196
</span>
190
197
<button
191
-
onclick={doPost}
198
+
onmousedown={(e) => {
199
+
e.preventDefault();
200
+
doPost();
201
+
}}
192
202
disabled={postText.length === 0 || postText.length > 300}
193
203
class="action-button border-none px-5 text-(--nucleus-fg)/94 disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:scale-100"
194
204
style="background: color-mix(in srgb, {color} 87%, transparent);"
+4
-1
src/routes/+page.svelte
+4
-1
src/routes/+page.svelte
···
493
493
494
494
{#snippet threadsView()}
495
495
{#each threads as thread (thread.rootUri)}
496
-
<div class="flex {reverseChronological ? 'flex-col' : 'flex-col-reverse'} mb-6.5">
496
+
<div class="flex w-full shrink-0 {reverseChronological ? 'flex-col' : 'flex-col-reverse'}">
497
497
{#if thread.branchParentPost}
498
498
{@render replyPost(thread.branchParentPost)}
499
499
{/if}
···
536
536
{/if}
537
537
{/each}
538
538
</div>
539
+
<div
540
+
class="mx-8 mt-3 mb-4 h-px bg-gradient-to-r from-(--nucleus-accent)/30 to-(--nucleus-accent2)/30"
541
+
></div>
539
542
{/each}
540
543
{/snippet}