See the best posts from any Bluesky account
0
fork

Configure Feed

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

Use consistent red heart logo on landing page and fix CSP for Vite HMR

Replace blue star with red heart icon on landing page to match navbar.
Update landing copy to "most popular posts". Add nonce to Vite script
tags and allow Vite dev server websocket in CSP connect-src.

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

+9 -75
+3 -68
config/shield.ts
··· 1 + import app from '@adonisjs/core/services/app' 1 2 import { defineConfig } from '@adonisjs/shield' 2 3 3 - /** 4 - * Security configuration using Shield. 5 - * Provides protection against common web vulnerabilities like CSRF, 6 - * XSS, clickjacking, and other security threats. 7 - */ 8 4 const shieldConfig = defineConfig({ 9 - /** 10 - * Configure CSP policies for your app. Refer documentation 11 - * to learn more 12 - */ 13 5 csp: { 14 6 enabled: true, 15 7 directives: { 16 8 defaultSrc: [`'self'`], 17 - scriptSrc: [`'self'`, `@nonce`], 9 + scriptSrc: [`'self'`, '@nonce'], 18 10 styleSrc: [`'self'`, `'unsafe-inline'`, 'https://cdn.jsdelivr.net'], 19 11 imgSrc: [`'self'`, 'data:', 'https://cdn.bsky.app', 'https://video.bsky.app'], 20 - connectSrc: [`'self'`], 12 + connectSrc: app.inDev ? [`'self'`, '@viteUrl', 'ws://localhost:*'] : [`'self'`], 21 13 fontSrc: [`'self'`, 'https://cdn.jsdelivr.net'], 22 14 objectSrc: [`'none'`], 23 15 baseUri: [`'self'`], ··· 27 19 reportOnly: false, 28 20 }, 29 21 30 - /** 31 - * Configure CSRF protection options. Refer documentation 32 - * to learn more 33 - */ 34 22 csrf: { 35 - /** 36 - * Enable CSRF protection. 37 - * Protects against Cross-Site Request Forgery attacks. 38 - */ 39 23 enabled: true, 40 - 41 - /** 42 - * Routes that should be excluded from CSRF protection. 43 - * Useful for webhooks or API endpoints that use other auth methods. 44 - */ 45 24 exceptRoutes: [], 46 - 47 - /** 48 - * Enable XSRF-TOKEN cookie for JavaScript frameworks. 49 - * When enabled, the CSRF token is available to client-side code. 50 - */ 51 25 enableXsrfCookie: false, 52 - 53 - /** 54 - * HTTP methods that require CSRF token validation. 55 - * GET, HEAD, and OPTIONS are safe methods and don't need protection. 56 - */ 57 26 methods: ['POST', 'PUT', 'PATCH', 'DELETE'], 58 27 }, 59 28 60 - /** 61 - * Control how your website should be embedded inside 62 - * iFrames 63 - */ 64 29 xFrame: { 65 - /** 66 - * Enable X-Frame-Options header. 67 - * Helps prevent clickjacking attacks. 68 - */ 69 30 enabled: true, 70 - 71 - /** 72 - * Frame embedding policy. 73 - * It can block all framing with 'DENY' or allow same-origin framing 74 - * with 'SAMEORIGIN'. 75 - */ 76 31 action: 'DENY', 77 32 }, 78 33 79 - /** 80 - * Force browser to always use HTTPS 81 - */ 82 34 hsts: { 83 - /** 84 - * Enable HTTP Strict Transport Security. 85 - * Tells browsers to always use HTTPS for this site. 86 - */ 87 35 enabled: true, 88 - 89 - /** 90 - * How long browsers should remember to use HTTPS. 91 - * After this period, browsers may try HTTP again. 92 - */ 93 36 maxAge: '180 days', 94 37 }, 95 38 96 - /** 97 - * Disable browsers from sniffing the content type of a 98 - * response and always rely on the "content-type" header. 99 - */ 100 39 contentTypeSniffing: { 101 - /** 102 - * Enable X-Content-Type-Options: nosniff header. 103 - * Prevents MIME type sniffing which can lead to security vulnerabilities. 104 - */ 105 40 enabled: true, 106 41 }, 107 42 })
-4
config/vite.ts
··· 28 28 * HTML attributes to add to script tags generated by Vite. 29 29 */ 30 30 scriptAttributes: { 31 - /** 32 - * Defer script execution until the HTML is fully parsed. 33 - * Improves page load performance. 34 - */ 35 31 defer: true, 36 32 }, 37 33 })
+1 -1
resources/views/components/layout.edge
··· 7 7 <script nonce="{{ cspNonce }}"> 8 8 (function(){if(document.cookie.indexOf('theme=')!==-1)return;var d=window.matchMedia('(prefers-color-scheme: dark)').matches;var v=d?'dark':'light';document.cookie='theme='+v+';path=/;max-age=31536000;SameSite=Lax';if(d)document.documentElement.classList.add('dark')})() 9 9 </script> 10 - @vite(['resources/css/app.css', 'resources/js/app.js']) 10 + @vite(['resources/css/app.css', 'resources/js/app.js'], { nonce: cspNonce }) 11 11 <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@phosphor-icons/web@2.1.2/src/fill/style.css" /> 12 12 <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@phosphor-icons/web@2.1.2/src/bold/style.css" /> 13 13 @if($slots.head)
+5 -2
resources/views/pages/landing.edge
··· 2 2 @slot('main') 3 3 <div class="pt-16 pb-12"> 4 4 <div class="flex items-center justify-between mb-2"> 5 - <h1 class="text-3xl font-bold">favs.blue <span class="text-blue-500">✦</span></h1> 5 + <h1 class="text-3xl font-bold flex items-center gap-2"> 6 + <i class="ph-fill ph-heart text-red-500"></i> 7 + favs.blue 8 + </h1> 6 9 <button 7 10 x-data="darkMode" 8 11 x-on:click="toggle" ··· 14 17 </button> 15 18 </div> 16 19 <p class="text-lg text-gray-600 dark:text-gray-400 mb-10"> 17 - See any Bluesky account's most-liked and most-reposted posts. 20 + See any Bluesky account's most popular posts. 18 21 </p> 19 22 20 23 <form action="/search" method="GET" class="mb-4">