Somewhat sensible design (WIP)
This commit is contained in:
parent
164571ec19
commit
dcca38a994
5 changed files with 162 additions and 75 deletions
|
@ -7,11 +7,13 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<h1>Welcome to the Feed</h1>
|
<div id="Content">
|
||||||
{#await accountsPromise}
|
{#await accountsPromise}
|
||||||
<p>Loading...</p>
|
<p>Loading...</p>
|
||||||
{:then accountsData}
|
{:then accountsData}
|
||||||
<div id="Account">
|
<div id="Account">
|
||||||
|
<h1 id="Header">ATProto PDS</h1>
|
||||||
|
<p>Home to {accountsData.length} accounts</p>
|
||||||
{#each accountsData as accountObject}
|
{#each accountsData as accountObject}
|
||||||
<AccountComponent account={accountObject} />
|
<AccountComponent account={accountObject} />
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -29,7 +31,39 @@
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/await}
|
{/await}
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
#Content {
|
||||||
|
display: flex;
|
||||||
|
/* split the screen in half, left for accounts, right for posts */
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #12082b;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
#Feed {
|
||||||
|
width: 65%;
|
||||||
|
height: 80vh;
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
#Account {
|
||||||
|
width: 35%;
|
||||||
|
height: 80vh;
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #070311;
|
||||||
|
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
#Header {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 2em;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
66
src/app.css
66
src/app.css
|
@ -1,16 +1,19 @@
|
||||||
:root {
|
@font-face {
|
||||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
font-family: 'ProggyClean';
|
||||||
line-height: 1.5;
|
src: url(https://witchcraft.systems/ProggyCleanNerdFont-Regular.ttf);
|
||||||
font-weight: 400;
|
}
|
||||||
|
|
||||||
color-scheme: light dark;
|
::-webkit-scrollbar {
|
||||||
color: rgba(255, 255, 255, 0.87);
|
width: 0px;
|
||||||
background-color: #242424;
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
font-synthesis: none;
|
* {
|
||||||
text-rendering: optimizeLegibility;
|
scrollbar-width: thin;
|
||||||
-webkit-font-smoothing: antialiased;
|
scrollbar-color: transparent transparent;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-ms-overflow-style: none; /* IE and Edge */
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
-webkit-scrollbar: none; /* Safari */
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
@ -28,6 +31,11 @@ body {
|
||||||
place-items: center;
|
place-items: center;
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
background-color: #12082b;
|
||||||
|
font-family: 'ProggyClean', monospace;
|
||||||
|
font-size: 24px;
|
||||||
|
color: white;
|
||||||
|
border-color: #8054f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
|
@ -35,45 +43,11 @@ h1 {
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
|
||||||
padding: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
max-width: 1280px;
|
max-width: 1400px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 0.6em 1.2em;
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: 500;
|
|
||||||
font-family: inherit;
|
|
||||||
background-color: #1a1a1a;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: border-color 0.25s;
|
|
||||||
}
|
|
||||||
button:hover {
|
|
||||||
border-color: #646cff;
|
|
||||||
}
|
|
||||||
button:focus,
|
|
||||||
button:focus-visible {
|
|
||||||
outline: 4px auto -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: light) {
|
|
||||||
:root {
|
|
||||||
color: #213547;
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #747bff;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,23 +1,39 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { AccountMetadata } from "./pdsfetch";
|
import type { AccountMetadata } from "./pdsfetch";
|
||||||
const { account }: { account: AccountMetadata } = $props();
|
const { account }: { account: AccountMetadata } = $props();
|
||||||
|
import { Config } from "../../config";
|
||||||
</script>
|
</script>
|
||||||
<div id="accountContainer">
|
<div id="accountContainer">
|
||||||
{#if account.avatarCid}
|
{#if account.avatarCid}
|
||||||
<img
|
<img
|
||||||
id="avatar"
|
id="avatar"
|
||||||
alt="avatar of {account.displayName}"
|
alt="avatar of {account.displayName}"
|
||||||
src="https://pds.witchcraft.systems/xrpc/com.atproto.sync.getBlob?did={account.did}&cid={account.avatarCid}"
|
src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={account.did}&cid={account.avatarCid}"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<p>{account.displayName}</p>
|
<div id="accountName">{account.displayName || account.did}</div>
|
||||||
</div>
|
</div>
|
||||||
<style>
|
<style>
|
||||||
#accountContainer {
|
#accountContainer {
|
||||||
display: column;
|
display: flex;
|
||||||
text-align: start;
|
text-align: start;
|
||||||
border: 2px solid black;
|
align-items: center;
|
||||||
|
background-color: #0d0620;
|
||||||
padding: 4%;
|
padding: 4%;
|
||||||
|
margin: 10px;
|
||||||
|
|
||||||
|
/* round corners */
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
#accountName {
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
|
||||||
|
/* replace overflow with ellipsis */
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
max-width: 80%;
|
||||||
}
|
}
|
||||||
#avatar {
|
#avatar {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
alt="avatar of {post.displayName}"
|
alt="avatar of {post.displayName}"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<p>{post.displayName} | {post.timenotstamp}</p>
|
<div id="headerText">{post.displayName} | {post.timenotstamp}</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="postContent">
|
<div id="postContent">
|
||||||
<p>{post.text}</p>
|
|
||||||
{#if post.replyingDid}
|
{#if post.replyingDid}
|
||||||
<p>Replying to: {post.replyingDid}</p>
|
<p id="replyingText">replying to: {post.replyingDid}</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
<p id="postText">{post.text}</p>
|
||||||
{#if post.imagesCid}
|
{#if post.imagesCid}
|
||||||
<div id="imagesContainer">
|
<div id="imagesContainer">
|
||||||
{#each post.imagesCid as imageLink}
|
{#each post.imagesCid as imageLink}
|
||||||
|
@ -42,21 +42,62 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#postContainer {
|
#postContainer {
|
||||||
display: column;
|
display: flex;
|
||||||
text-align: start;
|
flex-direction: column;
|
||||||
border: 2px solid black;
|
border: 1px solid #8054f0;
|
||||||
padding: 4%;
|
background-color: black;
|
||||||
|
margin-bottom: -1px;
|
||||||
}
|
}
|
||||||
#postHeader {
|
#postHeader {
|
||||||
text-decoration: underline;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: start;
|
||||||
|
background-color: #1f1145;
|
||||||
|
padding: 0px 0px;
|
||||||
|
height: fit-content;
|
||||||
|
border-bottom: 1px solid #8054f0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
#postContent {
|
||||||
|
display: flex;
|
||||||
|
text-align: start;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #0d0620;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
#replyingText {
|
||||||
|
font-size: 0.7em;
|
||||||
|
color: white;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#postText {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
#headerText {
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
text-align: start;
|
||||||
}
|
}
|
||||||
#avatar {
|
#avatar {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
border-radius: 50%;
|
margin: 0px;
|
||||||
|
margin-left: 0px;
|
||||||
|
border-right: #8054f0 1px solid;
|
||||||
}
|
}
|
||||||
#embedImages {
|
#embedImages {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
height: 50%;
|
height: 50%;
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: -5px;
|
||||||
|
}
|
||||||
|
#embedVideo {
|
||||||
|
width: 50%;
|
||||||
|
height: 50%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import type {
|
||||||
AppBskyFeedPost,
|
AppBskyFeedPost,
|
||||||
ComAtprotoRepoListRecords,
|
ComAtprotoRepoListRecords,
|
||||||
} from "@atcute/client/lexicons";
|
} from "@atcute/client/lexicons";
|
||||||
|
import { Config } from "../../config";
|
||||||
// import { ComAtprotoRepoListRecords.Record } from "@atcute/client/lexicons";
|
// import { ComAtprotoRepoListRecords.Record } from "@atcute/client/lexicons";
|
||||||
// import { AppBskyFeedPost } from "@atcute/client/lexicons";
|
// import { AppBskyFeedPost } from "@atcute/client/lexicons";
|
||||||
// import { AppBskyActorDefs } from "@atcute/client/lexicons";
|
// import { AppBskyActorDefs } from "@atcute/client/lexicons";
|
||||||
|
@ -87,7 +88,7 @@ const didFromATuri = (aturi: string) => {
|
||||||
|
|
||||||
const rpc = new XRPC({
|
const rpc = new XRPC({
|
||||||
handler: simpleFetchHandler({
|
handler: simpleFetchHandler({
|
||||||
service: "https://pds.witchcraft.systems",
|
service: Config.PDS_URL,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -99,6 +100,7 @@ const getDidsFromPDS = async () => {
|
||||||
};
|
};
|
||||||
const getAccountMetadata = async (did: `did:${string}:${string}`) => {
|
const getAccountMetadata = async (did: `did:${string}:${string}`) => {
|
||||||
// gonna assume self exists in the app.bsky.actor.profile
|
// gonna assume self exists in the app.bsky.actor.profile
|
||||||
|
try {
|
||||||
const { data } = await rpc.get("com.atproto.repo.getRecord", {
|
const { data } = await rpc.get("com.atproto.repo.getRecord", {
|
||||||
params: {
|
params: {
|
||||||
repo: did,
|
repo: did,
|
||||||
|
@ -116,6 +118,15 @@ const getAccountMetadata = async (did: `did:${string}:${string}`) => {
|
||||||
account.avatarCid = value.avatar.ref["$link"];
|
account.avatarCid = value.avatar.ref["$link"];
|
||||||
}
|
}
|
||||||
return account;
|
return account;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error(`Error fetching metadata for ${did}:`, e);
|
||||||
|
return {
|
||||||
|
did: "error",
|
||||||
|
displayName: "",
|
||||||
|
avatarCid: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getAllMetadataFromPds = async () => {
|
const getAllMetadataFromPds = async () => {
|
||||||
|
@ -125,10 +136,11 @@ const getAllMetadataFromPds = async () => {
|
||||||
return await getAccountMetadata(repo);
|
return await getAccountMetadata(repo);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return metadata;
|
return metadata.filter(account => account.did !== "error");
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchPosts = async (did: string) => {
|
const fetchPosts = async (did: string) => {
|
||||||
|
try {
|
||||||
const { data } = await rpc.get("com.atproto.repo.listRecords", {
|
const { data } = await rpc.get("com.atproto.repo.listRecords", {
|
||||||
params: {
|
params: {
|
||||||
repo: did,
|
repo: did,
|
||||||
|
@ -139,7 +151,16 @@ const fetchPosts = async (did: string) => {
|
||||||
return {
|
return {
|
||||||
records: data.records as ComAtprotoRepoListRecords.Record[],
|
records: data.records as ComAtprotoRepoListRecords.Record[],
|
||||||
did: did,
|
did: did,
|
||||||
|
error: false
|
||||||
};
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Error fetching posts for ${did}:`, e);
|
||||||
|
return {
|
||||||
|
records: [],
|
||||||
|
did: did,
|
||||||
|
error: true
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchAllPosts = async () => {
|
const fetchAllPosts = async () => {
|
||||||
|
@ -149,7 +170,8 @@ const fetchAllPosts = async () => {
|
||||||
await fetchPosts(metadata.did)
|
await fetchPosts(metadata.did)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const posts: Post[] = postRecords.flatMap((userFetch) =>
|
const validPostRecords = postRecords.filter(record => !record.error);
|
||||||
|
const posts: Post[] = validPostRecords.flatMap((userFetch) =>
|
||||||
userFetch.records.map((record) => {
|
userFetch.records.map((record) => {
|
||||||
const user = users.find((user: AccountMetadata) =>
|
const user = users.find((user: AccountMetadata) =>
|
||||||
user.did == userFetch.did
|
user.did == userFetch.did
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue