this repo has no description

Compare changes

Choose any two refs to compare.

+12 -1
.forgejo/workflows/deploy.yaml
··· 6 6 - main 7 7 - astra/ci 8 8 9 + 9 10 jobs: 10 11 deploy: 11 12 name: Deploy 12 13 runs-on: ubuntu-latest 13 14 14 15 steps: 15 - - name: Checkout repo 16 + - name: Checkout main repo 16 17 uses: actions/checkout@v4 17 18 19 + - name: Checkout overrides repo 20 + uses: actions/checkout@v4 21 + with: 22 + repository: scientific-witchery/pds-dash-overrides 23 + token: ${{ secrets.OVERRIDES_TOKEN}} 24 + path: overrides 25 + 26 + - name: Copy config file to root 27 + run: cp overrides/config.ts ./config.ts 28 + 18 29 - name: Setup Node.js 19 30 uses: actions/setup-node@v3 20 31 with:
+4 -1
.gitignore
··· 149 149 .yarn/unplugged 150 150 .yarn/build-state.yml 151 151 .yarn/install-state.gz 152 - .pnp.* 152 + .pnp.* 153 + 154 + # Config files 155 + config.ts
+6 -9
README.md
··· 10 10 11 11 ### installing 12 12 13 - clone the repo, install dependencies using deno: 13 + clone the repo, copy `config.ts.example` to `config.ts` and edit it to your liking. 14 + 15 + then, install dependencies using deno: 14 16 15 17 ```sh 16 18 deno install ··· 44 46 45 47 ## theming 46 48 47 - the colors are designated in [`src/app.css`](src/app.css) as variables, go crazy with them 49 + themes are located in the `themes/` directory, you can create your own theme by copying one of the existing themes and modifying it to your liking. 48 50 49 - the rest is done by editing the css files and style tags directly, good luck 51 + currently, the name of the theme is determined by the directory name, and the theme itself is defined in `theme.css` inside that directory. 50 52 51 - relevant files: 52 - 53 - - [`src/App.svelte`](src/App.svelte) 54 - - [`src/app.css`](src/app.css) 55 - - [`src/lib/AccountComponent.svelte`](src/lib/AccountComponent.svelte) 56 - - [`src/lib/PostComponent.svelte`](src/lib/PostComponent.svelte) 53 + you can switch themes by changing the `theme` property in `config.ts`. 57 54 58 55 the favicon is located at [`public/favicon.ico`](public/favicon.ico) 59 56
-43
config.ts
··· 1 - /** 2 - * Configuration module for the PDS Dashboard 3 - */ 4 - export class Config { 5 - /** 6 - * The base URL of the PDS (Personal Data Server) 7 - * @default "https://pds.witchcraft.systems" 8 - */ 9 - static readonly PDS_URL: string = "https://pds.witchcraft.systems"; 10 - 11 - /** 12 - * Hue value for the color scheme 13 - * @default 257 14 - */ 15 - static readonly HUE: number = 13; 16 - 17 - /** 18 - * The base URL of the frontend service for linking to replies/quotes/accounts etc. 19 - * @default "https://deer.social" 20 - */ 21 - static readonly FRONTEND_URL: string = "https://deer.social"; 22 - 23 - /** 24 - * Maximum number of posts to fetch from the PDS per request 25 - * Should be around 20 for about 10 users on the pds 26 - * The more users you have, the lower the number should be 27 - * since sorting is slow and is done on the frontend 28 - * @default 20 29 - */ 30 - static readonly MAX_POSTS: number = 20; 31 - 32 - /** 33 - * Footer text for the dashboard, you probably want to change this 34 - */ 35 - static readonly FOOTER_TEXT: string = 36 - "Astrally projected from <a href='https://witchcraft.systems' target='_blank'>witchcraft.systems</a><br><br><a href='https://git.witchcraft.systems/scientific-witchery/pds-dash' target='_blank'>Source</a> (<a href='https://github.com/witchcraft-systems/pds-dash/' target='_blank'>github mirror</a>)"; 37 - 38 - /** 39 - * Whether to show the posts that are in the future 40 - * @default false 41 - */ 42 - static readonly SHOW_FUTURE_POSTS: boolean = false; 43 - }
+44
config.ts.example
··· 1 + /** 2 + * Configuration module for the PDS Dashboard 3 + */ 4 + export class Config { 5 + /** 6 + * The base URL of the PDS (Personal Data Server). 7 + * @default none 8 + */ 9 + static readonly PDS_URL: string = ""; 10 + 11 + /** 12 + * Theme to be used 13 + * @default "default" 14 + */ 15 + static readonly THEME: string = "default"; 16 + 17 + /** 18 + * The base URL of the frontend service for linking to replies/quotes/accounts etc. 19 + * @default "https://deer.social" // or https://bsky.app if you're boring 20 + */ 21 + static readonly FRONTEND_URL: string = "https://deer.social"; 22 + 23 + /** 24 + * Maximum number of posts to fetch from the PDS per request 25 + * Should be around 20 for about 10 users on the pds 26 + * The more users you have, the lower the number should be 27 + * since sorting is slow and is done on the frontend 28 + * @default 20 29 + */ 30 + static readonly MAX_POSTS: number = 20; 31 + 32 + /** 33 + * Footer text for the dashboard, you probably want to change this. Supports HTML. 34 + * @default "<a href='https://git.witchcraft.systems/scientific-witchery/pds-dash' target='_blank'>Source</a> (<a href='https://github.com/witchcraft-systems/pds-dash/' target='_blank'>github mirror</a>)" 35 + */ 36 + static readonly FOOTER_TEXT: string = 37 + "<a href='https://git.witchcraft.systems/scientific-witchery/pds-dash' target='_blank'>Source</a> (<a href='https://github.com/witchcraft-systems/pds-dash/' target='_blank'>github mirror</a>)"; 38 + 39 + /** 40 + * Whether to show the posts with timestamps that are in the future. 41 + * @default false 42 + */ 43 + static readonly SHOW_FUTURE_POSTS: boolean = false; 44 + }
+16 -107
src/App.svelte
··· 4 4 import InfiniteLoading from "svelte-infinite-loading"; 5 5 import { getNextPosts, Post, getAllMetadataFromPds } from "./lib/pdsfetch"; 6 6 import { Config } from "../config"; 7 - import { onMount } from "svelte"; 8 - import { CssVarsFromHue } from "./lib/colorgenerator"; 9 - 10 - 11 7 const accountsPromise = getAllMetadataFromPds(); 12 - let colors = CssVarsFromHue(Config.HUE); 8 + import { onMount } from "svelte"; 13 9 14 10 let posts: Post[] = []; 15 11 12 + let hue: number = 1; 16 13 const cycleColors = async () => { 17 - let hue = Config.HUE; 18 - while (true) { 19 - colors = CssVarsFromHue(hue); 14 + while (true) { 20 15 hue += 1; 21 16 if (hue > 360) { 22 17 hue = 0; 23 18 } 24 - // Wait for 1 second before changing colors again 19 + document.documentElement.style.setProperty("--primary-h", hue.toString()); 25 20 await new Promise((resolve) => setTimeout(resolve, 10)); 26 21 } 27 22 } 28 - cycleColors(); 23 + let clickCounter = 0; 24 + const carameldansenfusion = async () => { 25 + clickCounter++; 26 + if (clickCounter >= 10) { 27 + clickCounter = 0; 28 + cycleColors(); 29 + } 30 + }; 31 + 29 32 onMount(() => { 30 33 // Fetch initial posts 31 34 getNextPosts().then((initialPosts) => { ··· 50 53 }; 51 54 </script> 52 55 53 - <main style=" 54 - --background-color: {colors.background}; 55 - --header-background-color: {colors.header}; 56 - --content-background-color: {colors.content}; 57 - --text-color: {colors.text}; 58 - --border-color: {colors.accent}; 59 - --link-color: {colors.link}; 60 - --link-hover-color: {colors.linkHover}; 61 - --indicator-inactive-color: #4a4a4a; 62 - --indicator-active-color: {colors.accent}; 63 - "> 56 + <main> 64 57 <div id="Content"> 65 58 {#await accountsPromise} 66 59 <p>Loading...</p> 67 60 {:then accountsData} 68 61 <div id="Account"> 69 - <h1 id="Header">ATProto PDS</h1> 62 + <h1 onclick={carameldansenfusion} id="Header">ATProto PDS</h1> 70 63 <p>Home to {accountsData.length} accounts</p> 71 64 <div id="accountsList"> 72 65 {#each accountsData as accountObject} ··· 91 84 </main> 92 85 93 86 <style> 94 - /* desktop style */ 95 - #Content { 96 - display: flex; 97 - /* split the screen in half, left for accounts, right for posts */ 98 - width: 100%; 99 - height: 100%; 100 - flex-direction: row; 101 - justify-content: space-between; 102 - align-items: center; 103 - background-color: var(--background-color); 104 - color: var(--text-color); 105 - } 106 - #Feed { 107 - overflow-y: scroll; 108 - width: 65%; 109 - height: 100vh; 110 - padding: 20px; 111 - padding-bottom: 0; 112 - padding-top: 0; 113 - margin-top: 0; 114 - margin-bottom: 0; 115 - } 116 - #spacer { 117 - padding: 0; 118 - margin: 0; 119 - height: 10vh; 120 - width: 100%; 121 - } 122 - #Account { 123 - width: 35%; 124 - display: flex; 125 - flex-direction: column; 126 - border: 1px solid var(--border-color); 127 - background-color: var(--content-background-color); 128 - height: 80vh; 129 - padding: 20px; 130 - margin-left: 20px; 131 - } 132 - #accountsList { 133 - display: flex; 134 - flex-direction: column; 135 - overflow-y: scroll; 136 - height: 100%; 137 - width: 100%; 138 - padding: 0px; 139 - margin: 0px; 140 - } 141 - 142 - #Header { 143 - text-align: center; 144 - font-size: 2em; 145 - margin-bottom: 20px; 146 - } 147 - 148 - /* mobile style */ 149 - @media screen and (max-width: 600px) { 150 - #Content { 151 - flex-direction: column; 152 - width: auto; 153 - padding-left: 0px; 154 - padding-right: 0px; 155 - margin-top: 5%; 156 - } 157 - #Account { 158 - width: 85%; 159 - padding-left: 5%; 160 - padding-right: 5%; 161 - margin-bottom: 20px; 162 - margin-left: 5%; 163 - margin-right: 5%; 164 - height: auto; 165 - } 166 - #Feed { 167 - width: 95%; 168 - margin: 0px; 169 - margin-left: 10%; 170 - margin-right: 10%; 171 - padding: 0px; 172 - overflow-y: visible; 173 - } 174 - 175 - #spacer { 176 - height: 0; 177 - } 178 - } 87 + 179 88 </style>
+3 -76
src/app.css
··· 1 - @font-face { 2 - font-family: "ProggyClean"; 3 - src: url(https://witchcraft.systems/ProggyCleanNerdFont-Regular.ttf); 4 - } 5 - 6 - 7 - ::-webkit-scrollbar { 8 - width: 0px; 9 - background: transparent; 10 - padding: 0; 11 - margin: 0; 12 - } 13 - ::-webkit-scrollbar-thumb { 14 - background: transparent; 15 - border-radius: 0; 16 - } 17 - ::-webkit-scrollbar-track { 18 - background: transparent; 19 - border-radius: 0; 20 - } 21 - ::-webkit-scrollbar-corner { 22 - background: transparent; 23 - border-radius: 0; 24 - } 25 - ::-webkit-scrollbar-button { 26 - background: transparent; 27 - border-radius: 0; 28 - } 29 - * { 30 - scrollbar-width: none; 31 - scrollbar-color: transparent transparent; 32 - -ms-overflow-style: none; /* IE and Edge */ 33 - -webkit-overflow-scrolling: touch; 34 - -webkit-scrollbar: none; /* Safari */ 35 - } 36 - 37 - a { 38 - font-weight: 500; 39 - color: var(--link-color); 40 - text-decoration: inherit; 41 - } 42 - a:hover { 43 - color: var(--link-hover-color); 44 - text-decoration: underline; 45 - } 46 - 1 + @import url('./themes/colors.css'); 47 2 body { 48 - margin: 0; 49 - display: flex; 50 - place-items: center; 51 - min-width: 320px; 52 - min-height: 100vh; 53 - background-color: var(--background-color); 54 - font-family: "ProggyClean", monospace; 55 - font-size: 24px; 56 - color: var(--text-color); 57 - border-color: var(--border-color); 58 - overflow-wrap: break-word; 59 - word-wrap: normal; 60 - word-break: break-word; 61 - hyphens: none; 62 - } 63 - 64 - h1 { 65 - font-size: 3.2em; 66 - line-height: 1.1; 67 - } 68 - 69 - #app { 70 - max-width: 1400px; 71 - width: 100%; 72 - margin: 0; 73 - padding: 0; 74 - margin-left: auto; 75 - margin-right: auto; 76 - text-align: center; 77 - } 3 + background-color: red; 4 + }
+7 -28
src/lib/AccountComponent.svelte
··· 12 12 alt="avatar of {account.displayName}" 13 13 src="{Config.PDS_URL}/xrpc/com.atproto.sync.getBlob?did={account.did}&cid={account.avatarCid}" 14 14 /> 15 + <div id="accountName"> 16 + {account.displayName || account.handle || account.did} 17 + </div> 18 + {:else} 19 + <div id="accountName" class="no-avatar"> 20 + {account.displayName || account.handle || account.did} 21 + </div> 15 22 {/if} 16 - <div id="accountName"> 17 - {account.displayName || account.handle || account.did} 18 - </div> 19 23 </div> 20 24 </a> 21 25 22 26 <style> 23 - #accountContainer { 24 - display: flex; 25 - text-align: start; 26 - align-items: center; 27 - background-color: var(--background-color); 28 - padding: 0px; 29 - margin-bottom: 15px; 30 - border: 1px solid var(--border-color); 31 - } 32 - #accountName { 33 - margin-left: 10px; 34 - font-size: 0.9em; 35 - max-width: 80%; 36 27 37 - /* replace overflow with ellipsis */ 38 - overflow: hidden; 39 - text-overflow: ellipsis; 40 - white-space: nowrap; 41 - } 42 - #avatar { 43 - width: 50px; 44 - height: 50px; 45 - margin: 0px; 46 - object-fit: cover; 47 - border-right: var(--border-color) 1px solid; 48 - } 49 28 </style>
+1 -163
src/lib/PostComponent.svelte
··· 71 71 > 72 72 <p id="handle"> 73 73 <a href="{Config.FRONTEND_URL}/profile/{post.authorHandle}" 74 - >{post.authorHandle}</a 74 + >@{post.authorHandle}</a 75 75 > 76 76 77 77 <a ··· 152 152 </div> 153 153 154 154 <style> 155 - a:hover { 156 - text-decoration: underline; 157 - } 158 - #postContainer { 159 - display: flex; 160 - flex-direction: column; 161 - border: 1px solid var(--border-color); 162 - background-color: var(--background-color); 163 - margin-bottom: 15px; 164 - overflow-wrap: break-word; 165 - } 166 - #postHeader { 167 - display: flex; 168 - flex-direction: row; 169 - align-items: center; 170 - justify-content: start; 171 - background-color: var(--header-background-color); 172 - padding: 0px 0px; 173 - height: fit-content; 174 - border-bottom: 1px solid var(--border-color); 175 - font-weight: bold; 176 - overflow-wrap: break-word; 177 - height: 60px; 178 - } 179 - #displayName { 180 - display: block; 181 - color: var(--text-color); 182 - font-size: 1.2em; 183 - padding: 0; 184 - margin: 0; 185 - overflow-wrap:normal; 186 - word-wrap: break-word; 187 - word-break: break-word; 188 - text-overflow: ellipsis; 189 - overflow: hidden; 190 - white-space: nowrap; 191 - width: 100%; 192 - } 193 - #handle { 194 - display: block; 195 - color: var(--border-color); 196 - font-size: 0.8em; 197 - padding: 0; 198 - margin: 0; 199 - } 200 155 201 - #postLink { 202 - color: var(--border-color); 203 - font-size: 0.8em; 204 - padding: 0; 205 - margin: 0; 206 - } 207 - #postContent { 208 - display: flex; 209 - text-align: start; 210 - flex-direction: column; 211 - padding: 10px; 212 - background-color: var(--content-background-color); 213 - color: var(--text-color); 214 - overflow-wrap: break-word; 215 - white-space: pre-line; 216 - } 217 - #replyingText { 218 - font-size: 0.7em; 219 - margin: 0; 220 - padding: 0; 221 - padding-bottom: 5px; 222 - } 223 - #quotingText { 224 - font-size: 0.7em; 225 - margin: 0; 226 - padding: 0; 227 - padding-bottom: 5px; 228 - } 229 - #postText { 230 - margin: 0; 231 - padding: 0; 232 - overflow-wrap: break-word; 233 - word-wrap: normal; 234 - word-break: break-word; 235 - hyphens: none; 236 - } 237 - #headerText { 238 - margin-left: 10px; 239 - font-size: 0.9em; 240 - text-align: start; 241 - word-break: break-word; 242 - max-width: 80%; 243 - max-height: 95%; 244 - overflow: hidden; 245 - align-self: flex-start; 246 - margin-top: auto; 247 - margin-bottom: auto; 248 - } 249 - #avatar { 250 - height: 60px; 251 - width: 60px; 252 - margin: 0px; 253 - margin-left: 0px; 254 - overflow: hidden; 255 - object-fit: cover; 256 - border-right: var(--border-color) 1px solid; 257 - } 258 - #carouselContainer { 259 - position: relative; 260 - width: 100%; 261 - margin-top: 10px; 262 - display: flex; 263 - flex-direction: column; 264 - align-items: center; 265 - } 266 - #carouselControls { 267 - display: flex; 268 - justify-content: space-between; 269 - align-items: center; 270 - width: 100%; 271 - max-width: 500px; 272 - margin-top: 5px; 273 - } 274 - #carouselIndicators { 275 - display: flex; 276 - gap: 5px; 277 - } 278 - .indicator { 279 - width: 8px; 280 - height: 8px; 281 - background-color: var(--indicator-inactive-color); 282 - } 283 - .indicator.active { 284 - background-color: var(--indicator-active-color); 285 - } 286 - #prevBtn, 287 - #nextBtn { 288 - background-color: rgba(31, 17, 69, 0.7); 289 - color: var(--text-color); 290 - border: 1px solid var(--border-color); 291 - width: 30px; 292 - height: 30px; 293 - cursor: pointer; 294 - display: flex; 295 - align-items: center; 296 - justify-content: center; 297 - } 298 - #prevBtn:disabled, 299 - #nextBtn:disabled { 300 - opacity: 0.5; 301 - cursor: not-allowed; 302 - } 303 - #embedVideo { 304 - width: 100%; 305 - max-width: 500px; 306 - margin-top: 10px; 307 - align-self: center; 308 - } 309 - 310 - #embedImages { 311 - min-width: min(100%, 500px); 312 - max-width: min(100%, 500px); 313 - max-height: 500px; 314 - object-fit: contain; 315 - 316 - margin: 0; 317 - } 318 156 </style>
-26
src/lib/colorgenerator.ts
··· 1 - 2 - // :root { 3 - // --link-color: #646cff; 4 - // --link-hover-color: #535bf2; 5 - // --background-color: #12082b; hsl(257, 69%, 10%) 6 - // --header-background-color: #1f1145; hsl(257, 60%, 15%) 7 - // --content-background-color: #0d0620; hsl(257, 68%, 7%) 8 - // --text-color: white; 9 - // --border-color: #8054f0; hsl(257, 84%, 64%) 10 - // --indicator-inactive-color: #4a4a4a; 11 - // --indicator-active-color: #8054f0; 12 - // } 13 - export const CssVarsFromHue = (hue: number) => { 14 - const h = hue % 360; 15 - const cssVars = { 16 - accent: `hsl(${h}, 85%, 65%)`, 17 - background: `hsl(${h}, 69%, 10%)`, 18 - header: `hsl(${h}, 60%, 15%)`, 19 - content: `hsl(${h}, 68%, 7%)`, 20 - text: `hsl(${h}, 0%, 100%)`, 21 - link: `hsl(${h}, 100%, 50%)`, 22 - linkHover: `hsl(${h}, 100%, 40%)`, 23 - }; 24 - return cssVars; 25 - }; 26 -
+17 -10
src/lib/pdsfetch.ts
··· 132 132 const getAccountMetadata = async ( 133 133 did: `did:${string}:${string}`, 134 134 ) => { 135 - // gonna assume self exists in the app.bsky.actor.profile 135 + const account: AccountMetadata = { 136 + did: did, 137 + handle: "", // Guaranteed to be filled out later 138 + displayName: "", 139 + avatarCid: null, 140 + }; 141 + 136 142 try { 137 143 const { data } = await rpc.get("com.atproto.repo.getRecord", { 138 144 params: { ··· 142 148 }, 143 149 }); 144 150 const value = data.value as AppBskyActorProfile.Record; 145 - const handle = await blueskyHandleFromDid(did); 146 - const account: AccountMetadata = { 147 - did: did, 148 - handle: handle, 149 - displayName: value.displayName || "", 150 - avatarCid: null, 151 - }; 151 + account.displayName = value.displayName || ""; 152 152 if (value.avatar) { 153 153 account.avatarCid = value.avatar.ref["$link"]; 154 154 } 155 - return account; 155 + } catch (e) { 156 + console.warn(`Error fetching profile for ${did}:`, e); 157 + } 158 + 159 + try { 160 + account.handle = await blueskyHandleFromDid(did); 156 161 } catch (e) { 157 - console.error(`Error fetching metadata for ${did}:`, e); 162 + console.error(`Error fetching handle for ${did}:`, e); 158 163 return null; 159 164 } 165 + 166 + return account; 160 167 }; 161 168 162 169 const getAllMetadataFromPds = async (): Promise<AccountMetadata[]> => {
+423
themes/default/theme.css
··· 1 + /* Modern Theme for pds-dash */ 2 + 3 + :root { 4 + /* Modern color palette */ 5 + --primary-h: 243; 6 + --link-color: hsl(var(--primary-h), 73%, 59%); 7 + --link-hover-color: #4338ca; 8 + --time-color: #8b5cf6; 9 + --background-color: #f8fafc; 10 + --header-background-color: #ffffff; 11 + --content-background-color: #ffffff; 12 + --text-color: #111827; 13 + --text-secondary-color: #4b5563; 14 + --border-color: #e2e8f0; 15 + --indicator-inactive-color: #cbd5e1; 16 + --indicator-active-color: #6366f1; 17 + 18 + /* Modern shadows */ 19 + --button-hover: #f3f4f6; 20 + } 21 + 22 + 23 + body { 24 + margin: 0; 25 + display: flex; 26 + place-items: center; 27 + min-width: 320px; 28 + min-height: 100vh; 29 + background-color: var(--background-color); 30 + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; 31 + font-size: 18px; 32 + line-height: 1.5; 33 + color: var(--text-color); 34 + border-color: var(--border-color); 35 + overflow-wrap: break-word; 36 + word-break: break-word; 37 + hyphens: none; 38 + } 39 + 40 + a { 41 + font-weight: 500; 42 + color: var(--link-color); 43 + text-decoration: none; 44 + transition: color 0.15s ease; 45 + } 46 + a:hover { 47 + color: var(--link-hover-color); 48 + } 49 + 50 + h1 { 51 + font-size: 2.5em; 52 + line-height: 1.2; 53 + font-weight: 700; 54 + } 55 + 56 + #app { 57 + max-width: 1400px; 58 + width: 100%; 59 + margin: 0 auto; 60 + padding: 0; 61 + text-align: center; 62 + } 63 + 64 + /* Post Component */ 65 + #postContainer { 66 + display: flex; 67 + flex-direction: column; 68 + border-radius: 12px; 69 + border: 1px solid var(--border-color); 70 + background-color: var(--content-background-color); 71 + margin-bottom: 20px; 72 + overflow-wrap: break-word; 73 + overflow: hidden; 74 + box-shadow: var(--card-shadow); 75 + transition: transform 0.2s ease, box-shadow 0.2s ease; 76 + } 77 + 78 + #postContainer:hover { 79 + transform: translateY(-2px); 80 + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); 81 + } 82 + 83 + #postHeader { 84 + display: flex; 85 + flex-direction: row; 86 + align-items: center; 87 + justify-content: start; 88 + background-color: var(--header-background-color); 89 + padding: 12px 16px; 90 + height: 60px; 91 + border-bottom: 1px solid var(--border-color); 92 + font-weight: 600; 93 + overflow-wrap: break-word; 94 + } 95 + 96 + #displayName { 97 + display: block; 98 + color: var(--text-color); 99 + font-size: 1.1em; 100 + padding: 0; 101 + margin: 0 0 2px 0; 102 + text-overflow: ellipsis; 103 + overflow: hidden; 104 + white-space: nowrap; 105 + width: 100%; 106 + letter-spacing: -0.01em; 107 + } 108 + 109 + #handle { 110 + display: flex; 111 + align-items: center; 112 + color: #6b7280; 113 + font-size: 0.85em; 114 + font-weight: 400; 115 + padding: 0; 116 + margin: 0; 117 + gap: 8px; 118 + } 119 + 120 + #postLink { 121 + color: var(--time-color); 122 + font-size: 0.85em; 123 + padding: 0; 124 + margin: 0; 125 + opacity: 0.9; 126 + } 127 + 128 + #postContent { 129 + display: flex; 130 + text-align: start; 131 + flex-direction: column; 132 + padding: 16px; 133 + background-color: var(--content-background-color); 134 + color: var(--text-color); 135 + overflow-wrap: break-word; 136 + white-space: pre-line; 137 + line-height: 1.6; 138 + } 139 + 140 + #replyingText, #quotingText { 141 + font-size: 0.8em; 142 + margin: 0; 143 + padding: 0 0 10px 0; 144 + color: #6b7280; 145 + } 146 + 147 + #postText { 148 + margin: 0 0 8px 0; 149 + padding: 0; 150 + overflow-wrap: break-word; 151 + word-break: break-word; 152 + hyphens: none; 153 + font-size: 1.05em; 154 + } 155 + 156 + #headerText { 157 + margin-left: 12px; 158 + font-size: 0.9em; 159 + text-align: start; 160 + word-break: break-word; 161 + max-width: 80%; 162 + max-height: 95%; 163 + overflow: hidden; 164 + align-self: flex-start; 165 + margin-top: auto; 166 + margin-bottom: auto; 167 + } 168 + 169 + #carouselContainer { 170 + position: relative; 171 + width: 100%; 172 + margin-top: 12px; 173 + display: flex; 174 + flex-direction: column; 175 + align-items: center; 176 + border-radius: 8px; 177 + overflow: hidden; 178 + } 179 + 180 + #carouselControls { 181 + display: flex; 182 + justify-content: space-between; 183 + align-items: center; 184 + width: 100%; 185 + max-width: 500px; 186 + margin-top: 10px; 187 + } 188 + 189 + #carouselIndicators { 190 + display: flex; 191 + gap: 6px; 192 + } 193 + 194 + .indicator { 195 + width: 6px; 196 + height: 6px; 197 + background-color: var(--indicator-inactive-color); 198 + border-radius: 50%; 199 + transition: background-color 0.2s ease, transform 0.2s ease; 200 + } 201 + 202 + .indicator.active { 203 + background-color: var(--indicator-active-color); 204 + transform: scale(1.3); 205 + } 206 + 207 + #prevBtn, 208 + #nextBtn { 209 + background-color: var(--button-bg); 210 + color: var(--text-color); 211 + border: 1px solid var(--border-color); 212 + width: 32px; 213 + height: 32px; 214 + cursor: pointer; 215 + display: flex; 216 + align-items: center; 217 + justify-content: center; 218 + border-radius: 50%; 219 + transition: background-color 0.15s ease, transform 0.15s ease; 220 + font-size: 16px; 221 + } 222 + 223 + #prevBtn:hover:not(:disabled), 224 + #nextBtn:hover:not(:disabled) { 225 + background-color: var(--button-hover); 226 + transform: scale(1.05); 227 + } 228 + 229 + #prevBtn:disabled, 230 + #nextBtn:disabled { 231 + opacity: 0.4; 232 + cursor: not-allowed; 233 + } 234 + 235 + #embedVideo { 236 + width: 100%; 237 + max-width: 500px; 238 + margin-top: 12px; 239 + align-self: center; 240 + border-radius: 8px; 241 + overflow: hidden; 242 + } 243 + 244 + #embedImages { 245 + min-width: min(100%, 500px); 246 + max-width: min(100%, 500px); 247 + max-height: 500px; 248 + object-fit: contain; 249 + margin: 0; 250 + border-radius: 8px; 251 + } 252 + 253 + /* Account Component */ 254 + #accountContainer { 255 + display: flex; 256 + text-align: start; 257 + align-items: center; 258 + background-color: var(--content-background-color); 259 + padding: 12px; 260 + margin-bottom: 15px; 261 + border: 1px solid var(--border-color); 262 + border-radius: 12px; 263 + transition: background-color 0.15s ease; 264 + } 265 + 266 + #accountContainer:hover { 267 + background-color: var(--hover-bg); 268 + } 269 + 270 + #accountName { 271 + margin-left: 12px; 272 + font-size: 0.95em; 273 + max-width: 80%; 274 + overflow: hidden; 275 + text-overflow: ellipsis; 276 + white-space: nowrap; 277 + font-weight: 500; 278 + } 279 + 280 + #avatar { 281 + width: 48px; 282 + height: 48px; 283 + margin: 0; 284 + object-fit: cover; 285 + border-radius: 50%; 286 + border: 2px solid white; 287 + box-shadow: 0 1px 3px rgba(0,0,0,0.1); 288 + } 289 + 290 + /* App.Svelte Layout */ 291 + #Content { 292 + display: flex; 293 + width: 100%; 294 + height: 100%; 295 + flex-direction: row; 296 + justify-content: space-between; 297 + align-items: center; 298 + background-color: var(--background-color); 299 + color: var(--text-color); 300 + gap: 24px; 301 + } 302 + 303 + #Feed { 304 + overflow-y: auto; 305 + width: 65%; 306 + height: 100vh; 307 + padding-right: 16px; 308 + align-self: flex-start; 309 + } 310 + 311 + #spacer { 312 + padding: 0; 313 + margin: 0; 314 + height: 10vh; 315 + width: 100%; 316 + } 317 + 318 + #Account { 319 + width: 35%; 320 + display: flex; 321 + flex-direction: column; 322 + border: 1px solid var(--border-color); 323 + background-color: var(--content-background-color); 324 + max-height: 80vh; 325 + padding: 24px; 326 + margin-left: 16px; 327 + border-radius: 12px; 328 + box-shadow: var(--card-shadow); 329 + } 330 + 331 + #accountsList { 332 + display: flex; 333 + flex-direction: column; 334 + overflow-y: auto; 335 + height: 100%; 336 + width: 100%; 337 + padding: 8px 0; 338 + margin: 0; 339 + } 340 + 341 + #Header { 342 + text-align: center; 343 + font-size: 1.8em; 344 + margin-bottom: 16px; 345 + font-weight: 700; 346 + background: linear-gradient(to right, var(--link-color), #8b5cf6); 347 + -webkit-background-clip: text; 348 + -webkit-text-fill-color: transparent; 349 + background-clip: text; 350 + } 351 + 352 + /* Mobile Styles */ 353 + @media screen and (max-width: 768px) { 354 + #Content { 355 + flex-direction: column; 356 + width: auto; 357 + padding: 12px; 358 + margin-top: 0; 359 + } 360 + 361 + #Account { 362 + width: calc(100% - 32px); 363 + padding: 16px; 364 + margin-bottom: 20px; 365 + margin-left: 0; 366 + margin-right: 0; 367 + height: auto; 368 + order: -1; 369 + } 370 + 371 + #Feed { 372 + width: 100%; 373 + margin: 0; 374 + padding: 0; 375 + overflow-y: visible; 376 + } 377 + 378 + #spacer { 379 + height: 5vh; 380 + } 381 + 382 + body { 383 + font-size: 16px; 384 + } 385 + 386 + #postHeader { 387 + padding: 10px; 388 + height: auto; 389 + min-height: 50px; 390 + } 391 + } 392 + 393 + /* Scrollbar Styles */ 394 + ::-webkit-scrollbar { 395 + width: 0px; 396 + background: transparent; 397 + padding: 0; 398 + margin: 0; 399 + } 400 + ::-webkit-scrollbar-thumb { 401 + background: transparent; 402 + border-radius: 0; 403 + } 404 + ::-webkit-scrollbar-track { 405 + background: transparent; 406 + border-radius: 0; 407 + } 408 + ::-webkit-scrollbar-corner { 409 + background: transparent; 410 + border-radius: 0; 411 + } 412 + ::-webkit-scrollbar-button { 413 + background: transparent; 414 + border-radius: 0; 415 + } 416 + 417 + * { 418 + scrollbar-width: none; 419 + scrollbar-color: transparent transparent; 420 + -ms-overflow-style: none; /* IE and Edge */ 421 + -webkit-overflow-scrolling: touch; 422 + -webkit-scrollbar: none; /* Safari */ 423 + }
+375
themes/express/theme.css
··· 1 + @import url("https://fonts.googleapis.com/css2?family=Share+Tech+Mono&display=swap"); 2 + 3 + :root { 4 + /* Color overrides, edit to whatever you want */ 5 + --primary-h: 341; /* Hue */ 6 + --background-color: hsl(var(--primary-h), 62%, 30%); 7 + --text-color: hsl(var(--primary-h), 69%, 18%); 8 + --link-color: hsl(var(--primary-h), 100%, 20%); 9 + --link-hover-color: hsl(var(--primary-h), 20%, 20%); 10 + --border-color: hsl(var(--primary-h), 59%, 52%); 11 + --content-background-color: hsl(var(--primary-h), 97%, 73%); 12 + 13 + --header-background-color: hsl(var(--primary-h), 97%, 73%); 14 + --indicator-inactive-color: #4a4a4a; 15 + --indicator-active-color: var(--border-color); 16 + } 17 + 18 + a { 19 + font-weight: 500; 20 + color: var(--link-color); 21 + text-decoration: inherit; 22 + } 23 + a:hover { 24 + color: var(--link-hover-color); 25 + text-decoration: underline; 26 + } 27 + 28 + body { 29 + margin: 0; 30 + display: flex; 31 + place-items: center; 32 + min-width: 320px; 33 + min-height: 100vh; 34 + background-color: var(--background-color); 35 + font-family: "Share Tech Mono", monospace; 36 + font-size: 24px; 37 + color: var(--text-color); 38 + border-color: var(--border-color); 39 + overflow-wrap: break-word; 40 + word-wrap: normal; 41 + word-break: break-word; 42 + hyphens: none; 43 + } 44 + 45 + h1 { 46 + font-size: 3.2em; 47 + line-height: 1.1; 48 + } 49 + 50 + #app { 51 + max-width: 1400px; 52 + width: 100%; 53 + margin: 0; 54 + padding: 0; 55 + margin-left: auto; 56 + margin-right: auto; 57 + text-align: center; 58 + } 59 + 60 + /* Post Component */ 61 + a:hover { 62 + text-decoration: underline; 63 + } 64 + #postContainer { 65 + display: flex; 66 + flex-direction: column; 67 + border: 4px solid var(--border-color); 68 + background-color: var(--background-color); 69 + margin-bottom: 15px; 70 + overflow-wrap: break-word; 71 + box-shadow: var(--border-color) 10px 10px; 72 + } 73 + #postHeader { 74 + display: flex; 75 + flex-direction: row; 76 + align-items: center; 77 + justify-content: start; 78 + background-color: var(--header-background-color); 79 + padding: 0px 0px; 80 + height: fit-content; 81 + 82 + font-weight: bold; 83 + overflow-wrap: break-word; 84 + height: 64px; 85 + } 86 + #displayName { 87 + display: block; 88 + color: var(--text-color); 89 + font-size: 1.2em; 90 + padding: 0; 91 + margin: 0; 92 + overflow-wrap: normal; 93 + word-wrap: break-word; 94 + word-break: break-word; 95 + text-overflow: ellipsis; 96 + overflow: hidden; 97 + white-space: nowrap; 98 + width: 100%; 99 + } 100 + #handle { 101 + display: block; 102 + color: var(--border-color); 103 + font-size: 0.8em; 104 + padding: 0; 105 + margin: 0; 106 + } 107 + 108 + #postLink { 109 + color: var(--link-hover-color); 110 + font-size: 0.8em; 111 + padding: 0; 112 + margin: 0; 113 + } 114 + #postContent { 115 + display: flex; 116 + text-align: start; 117 + flex-direction: column; 118 + padding: 10px; 119 + background-color: var(--content-background-color); 120 + color: var(--text-color); 121 + overflow-wrap: break-word; 122 + white-space: pre-line; 123 + } 124 + #replyingText { 125 + font-size: 0.7em; 126 + margin: 0; 127 + padding: 0; 128 + padding-bottom: 5px; 129 + } 130 + #quotingText { 131 + font-size: 0.7em; 132 + margin: 0; 133 + padding: 0; 134 + padding-bottom: 5px; 135 + } 136 + #postText { 137 + margin: 0; 138 + padding: 0; 139 + overflow-wrap: break-word; 140 + word-wrap: normal; 141 + word-break: break-word; 142 + hyphens: none; 143 + } 144 + #headerText { 145 + margin-left: 10px; 146 + font-size: 0.9em; 147 + text-align: start; 148 + word-break: break-word; 149 + max-width: 80%; 150 + max-height: 95%; 151 + overflow: hidden; 152 + align-self: flex-start; 153 + margin-top: auto; 154 + margin-bottom: auto; 155 + } 156 + #avatar { 157 + height: 30px; 158 + width: 30px; 159 + overflow: hidden; 160 + object-fit: cover; 161 + } 162 + #postContainer #avatar { 163 + height: 60px; 164 + width: 60px; 165 + border-right: var(--border-color) 4px solid; 166 + border-bottom: var(--border-color) 4px solid; 167 + } 168 + #carouselContainer { 169 + position: relative; 170 + width: 100%; 171 + margin-top: 10px; 172 + display: flex; 173 + flex-direction: column; 174 + align-items: center; 175 + } 176 + #carouselControls { 177 + display: flex; 178 + justify-content: space-between; 179 + align-items: center; 180 + width: 100%; 181 + max-width: 500px; 182 + margin-top: 5px; 183 + } 184 + #carouselIndicators { 185 + display: flex; 186 + gap: 5px; 187 + } 188 + .indicator { 189 + width: 8px; 190 + height: 8px; 191 + background-color: var(--indicator-inactive-color); 192 + } 193 + .indicator.active { 194 + background-color: var(--indicator-active-color); 195 + } 196 + #prevBtn, 197 + #nextBtn { 198 + background-color: rgba(31, 17, 69, 0.7); 199 + color: var(--text-color); 200 + border: 4px solid var(--border-color); 201 + width: 30px; 202 + height: 30px; 203 + cursor: pointer; 204 + display: flex; 205 + align-items: center; 206 + justify-content: center; 207 + } 208 + #prevBtn:disabled, 209 + #nextBtn:disabled { 210 + opacity: 0.5; 211 + cursor: not-allowed; 212 + } 213 + #embedVideo { 214 + width: 100%; 215 + max-width: 500px; 216 + margin-top: 10px; 217 + align-self: center; 218 + } 219 + 220 + #embedImages { 221 + min-width: min(100%, 500px); 222 + max-width: min(100%, 500px); 223 + max-height: 500px; 224 + object-fit: contain; 225 + 226 + margin: 0; 227 + } 228 + 229 + /* Account Component */ 230 + #accountContainer { 231 + display: flex; 232 + text-align: start; 233 + align-items: center; 234 + background-color: var(--header-background-color); 235 + padding: 0px; 236 + margin-bottom: 15px; 237 + margin-right: 4px; 238 + border: 4px solid var(--border-color); 239 + box-shadow: var(--border-color) 10px 10px; 240 + min-height: 30px; 241 + } 242 + #accountName { 243 + margin-left: 10px; 244 + font-size: 1em; 245 + max-width: 80%; 246 + 247 + /* replace overflow with ellipsis */ 248 + overflow: hidden; 249 + text-overflow: ellipsis; 250 + white-space: nowrap; 251 + } 252 + 253 + .no-avatar { 254 + margin-left: 40px !important; 255 + } 256 + 257 + /* App.Svelte */ 258 + /* desktop style */ 259 + 260 + #Content { 261 + display: flex; 262 + /* split the screen in half, left for accounts, right for posts */ 263 + width: 100%; 264 + height: 100%; 265 + flex-direction: row; 266 + justify-content: space-between; 267 + align-items: center; 268 + background-color: var(--background-color); 269 + color: var(--text-color); 270 + } 271 + #Feed { 272 + overflow-y: scroll; 273 + width: 65%; 274 + height: 100vh; 275 + padding: 20px; 276 + padding-bottom: 0; 277 + padding-top: 0; 278 + margin-top: 0; 279 + margin-bottom: 0; 280 + } 281 + #spacer { 282 + padding: 0; 283 + margin: 0; 284 + height: 10vh; 285 + width: 100%; 286 + } 287 + #Account { 288 + width: 35%; 289 + display: flex; 290 + flex-direction: column; 291 + border: 4px solid var(--border-color); 292 + background-color: var(--content-background-color); 293 + box-shadow: var(--border-color) 10px 10px; 294 + height: 80vh; 295 + padding: 20px; 296 + margin-left: 20px; 297 + } 298 + #accountsList { 299 + display: flex; 300 + flex-direction: column; 301 + overflow-y: scroll; 302 + height: 100%; 303 + width: 100%; 304 + padding: 0px; 305 + margin: 0px; 306 + } 307 + 308 + #Header { 309 + text-align: center; 310 + font-size: 2em; 311 + margin-bottom: 20px; 312 + } 313 + 314 + /* mobile style */ 315 + @media screen and (max-width: 600px) { 316 + #Content { 317 + flex-direction: column; 318 + width: auto; 319 + padding-left: 0px; 320 + padding-right: 0px; 321 + margin-top: 5%; 322 + } 323 + #Account { 324 + width: 85%; 325 + padding-left: 5%; 326 + padding-right: 5%; 327 + margin-bottom: 20px; 328 + margin-left: 5%; 329 + margin-right: 5%; 330 + height: auto; 331 + } 332 + #Feed { 333 + width: 95%; 334 + margin: 0px; 335 + margin-left: 10%; 336 + margin-right: 10%; 337 + padding: 0px; 338 + overflow-y: visible; 339 + } 340 + 341 + #spacer { 342 + height: 0; 343 + } 344 + } 345 + 346 + ::-webkit-scrollbar { 347 + width: 0px; 348 + background: transparent; 349 + padding: 0; 350 + margin: 0; 351 + } 352 + ::-webkit-scrollbar-thumb { 353 + background: transparent; 354 + border-radius: 0; 355 + } 356 + ::-webkit-scrollbar-track { 357 + background: transparent; 358 + border-radius: 0; 359 + } 360 + ::-webkit-scrollbar-corner { 361 + background: transparent; 362 + border-radius: 0; 363 + } 364 + ::-webkit-scrollbar-button { 365 + background: transparent; 366 + border-radius: 0; 367 + } 368 + 369 + * { 370 + scrollbar-width: none; 371 + scrollbar-color: transparent transparent; 372 + -ms-overflow-style: none; /* IE and Edge */ 373 + -webkit-overflow-scrolling: touch; 374 + -webkit-scrollbar: none; /* Safari */ 375 + }
+373
themes/witchcraft/theme.css
··· 1 + @font-face { 2 + font-family: "ProggyClean"; 3 + src: url(https://witchcraft.systems/ProggyCleanNerdFont-Regular.ttf); 4 + } 5 + 6 + :root { 7 + /* Color overrides, edit to whatever you want */ 8 + --primary-h: 260; /* Hue */ 9 + 10 + --link-color: hsl(calc(var(--primary-h) - 30), 75%, 60%); 11 + --link-hover-color: hsl(calc(var(--primary-h) - 30), 75%, 50%); 12 + --background-color: hsl(var(--primary-h), 75%, 10%); 13 + --header-background-color: hsl(var(--primary-h), 75%, 18%); 14 + --content-background-color: hsl(var(--primary-h), 75%, 8%); 15 + --text-color: #fff; 16 + --border-color: hsl(var(--primary-h), 75%, 60%); 17 + --indicator-inactive-color: #4a4a4a; 18 + --indicator-active-color: var(--border-color); 19 + } 20 + 21 + 22 + a { 23 + font-weight: 500; 24 + color: var(--link-color); 25 + text-decoration: inherit; 26 + } 27 + a:hover { 28 + color: var(--link-hover-color); 29 + text-decoration: underline; 30 + } 31 + 32 + body { 33 + margin: 0; 34 + display: flex; 35 + place-items: center; 36 + min-width: 320px; 37 + min-height: 100vh; 38 + background-color: var(--background-color); 39 + font-family: "ProggyClean", monospace; 40 + font-size: 24px; 41 + color: var(--text-color); 42 + border-color: var(--border-color); 43 + overflow-wrap: break-word; 44 + word-wrap: normal; 45 + word-break: break-word; 46 + hyphens: none; 47 + } 48 + 49 + h1 { 50 + font-size: 3.2em; 51 + line-height: 1.1; 52 + } 53 + 54 + #app { 55 + max-width: 1400px; 56 + width: 100%; 57 + margin: 0; 58 + padding: 0; 59 + margin-left: auto; 60 + margin-right: auto; 61 + text-align: center; 62 + } 63 + 64 + /* Post Component */ 65 + a:hover { 66 + text-decoration: underline; 67 + } 68 + #postContainer { 69 + display: flex; 70 + flex-direction: column; 71 + border: 1px solid var(--border-color); 72 + background-color: var(--background-color); 73 + margin-bottom: 15px; 74 + overflow-wrap: break-word; 75 + } 76 + #postHeader { 77 + display: flex; 78 + flex-direction: row; 79 + align-items: center; 80 + justify-content: start; 81 + background-color: var(--header-background-color); 82 + padding: 0px 0px; 83 + height: fit-content; 84 + border-bottom: 1px solid var(--border-color); 85 + font-weight: bold; 86 + overflow-wrap: break-word; 87 + height: 60px; 88 + } 89 + #displayName { 90 + display: block; 91 + color: var(--text-color); 92 + font-size: 1.2em; 93 + padding: 0; 94 + margin: 0; 95 + overflow-wrap: normal; 96 + word-wrap: break-word; 97 + word-break: break-word; 98 + text-overflow: ellipsis; 99 + overflow: hidden; 100 + white-space: nowrap; 101 + width: 100%; 102 + } 103 + #handle { 104 + display: block; 105 + color: var(--border-color); 106 + font-size: 0.8em; 107 + padding: 0; 108 + margin: 0; 109 + } 110 + 111 + #postLink { 112 + color: var(--border-color); 113 + font-size: 0.8em; 114 + padding: 0; 115 + margin: 0; 116 + } 117 + #postContent { 118 + display: flex; 119 + text-align: start; 120 + flex-direction: column; 121 + padding: 10px; 122 + background-color: var(--content-background-color); 123 + color: var(--text-color); 124 + overflow-wrap: break-word; 125 + white-space: pre-line; 126 + } 127 + #replyingText { 128 + font-size: 0.7em; 129 + margin: 0; 130 + padding: 0; 131 + padding-bottom: 5px; 132 + } 133 + #quotingText { 134 + font-size: 0.7em; 135 + margin: 0; 136 + padding: 0; 137 + padding-bottom: 5px; 138 + } 139 + #postText { 140 + margin: 0; 141 + padding: 0; 142 + overflow-wrap: break-word; 143 + word-wrap: normal; 144 + word-break: break-word; 145 + hyphens: none; 146 + } 147 + #headerText { 148 + margin-left: 10px; 149 + font-size: 0.9em; 150 + text-align: start; 151 + word-break: break-word; 152 + max-width: 80%; 153 + max-height: 95%; 154 + overflow: hidden; 155 + align-self: flex-start; 156 + margin-top: auto; 157 + margin-bottom: auto; 158 + } 159 + #avatar { 160 + height: 60px; 161 + width: 60px; 162 + margin: 0px; 163 + margin-left: 0px; 164 + overflow: hidden; 165 + object-fit: cover; 166 + border-right: var(--border-color) 1px solid; 167 + } 168 + #carouselContainer { 169 + position: relative; 170 + width: 100%; 171 + margin-top: 10px; 172 + display: flex; 173 + flex-direction: column; 174 + align-items: center; 175 + } 176 + #carouselControls { 177 + display: flex; 178 + justify-content: space-between; 179 + align-items: center; 180 + width: 100%; 181 + max-width: 500px; 182 + margin-top: 5px; 183 + } 184 + #carouselIndicators { 185 + display: flex; 186 + gap: 5px; 187 + } 188 + .indicator { 189 + width: 8px; 190 + height: 8px; 191 + background-color: var(--indicator-inactive-color); 192 + } 193 + .indicator.active { 194 + background-color: var(--indicator-active-color); 195 + } 196 + #prevBtn, 197 + #nextBtn { 198 + background-color: rgba(31, 17, 69, 0.7); 199 + color: var(--text-color); 200 + border: 1px solid var(--border-color); 201 + width: 30px; 202 + height: 30px; 203 + cursor: pointer; 204 + display: flex; 205 + align-items: center; 206 + justify-content: center; 207 + } 208 + #prevBtn:disabled, 209 + #nextBtn:disabled { 210 + opacity: 0.5; 211 + cursor: not-allowed; 212 + } 213 + #embedVideo { 214 + width: 100%; 215 + max-width: 500px; 216 + margin-top: 10px; 217 + align-self: center; 218 + } 219 + 220 + #embedImages { 221 + min-width: min(100%, 500px); 222 + max-width: min(100%, 500px); 223 + max-height: 500px; 224 + object-fit: contain; 225 + 226 + margin: 0; 227 + } 228 + 229 + /* Account Component */ 230 + #accountContainer { 231 + display: flex; 232 + text-align: start; 233 + align-items: center; 234 + background-color: var(--background-color); 235 + padding: 0px; 236 + margin-bottom: 15px; 237 + border: 1px solid var(--border-color); 238 + min-height: 30px; 239 + } 240 + #accountName { 241 + margin-left: 10px; 242 + font-size: 1em; 243 + max-width: 80%; 244 + 245 + /* replace overflow with ellipsis */ 246 + overflow: hidden; 247 + text-overflow: ellipsis; 248 + white-space: nowrap; 249 + } 250 + 251 + 252 + .no-avatar { 253 + margin-left: 70px !important; 254 + } 255 + 256 + /* App.Svelte */ 257 + /* desktop style */ 258 + 259 + #Content { 260 + display: flex; 261 + /* split the screen in half, left for accounts, right for posts */ 262 + width: 100%; 263 + height: 100%; 264 + flex-direction: row; 265 + justify-content: space-between; 266 + align-items: center; 267 + background-color: var(--background-color); 268 + color: var(--text-color); 269 + } 270 + #Feed { 271 + overflow-y: scroll; 272 + width: 65%; 273 + height: 100vh; 274 + padding: 20px; 275 + padding-bottom: 0; 276 + padding-top: 0; 277 + margin-top: 0; 278 + margin-bottom: 0; 279 + } 280 + #spacer { 281 + padding: 0; 282 + margin: 0; 283 + height: 10vh; 284 + width: 100%; 285 + } 286 + #Account { 287 + width: 35%; 288 + display: flex; 289 + flex-direction: column; 290 + border: 1px solid var(--border-color); 291 + background-color: var(--content-background-color); 292 + height: 80vh; 293 + padding: 20px; 294 + margin-left: 20px; 295 + } 296 + #accountsList { 297 + display: flex; 298 + flex-direction: column; 299 + overflow-y: scroll; 300 + height: 100%; 301 + width: 100%; 302 + padding: 0px; 303 + margin: 0px; 304 + } 305 + 306 + #Header { 307 + text-align: center; 308 + font-size: 2em; 309 + margin-bottom: 20px; 310 + } 311 + 312 + /* mobile style */ 313 + @media screen and (max-width: 600px) { 314 + #Content { 315 + flex-direction: column; 316 + width: auto; 317 + padding-left: 0px; 318 + padding-right: 0px; 319 + margin-top: 5%; 320 + } 321 + #Account { 322 + width: 85%; 323 + padding-left: 5%; 324 + padding-right: 5%; 325 + margin-bottom: 20px; 326 + margin-left: 5%; 327 + margin-right: 5%; 328 + height: auto; 329 + } 330 + #Feed { 331 + width: 95%; 332 + margin: 0px; 333 + margin-left: 10%; 334 + margin-right: 10%; 335 + padding: 0px; 336 + overflow-y: visible; 337 + } 338 + 339 + #spacer { 340 + height: 0; 341 + } 342 + } 343 + 344 + ::-webkit-scrollbar { 345 + width: 0px; 346 + background: transparent; 347 + padding: 0; 348 + margin: 0; 349 + } 350 + ::-webkit-scrollbar-thumb { 351 + background: transparent; 352 + border-radius: 0; 353 + } 354 + ::-webkit-scrollbar-track { 355 + background: transparent; 356 + border-radius: 0; 357 + } 358 + ::-webkit-scrollbar-corner { 359 + background: transparent; 360 + border-radius: 0; 361 + } 362 + ::-webkit-scrollbar-button { 363 + background: transparent; 364 + border-radius: 0; 365 + } 366 + 367 + * { 368 + scrollbar-width: none; 369 + scrollbar-color: transparent transparent; 370 + -ms-overflow-style: none; /* IE and Edge */ 371 + -webkit-overflow-scrolling: touch; 372 + -webkit-scrollbar: none; /* Safari */ 373 + }
+32
theming.ts
··· 1 + import { Plugin } from 'vite'; 2 + import { Config } from './config'; 3 + 4 + 5 + // Replaces app.css with the contents of the file specified in the 6 + // config file. 7 + export const themePlugin = (): Plugin => { 8 + const themeFolder = Config.THEME; 9 + console.log(`Using theme folder: ${themeFolder}`); 10 + return { 11 + name: 'theme-generator', 12 + enforce: 'pre', // Ensure this plugin runs first 13 + transform(code, id) { 14 + if (id.endsWith('app.css')) { 15 + // Read the theme file and replace the contents of app.css with it 16 + // Needs full path to the file 17 + const themeCode = Deno.readTextFileSync(Deno.cwd() + '/themes/' + themeFolder + '/theme.css'); 18 + // Replace the contents of app.css with the theme code 19 + 20 + // and add a comment at the top 21 + const themeComment = `/* Generated from ${themeFolder} */\n`; 22 + const themeCodeWithComment = themeComment + themeCode; 23 + // Return the theme code as the new contents of app.css 24 + return { 25 + code: themeCodeWithComment, 26 + map: null, 27 + }; 28 + } 29 + return null; 30 + } 31 + }; 32 + };
+5 -1
vite.config.ts
··· 1 1 import { defineConfig } from "vite"; 2 2 import { svelte } from "@sveltejs/vite-plugin-svelte"; 3 + import { themePlugin } from "./theming"; 3 4 4 5 // https://vite.dev/config/ 5 6 export default defineConfig({ 6 - plugins: [svelte()], 7 + plugins: [ 8 + themePlugin(), 9 + svelte(), 10 + ], 7 11 });