See the best posts from any Bluesky account
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Move sign-out to own profile page, cache mounts in Dockerfile

- Remove sign-out from header, keep only "My profile" / "Sign in"
- Show sign-out button on your own profile page next to profile details
- Add pnpm store cache mounts to Dockerfile for faster builds

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+47 -18
+23
.adonisjs/server/routes.d.ts
··· 12 12 'profile.likes': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 13 13 'profile.reposts': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 14 14 'profile.backfill.stream': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 15 + 'oauth.clientMetadata': { paramsTuple?: []; params?: {} } 16 + 'oauth.login': { paramsTuple?: []; params?: {} } 17 + 'oauth.callback': { paramsTuple?: []; params?: {} } 18 + 'oauth.logout': { paramsTuple?: []; params?: {} } 19 + 'api.like.create': { paramsTuple?: []; params?: {} } 20 + 'api.like.delete': { paramsTuple?: []; params?: {} } 21 + 'api.repost.create': { paramsTuple?: []; params?: {} } 22 + 'api.repost.delete': { paramsTuple?: []; params?: {} } 15 23 'health.live': { paramsTuple?: []; params?: {} } 16 24 'health.ready': { paramsTuple?: []; params?: {} } 17 25 } ··· 24 32 'profile.likes': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 25 33 'profile.reposts': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 26 34 'profile.backfill.stream': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 35 + 'oauth.clientMetadata': { paramsTuple?: []; params?: {} } 36 + 'oauth.login': { paramsTuple?: []; params?: {} } 37 + 'oauth.callback': { paramsTuple?: []; params?: {} } 27 38 'health.live': { paramsTuple?: []; params?: {} } 28 39 'health.ready': { paramsTuple?: []; params?: {} } 29 40 } ··· 36 47 'profile.likes': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 37 48 'profile.reposts': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 38 49 'profile.backfill.stream': { paramsTuple: [ParamValue]; params: {'handle': ParamValue} } 50 + 'oauth.clientMetadata': { paramsTuple?: []; params?: {} } 51 + 'oauth.login': { paramsTuple?: []; params?: {} } 52 + 'oauth.callback': { paramsTuple?: []; params?: {} } 39 53 'health.live': { paramsTuple?: []; params?: {} } 40 54 'health.ready': { paramsTuple?: []; params?: {} } 55 + } 56 + POST: { 57 + 'oauth.logout': { paramsTuple?: []; params?: {} } 58 + 'api.like.create': { paramsTuple?: []; params?: {} } 59 + 'api.repost.create': { paramsTuple?: []; params?: {} } 60 + } 61 + DELETE: { 62 + 'api.like.delete': { paramsTuple?: []; params?: {} } 63 + 'api.repost.delete': { paramsTuple?: []; params?: {} } 41 64 } 42 65 } 43 66 declare module '@adonisjs/core/types/http' {
+4 -2
Dockerfile
··· 12 12 13 13 # Copy package manifest + lockfile for layer caching 14 14 COPY package.json pnpm-lock.yaml ./ 15 - RUN NODE_ENV=development pnpm install --frozen-lockfile 15 + RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \ 16 + NODE_ENV=development pnpm install --frozen-lockfile 16 17 17 18 # Copy source and build the Adonis app 18 19 COPY . . ··· 28 29 # The build directory is self-contained (JS + package.json + lockfile). 29 30 # Copy it as the application root and install only production dependencies. 30 31 COPY --from=build --chown=node:node /app/build ./ 31 - RUN pnpm install --frozen-lockfile --prod 32 + RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \ 33 + pnpm install --frozen-lockfile --prod 32 34 33 35 # Ensure the SQLite data directory exists and is writable by the non-root user 34 36 RUN mkdir -p /data && chown node:node /data
+20 -12
resources/views/pages/profile/show.edge
··· 6 6 @slot('main') 7 7 <div class="pt-8 pb-4"> 8 8 {{-- Profile header --}} 9 - <a href="https://bsky.app/profile/{{ handle }}" target="_blank" rel="noopener" class="group flex items-center gap-4 mb-6 no-underline"> 10 - @if(avatarUrl) 11 - <img src="{{ avatarUrl }}" alt="" class="size-14 rounded-full shrink-0 object-cover"> 12 - @else 13 - <div class="size-14 rounded-full bg-gray-300 dark:bg-gray-700 shrink-0 flex items-center justify-center text-xl text-gray-400">@</div> 14 - @endif 15 - <div> 16 - @if(displayName) 17 - <div class="font-heading text-xl font-bold group-hover:underline leading-tight">{{ displayName }}</div> 9 + <div class="flex items-center justify-between mb-6"> 10 + <a href="https://bsky.app/profile/{{ handle }}" target="_blank" rel="noopener" class="group flex items-center gap-4 no-underline"> 11 + @if(avatarUrl) 12 + <img src="{{ avatarUrl }}" alt="" class="size-14 rounded-full shrink-0 object-cover"> 13 + @else 14 + <div class="size-14 rounded-full bg-gray-300 dark:bg-gray-700 shrink-0 flex items-center justify-center text-xl text-gray-400">@</div> 18 15 @endif 19 - <div class="text-gray-600 dark:text-gray-400 group-hover:underline">{{ '@' + handle }}</div> 20 - </div> 21 - </a> 16 + <div> 17 + @if(displayName) 18 + <div class="font-heading text-xl font-bold group-hover:underline leading-tight">{{ displayName }}</div> 19 + @endif 20 + <div class="text-gray-600 dark:text-gray-400 group-hover:underline">{{ '@' + handle }}</div> 21 + </div> 22 + </a> 23 + @if(auth.isAuthenticated && auth.user.handle === handle) 24 + <form action="/oauth/logout" method="POST"> 25 + {{ csrfField() }} 26 + <button type="submit" class="text-sm text-gray-500 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-400 transition-colors duration-200 cursor-pointer">Sign out</button> 27 + </form> 28 + @endif 29 + </div> 22 30 23 31 {{-- Controls --}} 24 32 <div class="flex items-center justify-between mb-6 flex-wrap gap-6">
-4
resources/views/partials/auth_buttons.edge
··· 4 4 href="/profile/{{ auth.user.handle }}/likes" 5 5 class="text-sm text-gray-600 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200" 6 6 >My profile</a> 7 - <form action="/oauth/logout" method="POST" class="inline"> 8 - {{ csrfField() }} 9 - <button type="submit" class="text-sm text-gray-600 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors duration-200 cursor-pointer">Sign out</button> 10 - </form> 11 7 @else 12 8 <a 13 9 href="/oauth/login"