+18
-9
.tangled/workflows/build.yml
+18
-9
.tangled/workflows/build.yml
···
8
8
nixpkgs:
9
9
- deno
10
10
- openssh
11
+
- su
11
12
12
13
steps:
13
-
- name: "Creating local user"
14
+
- name: "Pretend we have a real local user"
14
15
command: |
15
-
sudo useradd -r -u 0 pipeuser
16
+
echo "🪶 pretend root is a real user"
17
+
echo "root:x:0:0:System administrator:/root:/run/current-system/sw/bin/bash" >> /etc/passwd
16
18
17
19
- name: "Copy config to server"
18
20
command: |
···
35
37
mkdir ~/.ssh
36
38
echo "${SSH_KEY}" > ~/.ssh/id_tangledsh
37
39
chmod 600 ~/.ssh/id_tangledsh
38
-
ssh-keyscan -H $SERVER_HOST > ~/.ssh/known_hosts
39
-
40
-
- name: "Check SSH connection"
41
-
command: |
42
-
echo "🪶 checking ssh connection"
43
-
ssh -v $SERVER_USER@$SERVER_HOST echo "🪶 ssh connection successful"
40
+
cat > /etc/ssh/ssh_config << EOF
41
+
Host deploy
42
+
HostName ${SERVER_HOST}
43
+
User ${SERVER_USER}
44
+
IdentityFile ~/.ssh/id_tangledsh
45
+
StrictHostKeyChecking no
46
+
UserKnownHostsFile /dev/null
47
+
BatchMode yes
48
+
PasswordAuthentication no
49
+
PubkeyAuthentication yes
50
+
EOF
51
+
chmod 600 /etc/ssh/ssh_config
52
+
ssh-keyscan -H $SERVER_HOST >> ~/.ssh/known_hosts
44
53
45
54
- name: "Deploy via SCP"
46
55
command: |
47
56
echo "🪶 deploying files via scp"
48
-
scp -r ./dist/* $SERVER_USER@$SERVER_HOST:/pds/caddy/etc/caddy/static
57
+
scp -r ./dist/* deploy:/pds/caddy/etc/caddy/static
49
58
50
59
- name: "Done!"
51
60
command: |
+1
-1
README.md
+1
-1
README.md
···
10
10
* Replaced favicon
11
11
* Ported in guestbook functionality from another PDS frontpage (see new config options)
12
12
* Secret unique easter egg :)
13
-
* Wrote deploy pipeline for tangled.sh
13
+
* Wrote deploy pipeline for tangled.sh (WORK IN PROGRESS help try #5 - changing ssh perms?)
14
14
15
15
you can see it running at [my pds!](https://shimaenaga.veryroundbird.house)
16
16
+2
-1
src/App.svelte
+2
-1
src/App.svelte
···
1
1
<script lang="ts">
2
2
import PostComponent from "./lib/PostComponent.svelte";
3
+
import GuestbookPostComponent from "./lib/GuestbookPostComponent.svelte";
3
4
import AccountComponent from "./lib/AccountComponent.svelte";
4
5
import InfiniteLoading from "svelte-infinite-loading";
5
6
import { getNextPosts, Post, getAllMetadataFromPds, fetchGuestbookPosts } from "./lib/pdsfetch";
···
152
153
<div id="guestbookPosts">
153
154
{#if guestbookPosts.length > 0}
154
155
{#each guestbookPosts as postObject}
155
-
<PostComponent post={postObject as Post} />
156
+
<GuestbookPostComponent post={postObject.post} />
156
157
{/each}
157
158
{:else}
158
159
<p class="noGuestbookPosts">No guestbook posts yet!</p>
+92
src/lib/GuestbookPostComponent.svelte
+92
src/lib/GuestbookPostComponent.svelte
···
1
+
<script lang="ts">
2
+
import { Post } from "./pdsfetch";
3
+
import { Config } from "../../config";
4
+
import { onMount } from "svelte";
5
+
import moment from "moment";
6
+
7
+
let { post }: { post: Post } = $props();
8
+
console.log(post);
9
+
</script>
10
+
11
+
<div class="postContainer">
12
+
<div class="postHeader">
13
+
{#if post.author.avatar}
14
+
<img
15
+
class="avatar"
16
+
src="{post.author.avatar}"
17
+
alt="avatar of {post.author.displayName}"
18
+
/>
19
+
{/if}
20
+
<div class="headerText">
21
+
<a class="displayName" href="{Config.FRONTEND_URL}/profile/{post.author.did}">{post.author.displayName}</a>
22
+
<p class="handle">
23
+
<a href="{Config.FRONTEND_URL}/profile/{post.author.handle}"
24
+
>@{post.author.handle}</a
25
+
>
26
+
<a
27
+
class="postLink" href="{Config.FRONTEND_URL}/profile/{post.author.did}/post/{post.record.id}"
28
+
>{moment(post.record.createdAt).isBefore(moment().subtract(1, "month"))
29
+
? moment(post.record.createdAt).format("MMM D, YYYY")
30
+
: moment(post.record.createdAt).fromNow()}</a>
31
+
</p>
32
+
</div>
33
+
</div>
34
+
<div class="postContent">
35
+
{#if post.record.quote}
36
+
<a
37
+
class="quotingText"
38
+
href="{Config.FRONTEND_URL}/profile/{post.record.quote.uri}/post/{post
39
+
.quotingUri.rkey}">quoting {post.quotingUri.repo}</a
40
+
>
41
+
{/if}
42
+
<div class="postText">{post.record.text}</div>
43
+
{#if post.record.imagesCid && post.record.imagesCid.length > 0}
44
+
<div id="carouselContainer">
45
+
<img
46
+
class="embedImages"
47
+
alt="Post Image {currentImageIndex + 1} of {post.record.imagesCid.length}"
48
+
src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.record.author.did}&cid={post.record
49
+
.imagesCid[currentImageIndex]}"
50
+
/>
51
+
52
+
{#if post.imagesCid.length > 1}
53
+
<div class="carouselControls">
54
+
<button
55
+
id="prevBtn"
56
+
onclick={prevImage}
57
+
disabled={currentImageIndex === 0}>←</button
58
+
>
59
+
<div class="carouselIndicators">
60
+
{#each post.record.imagesCid as _, i}
61
+
<div
62
+
class="indicator {i === currentImageIndex ? 'active' : ''}"
63
+
></div>
64
+
{/each}
65
+
</div>
66
+
<button
67
+
class="nextBtn"
68
+
onclick={nextImage}
69
+
disabled={currentImageIndex === post.imagesCid.length - 1}
70
+
>→</button
71
+
>
72
+
</div>
73
+
{/if}
74
+
</div>
75
+
{/if}
76
+
{#if post.record.videosLinkCid}
77
+
<!-- svelte-ignore a11y_media_has_caption -->
78
+
<video
79
+
class="embedVideo"
80
+
src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={post.authorDid}&cid={post.videosLinkCid}"
81
+
controls
82
+
></video>
83
+
{/if}
84
+
{#if post.gifLink}
85
+
<img
86
+
class="embedVideo"
87
+
src="{post.record.gifLink}"
88
+
alt="Post GIF"
89
+
/>
90
+
{/if}
91
+
</div>
92
+
</div>