[WIP] music platform user data scraper
teal-fm atproto

convert to tailwindcss styles

Changed files
+291 -303
pages
-125
pages/static/base.css
··· 1 1 @import "tailwindcss"; 2 - 3 - body { 4 - font-family: Arial, sans-serif; 5 - max-width: 800px; 6 - margin: 0 auto; 7 - padding: 20px; 8 - line-height: 1.6; 9 - } 10 - 11 - 12 - h1 { 13 - color: #1DB954; /* Spotify green */ 14 - } 15 - 16 - .nav { 17 - display: flex; 18 - flex-wrap: wrap; /* Allow wrapping on smaller screens */ 19 - margin-bottom: 20px; 20 - } 21 - 22 - .nav a { 23 - margin-right: 15px; 24 - margin-bottom: 5px; /* Add spacing below links */ 25 - text-decoration: none; 26 - color: #1DB954; 27 - font-weight: bold; 28 - } 29 - 30 - .card { 31 - border: 1px solid #ddd; 32 - border-radius: 8px; 33 - padding: 20px; 34 - margin-bottom: 20px; 35 - } 36 - 37 - .service-status { 38 - font-style: italic; 39 - color: #555; 40 - } 41 - 42 - 43 - label, input { 44 - display: block; 45 - margin-bottom: 10px; 46 - } 47 - 48 - input[type='text'] { 49 - width: 95%; 50 - padding: 8px; 51 - } 52 - 53 - /* Corrected width */ 54 - input[type='submit'] { 55 - padding: 10px 15px; 56 - color: white; 57 - border: none; 58 - border-radius: 4px; 59 - cursor: pointer; 60 - } 61 - 62 - .last-fm-input { 63 - background-color: #d51007; 64 - } 65 - 66 - .teal-input { 67 - background-color: #1DB954; 68 - } 69 - 70 - .error { 71 - color: red; 72 - margin-bottom: 10px; 73 - } 74 - 75 - .lastfm-form { 76 - max-width: 600px; 77 - margin: 20px auto; 78 - padding: 20px; 79 - border: 1px solid #ddd; 80 - border-radius: 8px; 81 - } 82 - 83 - .card { 84 - border: 1px solid #ddd; 85 - border-radius: 8px; 86 - padding: 20px; 87 - margin-bottom: 20px; 88 - } 89 - table { 90 - width: 100%; 91 - border-collapse: collapse; 92 - } 93 - table th, table td { 94 - padding: 8px; 95 - text-align: left; 96 - border-bottom: 1px solid #ddd; 97 - } 98 - .key-value { 99 - font-family: monospace; 100 - padding: 10px; 101 - background-color: #f5f5f5; 102 - border: 1px solid #ddd; 103 - border-radius: 4px; 104 - word-break: break-all; 105 - } 106 - .new-key-alert { 107 - background-color: #f8f9fa; 108 - border-left: 4px solid #1DB954; 109 - padding: 15px; 110 - margin-bottom: 20px; 111 - } 112 - .btn { 113 - padding: 8px 16px; 114 - background-color: #1DB954; 115 - color: white; 116 - border: none; 117 - border-radius: 4px; 118 - cursor: pointer; 119 - } 120 - .btn-danger { 121 - background-color: #dc3545; 122 - } 123 - 124 - .teal-header { 125 - color: #1DB954; 126 - }
+220 -107
pages/static/main.css
··· 7 7 "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 8 8 --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", 9 9 "Courier New", monospace; 10 + --color-gray-100: oklch(96.7% 0.003 264.542); 11 + --color-gray-200: oklch(92.8% 0.006 264.531); 12 + --color-gray-300: oklch(87.2% 0.01 258.338); 13 + --color-gray-600: oklch(44.6% 0.03 256.802); 14 + --color-white: #fff; 15 + --spacing: 0.25rem; 16 + --text-lg: 1.125rem; 17 + --text-lg--line-height: calc(1.75 / 1.125); 18 + --text-xl: 1.25rem; 19 + --text-xl--line-height: calc(1.75 / 1.25); 20 + --font-weight-semibold: 600; 21 + --font-weight-bold: 700; 22 + --leading-relaxed: 1.625; 23 + --radius-lg: 0.5rem; 10 24 --default-font-family: var(--font-sans); 11 25 --default-mono-font-family: var(--font-mono); 12 26 } ··· 190 204 max-width: 96rem; 191 205 } 192 206 } 207 + .mx-auto { 208 + margin-inline: auto; 209 + } 210 + .my-5 { 211 + margin-block: calc(var(--spacing) * 5); 212 + } 213 + .mt-1 { 214 + margin-top: calc(var(--spacing) * 1); 215 + } 216 + .mt-3 { 217 + margin-top: calc(var(--spacing) * 3); 218 + } 219 + .mb-1 { 220 + margin-bottom: calc(var(--spacing) * 1); 221 + } 222 + .mb-2 { 223 + margin-bottom: calc(var(--spacing) * 2); 224 + } 225 + .mb-3 { 226 + margin-bottom: calc(var(--spacing) * 3); 227 + } 228 + .mb-4 { 229 + margin-bottom: calc(var(--spacing) * 4); 230 + } 231 + .mb-5 { 232 + margin-bottom: calc(var(--spacing) * 5); 233 + } 193 234 .block { 194 235 display: block; 195 236 } 196 237 .contents { 197 238 display: contents; 198 239 } 240 + .flex { 241 + display: flex; 242 + } 199 243 .hidden { 200 244 display: none; 201 245 } 202 246 .table { 203 247 display: table; 204 248 } 249 + .w-\[95\%\] { 250 + width: 95%; 251 + } 252 + .w-full { 253 + width: 100%; 254 + } 255 + .max-w-\[600px\] { 256 + max-width: 600px; 257 + } 258 + .max-w-\[800px\] { 259 + max-width: 800px; 260 + } 261 + .border-collapse { 262 + border-collapse: collapse; 263 + } 205 264 .transform { 206 265 transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,); 207 266 } 267 + .cursor-pointer { 268 + cursor: pointer; 269 + } 270 + .list-disc { 271 + list-style-type: disc; 272 + } 273 + .flex-wrap { 274 + flex-wrap: wrap; 275 + } 276 + .space-y-2 { 277 + :where(& > :not(:last-child)) { 278 + --tw-space-y-reverse: 0; 279 + margin-block-start: calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse)); 280 + margin-block-end: calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse))); 281 + } 282 + } 283 + .gap-x-4 { 284 + column-gap: calc(var(--spacing) * 4); 285 + } 286 + .gap-y-1 { 287 + row-gap: calc(var(--spacing) * 1); 288 + } 289 + .rounded { 290 + border-radius: 0.25rem; 291 + } 292 + .rounded-lg { 293 + border-radius: var(--radius-lg); 294 + } 295 + .border { 296 + border-style: var(--tw-border-style); 297 + border-width: 1px; 298 + } 299 + .border-b { 300 + border-bottom-style: var(--tw-border-style); 301 + border-bottom-width: 1px; 302 + } 303 + .border-l-4 { 304 + border-left-style: var(--tw-border-style); 305 + border-left-width: 4px; 306 + } 307 + .border-\[\#1DB954\] { 308 + border-color: #1DB954; 309 + } 310 + .border-gray-200 { 311 + border-color: var(--color-gray-200); 312 + } 313 + .border-gray-300 { 314 + border-color: var(--color-gray-300); 315 + } 316 + .bg-\[\#1DB954\] { 317 + background-color: #1DB954; 318 + } 319 + .bg-\[\#d51007\] { 320 + background-color: #d51007; 321 + } 322 + .bg-\[\#dc3545\] { 323 + background-color: #dc3545; 324 + } 325 + .bg-gray-100 { 326 + background-color: var(--color-gray-100); 327 + } 328 + .p-2 { 329 + padding: calc(var(--spacing) * 2); 330 + } 331 + .p-4 { 332 + padding: calc(var(--spacing) * 4); 333 + } 334 + .p-5 { 335 + padding: calc(var(--spacing) * 5); 336 + } 337 + .px-3 { 338 + padding-inline: calc(var(--spacing) * 3); 339 + } 340 + .px-4 { 341 + padding-inline: calc(var(--spacing) * 4); 342 + } 343 + .py-1\.5 { 344 + padding-block: calc(var(--spacing) * 1.5); 345 + } 346 + .py-2 { 347 + padding-block: calc(var(--spacing) * 2); 348 + } 349 + .py-2\.5 { 350 + padding-block: calc(var(--spacing) * 2.5); 351 + } 352 + .pl-5 { 353 + padding-left: calc(var(--spacing) * 5); 354 + } 355 + .text-left { 356 + text-align: left; 357 + } 358 + .font-mono { 359 + font-family: var(--font-mono); 360 + } 361 + .font-sans { 362 + font-family: var(--font-sans); 363 + } 364 + .text-lg { 365 + font-size: var(--text-lg); 366 + line-height: var(--tw-leading, var(--text-lg--line-height)); 367 + } 368 + .text-xl { 369 + font-size: var(--text-xl); 370 + line-height: var(--tw-leading, var(--text-xl--line-height)); 371 + } 372 + .leading-relaxed { 373 + --tw-leading: var(--leading-relaxed); 374 + line-height: var(--leading-relaxed); 375 + } 376 + .font-bold { 377 + --tw-font-weight: var(--font-weight-bold); 378 + font-weight: var(--font-weight-bold); 379 + } 380 + .font-semibold { 381 + --tw-font-weight: var(--font-weight-semibold); 382 + font-weight: var(--font-weight-semibold); 383 + } 384 + .text-\[\#1DB954\] { 385 + color: #1DB954; 386 + } 387 + .text-gray-600 { 388 + color: var(--color-gray-600); 389 + } 390 + .text-white { 391 + color: var(--color-white); 392 + } 208 393 .lowercase { 209 394 text-transform: lowercase; 210 395 } 396 + .italic { 397 + font-style: italic; 398 + } 399 + .no-underline { 400 + text-decoration-line: none; 401 + } 211 402 .filter { 212 403 filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); 213 404 } 214 - } 215 - body { 216 - font-family: Arial, sans-serif; 217 - max-width: 800px; 218 - margin: 0 auto; 219 - padding: 20px; 220 - line-height: 1.6; 221 - } 222 - h1 { 223 - color: #1DB954; 224 - } 225 - .nav { 226 - display: flex; 227 - flex-wrap: wrap; 228 - margin-bottom: 20px; 229 - } 230 - .nav a { 231 - margin-right: 15px; 232 - margin-bottom: 5px; 233 - text-decoration: none; 234 - color: #1DB954; 235 - font-weight: bold; 236 - } 237 - .card { 238 - border: 1px solid #ddd; 239 - border-radius: 8px; 240 - padding: 20px; 241 - margin-bottom: 20px; 242 - } 243 - .service-status { 244 - font-style: italic; 245 - color: #555; 246 - } 247 - label, input { 248 - display: block; 249 - margin-bottom: 10px; 250 - } 251 - input[type='text'] { 252 - width: 95%; 253 - padding: 8px; 254 - } 255 - input[type='submit'] { 256 - padding: 10px 15px; 257 - color: white; 258 - border: none; 259 - border-radius: 4px; 260 - cursor: pointer; 261 - } 262 - .last-fm-input { 263 - background-color: #d51007; 264 - } 265 - .teal-input { 266 - background-color: #1DB954; 267 - } 268 - .error { 269 - color: red; 270 - margin-bottom: 10px; 271 - } 272 - .lastfm-form { 273 - max-width: 600px; 274 - margin: 20px auto; 275 - padding: 20px; 276 - border: 1px solid #ddd; 277 - border-radius: 8px; 278 - } 279 - .card { 280 - border: 1px solid #ddd; 281 - border-radius: 8px; 282 - padding: 20px; 283 - margin-bottom: 20px; 284 - } 285 - table { 286 - width: 100%; 287 - border-collapse: collapse; 288 - } 289 - table th, table td { 290 - padding: 8px; 291 - text-align: left; 292 - border-bottom: 1px solid #ddd; 293 - } 294 - .key-value { 295 - font-family: monospace; 296 - padding: 10px; 297 - background-color: #f5f5f5; 298 - border: 1px solid #ddd; 299 - border-radius: 4px; 300 - word-break: break-all; 301 - } 302 - .new-key-alert { 303 - background-color: #f8f9fa; 304 - border-left: 4px solid #1DB954; 305 - padding: 15px; 306 - margin-bottom: 20px; 307 - } 308 - .btn { 309 - padding: 8px 16px; 310 - background-color: #1DB954; 311 - color: white; 312 - border: none; 313 - border-radius: 4px; 314 - cursor: pointer; 315 - } 316 - .btn-danger { 317 - background-color: #dc3545; 318 - } 319 - .teal-header { 320 - color: #1DB954; 405 + .hover\:opacity-90 { 406 + &:hover { 407 + @media (hover: hover) { 408 + opacity: 90%; 409 + } 410 + } 411 + } 321 412 } 322 413 @property --tw-rotate-x { 323 414 syntax: "*"; ··· 336 427 inherits: false; 337 428 } 338 429 @property --tw-skew-y { 430 + syntax: "*"; 431 + inherits: false; 432 + } 433 + @property --tw-space-y-reverse { 434 + syntax: "*"; 435 + inherits: false; 436 + initial-value: 0; 437 + } 438 + @property --tw-border-style { 439 + syntax: "*"; 440 + inherits: false; 441 + initial-value: solid; 442 + } 443 + @property --tw-leading { 444 + syntax: "*"; 445 + inherits: false; 446 + } 447 + @property --tw-font-weight { 339 448 syntax: "*"; 340 449 inherits: false; 341 450 } ··· 400 509 --tw-rotate-z: initial; 401 510 --tw-skew-x: initial; 402 511 --tw-skew-y: initial; 512 + --tw-space-y-reverse: 0; 513 + --tw-border-style: solid; 514 + --tw-leading: initial; 515 + --tw-font-weight: initial; 403 516 --tw-blur: initial; 404 517 --tw-brightness: initial; 405 518 --tw-contrast: initial;
+32 -32
pages/templates/apiKeys.gohtml
··· 4 4 {{ template "components/navBar" .NavBar }} 5 5 6 6 7 - <h1>API Key Management</h1> 7 + <h1 class="text-[#1DB954]">API Key Management</h1> 8 8 9 - <div class="card"> 10 - <h2 class="teal-header">Create New API Key</h2> 11 - <p>API keys allow programmatic access to your Piper account data.</p> 9 + <div class="border border-gray-300 rounded-lg p-5 mb-5"> 10 + <h2 class="text-[#1DB954] text-xl font-semibold mb-2">Create New API Key</h2> 11 + <p class="mb-3">API keys allow programmatic access to your Piper account data.</p> 12 12 <form method="POST" action="/api-keys"> 13 - <div style="margin-bottom: 15px;"> 14 - <label for="name">Key Name (for your reference):</label> 15 - <input type="text" id="name" name="name" placeholder="My Application" style="width: 100%; padding: 8px; margin-top: 5px;"> 13 + <div class="mb-4"> 14 + <label class="block" for="name">Key Name (for your reference):</label> 15 + <input class="mt-1 w-full p-2 border border-gray-300 rounded" type="text" id="name" name="name" placeholder="My Application"> 16 16 </div> 17 - <button type="submit" class="btn">Generate New API Key</button> 17 + <button type="submit" class="bg-[#1DB954] text-white px-4 py-2 rounded cursor-pointer hover:opacity-90">Generate New API Key</button> 18 18 </form> 19 19 </div> 20 20 21 21 {{if .NewKeyID}} <!-- Changed from .NewKey to .NewKeyID for clarity --> 22 - <div class="new-key-alert"> 23 - <h3 class="teal-header">Your new API key (ID: {{.NewKeyID}}) has been created</h3> 22 + <div class="bg-gray-100 border-l-4 border-[#1DB954] p-4 mb-5"> 23 + <h3 class="text-[#1DB954] text-lg font-semibold mb-1">Your new API key (ID: {{.NewKeyID}}) has been created</h3> 24 24 <!-- The message below is misleading if only the ID is shown. 25 25 Consider changing this text or modifying the flow to show the actual key once for HTML. --> 26 26 <p><strong>Important:</strong> If this is an ID, ensure you have copied the actual key if it was displayed previously. For keys generated via the API, the key is returned in the API response.</p> 27 27 </div> 28 28 {{end}} 29 29 30 - <div class="card"> 31 - <h2 class="teal-header">Your API Keys</h2> 30 + <div class="border border-gray-300 rounded-lg p-5 mb-5"> 31 + <h2 class="text-[#1DB954] text-xl font-semibold mb-2">Your API Keys</h2> 32 32 {{if .Keys}} 33 - <table> 33 + <table class="w-full border-collapse"> 34 34 <thead> 35 - <tr> 36 - <th>Name</th> 37 - <th>Prefix</th> 38 - <th>Created</th> 39 - <th>Expires</th> 40 - <th>Actions</th> 35 + <tr class="text-left border-b border-gray-300"> 36 + <th class="p-2">Name</th> 37 + <th class="p-2">Prefix</th> 38 + <th class="p-2">Created</th> 39 + <th class="p-2">Expires</th> 40 + <th class="p-2">Actions</th> 41 41 </tr> 42 42 </thead> 43 43 <tbody> 44 44 {{range .Keys}} 45 - <tr> 46 - <td>{{.Name}}</td> 47 - <td>{{.KeyPrefix}}</td> <!-- Added KeyPrefix for better identification --> 48 - <td>{{formatTime .CreatedAt}}</td> 49 - <td>{{formatTime .ExpiresAt}}</td> 50 - <td> 51 - <button class="btn btn-danger" onclick="deleteKey('{{.ID}}')">Delete</button> 45 + <tr class="border-b border-gray-200"> 46 + <td class="p-2">{{.Name}}</td> 47 + <td class="p-2">{{.KeyPrefix}}</td> <!-- Added KeyPrefix for better identification --> 48 + <td class="p-2">{{formatTime .CreatedAt}}</td> 49 + <td class="p-2">{{formatTime .ExpiresAt}}</td> 50 + <td class="p-2"> 51 + <button class="bg-[#dc3545] text-white px-3 py-1.5 rounded cursor-pointer hover:opacity-90" onclick="deleteKey('{{.ID}}')">Delete</button> 52 52 </td> 53 53 </tr> 54 54 {{end}} ··· 59 59 {{end}} 60 60 </div> 61 61 62 - <div class="card"> 63 - <h2 class="teal-header">API Usage</h2> 64 - <p>To use your API key, include it in the Authorization header of your HTTP requests:</p> 65 - <pre>Authorization: Bearer YOUR_API_KEY</pre> 66 - <p>Or include it as a query parameter (less secure for the key itself):</p> 67 - <pre>https://your-piper-instance.com/endpoint?api_key=YOUR_API_KEY</pre> 62 + <div class="border border-gray-300 rounded-lg p-5 mb-5"> 63 + <h2 class="text-[#1DB954] text-xl font-semibold mb-2">API Usage</h2> 64 + <p class="mb-2">To use your API key, include it in the Authorization header of your HTTP requests:</p> 65 + <pre class="font-mono p-2 bg-gray-100 border border-gray-300 rounded">Authorization: Bearer YOUR_API_KEY</pre> 66 + <p class="mt-3 mb-2">Or include it as a query parameter (less secure for the key itself):</p> 67 + <pre class="font-mono p-2 bg-gray-100 border border-gray-300 rounded">https://your-piper-instance.com/endpoint?api_key=YOUR_API_KEY</pre> 68 68 </div> 69 69 70 70 <script>
+11 -11
pages/templates/components/navBar.gohtml
··· 1 1 {{ define "components/navBar" }} 2 2 3 - <div class="nav"> 4 - <a href="/">Home</a> 3 + <nav class="flex flex-wrap mb-5 gap-x-4 gap-y-1"> 4 + <a class="text-[#1DB954] font-bold no-underline" href="/">Home</a> 5 5 6 6 {{if .IsLoggedIn}} 7 - <a href="/current-track">Spotify Current</a> 8 - <a href="/history">Spotify History</a> 9 - <a href="/link-lastfm">Link Last.fm</a> 7 + <a class="text-[#1DB954] font-bold no-underline" href="/current-track">Spotify Current</a> 8 + <a class="text-[#1DB954] font-bold no-underline" href="/history">Spotify History</a> 9 + <a class="text-[#1DB954] font-bold no-underline" href="/link-lastfm">Link Last.fm</a> 10 10 {{ if .LastFMUsername }} 11 - <a href="/lastfm/recent">Last.fm Recent</a> 11 + <a class="text-[#1DB954] font-bold no-underline" href="/lastfm/recent">Last.fm Recent</a> 12 12 {{ end }} 13 - <a href="/api-keys">API Keys</a> 14 - <a href="/login/spotify">Connect Spotify Account</a> 15 - <a href="/logout">Logout</a> 13 + <a class="text-[#1DB954] font-bold no-underline" href="/api-keys">API Keys</a> 14 + <a class="text-[#1DB954] font-bold no-underline" href="/login/spotify">Connect Spotify Account</a> 15 + <a class="text-[#1DB954] font-bold no-underline" href="/logout">Logout</a> 16 16 {{ else }} 17 - <a href="/login/atproto">Login with ATProto</a> 17 + <a class="text-[#1DB954] font-bold no-underline" href="/login/atproto">Login with ATProto</a> 18 18 {{ end }} 19 - </div> 19 + </nav> 20 20 {{ end }}
+20 -20
pages/templates/home.gohtml
··· 1 1 2 2 {{ define "content" }} 3 3 4 - <h1>Piper - Multi-User Spotify & Last.fm Tracker via ATProto</h1> 4 + <h1 class="text-[#1DB954]">Piper - Multi-User Spotify & Last.fm Tracker via ATProto</h1> 5 5 {{ template "components/navBar" .NavBar }} 6 6 7 7 8 - <div class="card"> 9 - <h2 class="">Welcome to Piper</h2> 10 - <p>Piper is a multi-user application that records what you're listening to on Spotify and Last.fm, saving your listening history.</p> 8 + <div class="border border-gray-300 rounded-lg p-5 mb-5"> 9 + <h2 class="text-xl font-semibold mb-2">Welcome to Piper</h2> 10 + <p class="mb-3">Piper is a multi-user application that records what you're listening to on Spotify and Last.fm, saving your listening history.</p> 11 11 12 12 {{if .NavBar.IsLoggedIn}} 13 - <p>You're logged in!</p> 14 - <ul> 15 - <li><a href="/login/spotify">Connect your Spotify account</a> to start tracking.</li> 16 - <li><a href="/link-lastfm">Link your Last.fm account</a> to track scrobbles.</li> 13 + <p class="mb-2">You're logged in!</p> 14 + <ul class="list-disc pl-5 mb-3"> 15 + <li><a class="text-[#1DB954] font-bold" href="/login/spotify">Connect your Spotify account</a> to start tracking.</li> 16 + <li><a class="text-[#1DB954] font-bold" href="/link-lastfm">Link your Last.fm account</a> to track scrobbles.</li> 17 17 </ul> 18 - <p>Once connected, you can check out your:</p> 19 - <ul> 20 - <li><a href="/current-track">Spotify current track</a> or <a href="/history">listening history</a>.</li> 18 + <p class="mb-2">Once connected, you can check out your:</p> 19 + <ul class="list-disc pl-5 mb-3"> 20 + <li><a class="text-[#1DB954] font-bold" href="/current-track">Spotify current track</a> or <a class="text-[#1DB954] font-bold" href="/history">listening history</a>.</li> 21 21 {{ if .NavBar.LastFMUsername }} 22 - <li><a href="/lastfm/recent">Last.fm recent tracks</a>.</li> 22 + <li><a class="text-[#1DB954] font-bold" href="/lastfm/recent">Last.fm recent tracks</a>.</li> 23 23 {{ end }} 24 24 25 25 </ul> 26 - <p>You can also manage your <a href="/api-keys">API keys</a> for programmatic access.</p> 26 + <p class="mb-3">You can also manage your <a class="text-[#1DB954] font-bold" href="/api-keys">API keys</a> for programmatic access.</p> 27 27 28 28 {{ if .NavBar.LastFMUsername }} 29 - <p class='service-status'>Last.fm Username: {{ .NavBar.LastFMUsername }}</p> 29 + <p class='italic text-gray-600'>Last.fm Username: {{ .NavBar.LastFMUsername }}</p> 30 30 {{else }} 31 - <p class='service-status'>Last.fm account not linked.</p> 31 + <p class='italic text-gray-600'>Last.fm account not linked.</p> 32 32 {{end}} 33 33 34 34 35 35 {{ else }} 36 36 37 - <p>Login with ATProto to get started!</p> 38 - <form action="/login/atproto"> 39 - <label for="handle">handle:</label> 40 - <input type="text" id="handle" name="handle" > 41 - <input class="teal-input" type="submit" value="submit"> 37 + <p class="mb-3">Login with ATProto to get started!</p> 38 + <form class="space-y-2" action="/login/atproto"> 39 + <label class="block" for="handle">handle:</label> 40 + <input class="block w-[95%] p-2 border border-gray-300 rounded" type="text" id="handle" name="handle" > 41 + <input class="bg-[#1DB954] text-white px-4 py-2.5 rounded cursor-pointer hover:opacity-90" type="submit" value="submit"> 42 42 </form> 43 43 44 44
+7 -7
pages/templates/lastFMForm.gohtml
··· 1 1 {{ define "content" }} 2 2 {{ template "components/navBar" .NavBar }} 3 3 4 - <div class="lastfm-form"> 5 - <h2>Link Your Last.fm Account</h2> 6 - <p>Enter your Last.fm username to start tracking your scrobbles.</p> 7 - <form method="post" action="/link-lastfm"> 8 - <label for="lastfm_username">Last.fm Username:</label> 9 - <input type="text" id="lastfm_username" name="lastfm_username" value="{{.CurrentUsername}}" required> 10 - <input class="last-fm-input" type="submit" value="Save Username"> 4 + <div class="max-w-[600px] mx-auto my-5 p-5 border border-gray-300 rounded-lg"> 5 + <h2 class="text-xl font-semibold mb-2">Link Your Last.fm Account</h2> 6 + <p class="mb-3">Enter your Last.fm username to start tracking your scrobbles.</p> 7 + <form class="space-y-2" method="post" action="/link-lastfm"> 8 + <label class="block" for="lastfm_username">Last.fm Username:</label> 9 + <input class="block w-[95%] p-2 border border-gray-300 rounded" type="text" id="lastfm_username" name="lastfm_username" value="{{.CurrentUsername}}" required> 10 + <input class="bg-[#d51007] text-white px-4 py-2.5 rounded cursor-pointer hover:opacity-90" type="submit" value="Save Username"> 11 11 </form> 12 12 </div> 13 13
+1 -1
pages/templates/layouts/base.gohtml
··· 5 5 <title>Piper - Spotify & Last.fm Tracker</title> 6 6 <link rel="stylesheet" href="/static/main.css"> 7 7 </head> 8 - <body> 8 + <body class="font-sans max-w-[800px] mx-auto p-5 leading-relaxed"> 9 9 {{ block "content" . }}{{ end }} 10 10 11 11 </body>