this repo has no description
0
fork

Configure Feed

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

fix(profile): show update history in modal

Keep What's New below reviews while moving version history into a popup and aligning the profile card heading and review card styling.

Made-with: Cursor

+158 -62
+52 -27
assets/styles.css
··· 5016 5016 .profile-reviews-shell { 5017 5017 display: flex; 5018 5018 flex-direction: column; 5019 - gap: 0.85rem; 5020 - margin-top: 1.5rem; 5019 + gap: 0.75rem; 5020 + margin-top: 1rem; 5021 5021 } 5022 5022 .profile-whats-new { 5023 5023 margin-top: 1rem; ··· 5107 5107 color: rgba(18, 26, 47, 0.58); 5108 5108 } 5109 5109 .profile-whats-new-icon-button, 5110 - .profile-whats-new-history-link, 5110 + .profile-whats-new-history-button, 5111 5111 .profile-version-history-commit { 5112 5112 flex: 0 0 auto; 5113 5113 display: inline-flex; 5114 5114 align-items: center; 5115 5115 justify-content: center; 5116 + font: inherit; 5116 5117 text-decoration: none; 5117 5118 color: #254a9e; 5118 5119 border: 1px solid rgba(18, 26, 47, 0.12); ··· 5120 5121 border-radius: 999px; 5121 5122 } 5122 5123 .profile-whats-new-icon-button, 5123 - .profile-whats-new-history-link { 5124 + .profile-whats-new-history-button { 5124 5125 width: 2.15rem; 5125 5126 height: 2.15rem; 5126 5127 } 5127 5128 .profile-whats-new-icon-button { 5128 5129 position: relative; 5129 5130 } 5130 - .profile-whats-new-history-link { 5131 + .profile-whats-new-history-button { 5132 + cursor: pointer; 5131 5133 font-size: 1rem; 5132 5134 } 5133 5135 .profile-whats-new-icon-button:hover, 5134 - .profile-whats-new-history-link:hover, 5136 + .profile-whats-new-history-button:hover, 5135 5137 .profile-version-history-commit:hover { 5136 5138 background: rgba(255, 255, 255, 0.86); 5137 5139 border-color: rgba(42, 90, 168, 0.3); ··· 5147 5149 font-size: 0.62rem; 5148 5150 line-height: 1; 5149 5151 } 5150 - .profile-version-history { 5151 - margin-top: 1rem; 5152 - padding-top: 1rem; 5153 - border-top: 1px solid rgba(18, 26, 47, 0.1); 5154 - scroll-margin-top: 6rem; 5152 + .profile-version-history-modal { 5153 + max-width: 640px; 5155 5154 } 5156 - .profile-version-history h3 { 5157 - font-size: 0.9rem; 5158 - margin-bottom: 0.75rem; 5155 + .profile-version-history-list { 5156 + display: flex; 5157 + flex-direction: column; 5158 + gap: 0; 5159 + margin-top: 0.75rem; 5159 5160 } 5160 5161 .profile-version-history-item { 5161 5162 padding: 0.85rem 0; ··· 5165 5166 border-top: 0; 5166 5167 padding-top: 0; 5167 5168 } 5168 - .profile-version-history-item h4 { 5169 + .profile-version-history-item h3 { 5169 5170 margin-top: 0.2rem; 5170 5171 font-size: 0.98rem; 5171 5172 } ··· 5183 5184 .profile-reviews-summary, 5184 5185 .profile-reviews-panel, 5185 5186 .profile-review-card { 5186 - padding: 1.1rem 1.2rem; 5187 + padding: 1rem; 5187 5188 border-radius: 1.2rem; 5188 5189 } 5190 + .profile-reviews-summary.glass, 5191 + .profile-reviews-panel.glass, 5192 + .profile-review-card.glass { 5193 + background: rgba(255, 255, 255, 0.58); 5194 + border-color: rgba(18, 26, 47, 0.08); 5195 + } 5189 5196 .profile-reviews-summary { 5190 5197 display: grid; 5191 5198 grid-template-columns: minmax(0, 1fr) minmax(180px, 280px); ··· 5193 5200 align-items: center; 5194 5201 } 5195 5202 .profile-reviews-average { 5196 - margin: 0.2rem 0 0; 5197 - font-size: clamp(1.3rem, 2.5vw, 1.9rem); 5203 + margin: 0.3rem 0 0; 5204 + font-size: clamp(1.15rem, 2.1vw, 1.55rem); 5198 5205 font-weight: 850; 5199 5206 } 5200 5207 .profile-reviews-average span, ··· 5236 5243 align-items: center; 5237 5244 justify-content: space-between; 5238 5245 gap: 0.75rem; 5239 - margin-bottom: 0.85rem; 5246 + margin-bottom: 0.75rem; 5247 + padding-bottom: 0.75rem; 5248 + border-bottom: 1px solid rgba(18, 26, 47, 0.08); 5240 5249 } 5241 5250 .profile-review-action-row { 5242 5251 display: flex; ··· 5315 5324 .profile-review-cards { 5316 5325 display: flex; 5317 5326 flex-direction: column; 5318 - gap: 0.85rem; 5327 + gap: 0.65rem; 5328 + } 5329 + .profile-review-card { 5330 + background: rgba(255, 255, 255, 0.46); 5331 + border: 1px solid rgba(18, 26, 47, 0.07); 5332 + box-shadow: none; 5319 5333 } 5320 5334 .profile-reviews-empty { 5321 5335 margin-top: 0.25rem; ··· 5379 5393 color: rgba(18, 26, 47, 0.24); 5380 5394 } 5381 5395 .profile-review-body { 5382 - margin-top: 0.8rem; 5396 + margin-top: 0.75rem; 5397 + padding-top: 0.75rem; 5398 + border-top: 1px solid rgba(18, 26, 47, 0.07); 5383 5399 white-space: pre-wrap; 5400 + font-size: 0.92rem; 5401 + line-height: 1.55; 5384 5402 } 5385 5403 .profile-review-response { 5386 5404 margin-top: 0.9rem; ··· 5415 5433 .dark-phase .profile-card-section-title { 5416 5434 color: rgba(255, 255, 255, 0.92); 5417 5435 } 5436 + .dark-phase .profile-reviews-summary.glass, 5437 + .dark-phase .profile-reviews-panel.glass, 5438 + .dark-phase .profile-review-card.glass { 5439 + background: rgba(255, 255, 255, 0.08); 5440 + border-color: rgba(255, 255, 255, 0.13); 5441 + } 5418 5442 .dark-phase .profile-reviews-threshold, 5419 5443 .dark-phase .profile-whats-new-empty, 5420 5444 .dark-phase .profile-whats-new-body, ··· 5432 5456 } 5433 5457 .dark-phase .profile-rating-bar { 5434 5458 background: rgba(255, 255, 255, 0.12); 5459 + } 5460 + .dark-phase .profile-reviews-panel-header, 5461 + .dark-phase .profile-review-body { 5462 + border-color: rgba(255, 255, 255, 0.1); 5435 5463 } 5436 5464 .dark-phase .profile-review-star { 5437 5465 color: rgba(255, 255, 255, 0.22); ··· 5448 5476 } 5449 5477 .dark-phase .profile-whats-new-expand summary, 5450 5478 .dark-phase .profile-whats-new-icon-button, 5451 - .dark-phase .profile-whats-new-history-link, 5479 + .dark-phase .profile-whats-new-history-button, 5452 5480 .dark-phase .profile-version-history-commit { 5453 5481 color: rgba(160, 200, 255, 1); 5454 5482 } 5455 5483 .dark-phase .profile-whats-new-icon-button, 5456 - .dark-phase .profile-whats-new-history-link, 5484 + .dark-phase .profile-whats-new-history-button, 5457 5485 .dark-phase .profile-version-history-commit { 5458 5486 background: rgba(255, 255, 255, 0.06); 5459 5487 border-color: rgba(255, 255, 255, 0.13); 5460 5488 } 5461 5489 .dark-phase .profile-whats-new-icon-button:hover, 5462 - .dark-phase .profile-whats-new-history-link:hover, 5490 + .dark-phase .profile-whats-new-history-button:hover, 5463 5491 .dark-phase .profile-version-history-commit:hover { 5464 5492 background: rgba(255, 255, 255, 0.1); 5465 5493 border-color: rgba(160, 200, 255, 0.35); 5466 - } 5467 - .dark-phase .profile-version-history { 5468 - border-top-color: rgba(255, 255, 255, 0.12); 5469 5494 } 5470 5495 .dark-phase .profile-version-history-item { 5471 5496 border-top-color: rgba(255, 255, 255, 0.1);
+8 -35
components/explore/ProfileWhatsNew.tsx
··· 1 1 import type { ProfileUpdateRow } from "../../lib/profile-updates.ts"; 2 + import ProfileVersionHistoryModal from "../../islands/ProfileVersionHistoryModal.tsx"; 2 3 import TangledIcon from "../icons/TangledIcon.tsx"; 3 4 4 5 interface Props { ··· 77 78 <div class="profile-whats-new-copy"> 78 79 <div class="profile-whats-new-heading-row"> 79 80 <h2 class="profile-card-section-title">{copy.heading}</h2> 80 - {history.length > 0 && ( 81 - <a 82 - href="#profile-version-history" 83 - class="profile-whats-new-history-link" 84 - aria-label={copy.versionHistory} 85 - title={copy.versionHistory} 86 - > 87 - <span aria-hidden="true">↺</span> 88 - </a> 89 - )} 81 + <ProfileVersionHistoryModal 82 + updates={history} 83 + copy={{ 84 + versionHistory: copy.versionHistory, 85 + viewCommit: copy.viewCommit, 86 + }} 87 + /> 90 88 </div> 91 89 <UpdateMeta update={latest} /> 92 90 <h3 class="profile-whats-new-title">{latest.title}</h3> ··· 106 104 <CommitLink href={latest.tangledCommitUrl} label={copy.viewCommit} /> 107 105 )} 108 106 </div> 109 - 110 - {history.length > 0 && ( 111 - <div class="profile-version-history" id="profile-version-history"> 112 - <h3>{copy.versionHistory}</h3> 113 - {history.slice(0, 5).map((update) => ( 114 - <article class="profile-version-history-item" key={update.uri}> 115 - <UpdateMeta update={update} /> 116 - <h4>{update.title}</h4> 117 - <p>{update.body}</p> 118 - {update.tangledCommitUrl && ( 119 - <a 120 - href={update.tangledCommitUrl} 121 - target="_blank" 122 - rel="noopener noreferrer" 123 - class="profile-version-history-commit" 124 - > 125 - <TangledIcon class="profile-whats-new-icon" /> 126 - <span aria-hidden="true">↗</span> 127 - <span class="visually-hidden">{copy.viewCommit}</span> 128 - </a> 129 - )} 130 - </article> 131 - ))} 132 - </div> 133 - )} 134 107 </section> 135 108 ); 136 109 }
+98
islands/ProfileVersionHistoryModal.tsx
··· 1 + import { useSignal } from "@preact/signals"; 2 + import type { ProfileUpdateRow } from "../lib/profile-updates.ts"; 3 + import TangledIcon from "../components/icons/TangledIcon.tsx"; 4 + 5 + interface Props { 6 + updates: ProfileUpdateRow[]; 7 + copy: { 8 + versionHistory: string; 9 + viewCommit: string; 10 + }; 11 + } 12 + 13 + function dateLabel(ms: number): string { 14 + return new Intl.DateTimeFormat("en", { 15 + month: "short", 16 + day: "numeric", 17 + year: "numeric", 18 + }).format(new Date(ms)); 19 + } 20 + 21 + function UpdateMeta({ update }: { update: ProfileUpdateRow }) { 22 + return ( 23 + <div class="profile-whats-new-meta"> 24 + {update.version && <span>{update.version}</span>} 25 + <time dateTime={new Date(update.createdAt).toISOString()}> 26 + {dateLabel(update.createdAt)} 27 + </time> 28 + </div> 29 + ); 30 + } 31 + 32 + export default function ProfileVersionHistoryModal({ updates, copy }: Props) { 33 + const open = useSignal(false); 34 + if (updates.length === 0) return null; 35 + 36 + return ( 37 + <> 38 + <button 39 + type="button" 40 + class="profile-whats-new-history-button" 41 + aria-label={copy.versionHistory} 42 + title={copy.versionHistory} 43 + onClick={() => open.value = true} 44 + > 45 + <span aria-hidden="true">↺</span> 46 + </button> 47 + {open.value && ( 48 + <div 49 + class="modal-backdrop" 50 + role="dialog" 51 + aria-modal="true" 52 + aria-labelledby="profile-version-history-title" 53 + onClick={(event) => { 54 + if (event.target === event.currentTarget) open.value = false; 55 + }} 56 + > 57 + <div class="modal-card profile-version-history-modal"> 58 + <header class="modal-header"> 59 + <h2 id="profile-version-history-title" class="modal-title"> 60 + {copy.versionHistory} 61 + </h2> 62 + </header> 63 + <div class="profile-version-history-list"> 64 + {updates.map((update) => ( 65 + <article class="profile-version-history-item" key={update.uri}> 66 + <UpdateMeta update={update} /> 67 + <h3>{update.title}</h3> 68 + <p>{update.body}</p> 69 + {update.tangledCommitUrl && ( 70 + <a 71 + href={update.tangledCommitUrl} 72 + target="_blank" 73 + rel="noopener noreferrer" 74 + class="profile-version-history-commit" 75 + > 76 + <TangledIcon class="profile-whats-new-icon" /> 77 + <span aria-hidden="true">↗</span> 78 + <span class="visually-hidden">{copy.viewCommit}</span> 79 + </a> 80 + )} 81 + </article> 82 + ))} 83 + </div> 84 + <footer class="modal-footer"> 85 + <button 86 + type="button" 87 + class="profile-form-button-secondary" 88 + onClick={() => open.value = false} 89 + > 90 + Close 91 + </button> 92 + </footer> 93 + </div> 94 + </div> 95 + )} 96 + </> 97 + ); 98 + }