mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
## Summary - include the reported event's complete stored content, author, creation time, and deletion state in the admin report detail response - resolve the event through a community-scoped join so an event ID collision cannot cross tenant boundaries - render the message only on report detail, with an explicit unavailable state when retention has removed it - preserve the existing report list contract so message bodies are not returned during queue browsing ## Security - the existing admin host/origin authorization runs before the detail database read; a route test pins that ordering - the target event is selected using both `events.community_id = moderation_reports.community_id` and `events.id = moderation_reports.target_event_id` - the client supplies only the report UUID; it cannot choose a community or arbitrary event ID - soft-deleted content is visible only through this restricted admin detail route and is labeled deleted - responses retain the admin API's `no-store`, CSP, `nosniff`, frame denial, and referrer policy middleware ## Testing - `pnpm -C admin-web check` - `pnpm -C admin-web test:e2e` (10 passed) - `cargo test -p buzz-db` (84 passed, 130 ignored) - `cargo clippy -p buzz-db -p buzz-relay --all-targets -- -D warnings` - focused admin authorization tests - pre-push Rust and desktop/Tauri suites passed The new Postgres integration test is ignored under the repository convention and will run when explicitly enabled against migrated Postgres. Local Postgres and Redis were unavailable, so the full `buzz-relay --lib` run had 8 existing infrastructure-dependent failures after 749 tests passed. --------- Signed-off-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Signed-off-by: Kalvin Chau <kalvin@block.xyz> Signed-off-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz> Co-authored-by: npub1dccv64krpcpse5cmkzfeh998cftungyatw3djt8jwdw6g43f7fyqzzmrf7 <6e30cd56c30e030cd31bb0939b94a7c257c9a09d5ba2d92cf2735da45629f248@buzz.block.builderlab.xyz> Co-authored-by: npub122y0pqkertljmedu303rl0aqrj3w8pvu43t6jxm6875lzg6f2pwqegc3xc <5288f082d91aff2de5bc8be23fbfa01ca2e3859cac57a91b7a3fa9f12349505c@buzz.block.builderlab.xyz>
735 lines
12 KiB
CSS
735 lines
12 KiB
CSS
:root {
|
|
font-family:
|
|
"Helvetica Neue", Helvetica, Arial, ui-sans-serif, system-ui, sans-serif;
|
|
color: #231e1e;
|
|
background: #d7e7f6;
|
|
font-synthesis: none;
|
|
}
|
|
|
|
* {
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
}
|
|
|
|
a {
|
|
color: inherit;
|
|
text-decoration: none;
|
|
}
|
|
|
|
button {
|
|
font: inherit;
|
|
}
|
|
|
|
input,
|
|
select {
|
|
font: inherit;
|
|
}
|
|
|
|
button {
|
|
color: white;
|
|
background: #231e1e;
|
|
border: 0;
|
|
border-radius: 999px;
|
|
padding: 0.75rem 1.25rem;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.app {
|
|
min-height: 100vh;
|
|
background: linear-gradient(180deg, #d7d72e 0%, #dfe379 24%, #d7e7f6 78%);
|
|
}
|
|
|
|
.app-header {
|
|
width: min(1120px, calc(100% - 3rem));
|
|
margin: 0 auto;
|
|
padding: 1.5rem 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 2rem;
|
|
}
|
|
|
|
.brand {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
font-size: 1.1rem;
|
|
font-weight: 500;
|
|
letter-spacing: -0.04em;
|
|
}
|
|
|
|
.brand b {
|
|
font-weight: 400;
|
|
color: rgb(35 30 30 / 60%);
|
|
}
|
|
|
|
.brand-mark {
|
|
width: 2.5rem;
|
|
height: 2.5rem;
|
|
display: grid;
|
|
place-items: center;
|
|
border-radius: 0.7rem;
|
|
color: #d7d72e;
|
|
background: #231e1e;
|
|
}
|
|
|
|
.brand-mark svg {
|
|
width: 1.7rem;
|
|
fill: currentColor;
|
|
}
|
|
|
|
nav {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
padding: 0.3rem;
|
|
border: 1px solid rgb(35 30 30 / 10%);
|
|
border-radius: 999px;
|
|
background: rgb(255 255 255 / 42%);
|
|
backdrop-filter: blur(12px);
|
|
}
|
|
|
|
.nav-link {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.65rem 1rem;
|
|
border-radius: 999px;
|
|
color: rgb(35 30 30 / 60%);
|
|
font-size: 0.9rem;
|
|
letter-spacing: -0.035em;
|
|
transition:
|
|
color 160ms ease,
|
|
background 160ms ease;
|
|
}
|
|
|
|
.nav-link svg {
|
|
width: 1rem;
|
|
height: 1rem;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.7;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
.nav-link:hover {
|
|
color: #231e1e;
|
|
}
|
|
|
|
.nav-link[aria-current="page"] {
|
|
color: #231e1e;
|
|
background: white;
|
|
box-shadow: 0 0.2rem 1rem rgb(35 30 30 / 8%);
|
|
}
|
|
|
|
main {
|
|
width: min(1120px, calc(100% - 3rem));
|
|
margin: 0 auto;
|
|
padding: 4.5rem 0 7rem;
|
|
}
|
|
|
|
.page-title {
|
|
max-width: 52rem;
|
|
margin-bottom: 3rem;
|
|
}
|
|
|
|
.page-title > p {
|
|
margin: 0 0 1rem;
|
|
color: rgb(35 30 30 / 55%);
|
|
font-size: 0.78rem;
|
|
font-weight: 500;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
h1 {
|
|
margin: 0;
|
|
font-size: clamp(3rem, 7vw, 5.5rem);
|
|
font-weight: 400;
|
|
line-height: 0.92;
|
|
letter-spacing: -0.065em;
|
|
}
|
|
|
|
.page-title > span {
|
|
display: block;
|
|
margin-top: 1.5rem;
|
|
color: rgb(35 30 30 / 62%);
|
|
font-size: 1.05rem;
|
|
line-height: 1.5;
|
|
letter-spacing: -0.035em;
|
|
}
|
|
|
|
.back-link {
|
|
width: fit-content;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
margin-bottom: 2.25rem;
|
|
color: rgb(35 30 30 / 62%);
|
|
font-size: 0.9rem;
|
|
letter-spacing: -0.035em;
|
|
}
|
|
|
|
.cards {
|
|
display: grid;
|
|
gap: 0.8rem;
|
|
}
|
|
|
|
.feedback-filters {
|
|
display: grid;
|
|
grid-template-columns: minmax(14rem, 1fr) repeat(3, auto);
|
|
gap: 0.75rem;
|
|
align-items: end;
|
|
margin-bottom: 0.75rem;
|
|
padding: 1rem;
|
|
border: 1px solid rgb(35 30 30 / 10%);
|
|
border-radius: 1.25rem;
|
|
background: rgb(255 255 255 / 45%);
|
|
backdrop-filter: blur(12px);
|
|
}
|
|
|
|
.feedback-filters label {
|
|
display: grid;
|
|
gap: 0.45rem;
|
|
}
|
|
|
|
.feedback-filters label > span {
|
|
color: rgb(35 30 30 / 48%);
|
|
font-size: 0.7rem;
|
|
letter-spacing: 0.07em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.feedback-filters input,
|
|
.feedback-filters select {
|
|
min-height: 2.75rem;
|
|
border: 1px solid rgb(35 30 30 / 12%);
|
|
border-radius: 999px;
|
|
outline: none;
|
|
color: #231e1e;
|
|
background: white;
|
|
}
|
|
|
|
.feedback-filters input:focus,
|
|
.feedback-filters select:focus {
|
|
border-color: #231e1e;
|
|
box-shadow: 0 0 0 3px rgb(35 30 30 / 10%);
|
|
}
|
|
|
|
.feedback-filters select {
|
|
padding: 0 2.25rem 0 1rem;
|
|
}
|
|
|
|
.search-field > div {
|
|
position: relative;
|
|
}
|
|
|
|
.search-field input {
|
|
width: 100%;
|
|
padding: 0 1rem 0 2.6rem;
|
|
}
|
|
|
|
.search-field svg {
|
|
position: absolute;
|
|
z-index: 1;
|
|
top: 50%;
|
|
left: 1rem;
|
|
width: 1rem;
|
|
height: 1rem;
|
|
transform: translateY(-50%);
|
|
fill: none;
|
|
stroke: rgb(35 30 30 / 45%);
|
|
stroke-width: 1.7;
|
|
stroke-linecap: round;
|
|
}
|
|
|
|
.result-count {
|
|
margin: 0 0 0.75rem;
|
|
color: rgb(35 30 30 / 48%);
|
|
font-size: 0.78rem;
|
|
}
|
|
|
|
.card-link {
|
|
display: block;
|
|
border-radius: 1.6rem;
|
|
}
|
|
|
|
.record-card,
|
|
.detail,
|
|
.state {
|
|
background: white;
|
|
border-radius: 1.6rem;
|
|
box-shadow: 0 1rem 4rem rgb(35 30 30 / 6%);
|
|
}
|
|
|
|
.record-card {
|
|
min-height: 7.2rem;
|
|
display: grid;
|
|
grid-template-columns: auto minmax(0, 1fr) auto auto;
|
|
align-items: center;
|
|
gap: 1.4rem;
|
|
padding: 1.2rem 1.5rem;
|
|
transition:
|
|
transform 180ms ease,
|
|
box-shadow 180ms ease;
|
|
}
|
|
|
|
.feedback-record {
|
|
grid-template-columns: minmax(0, 1fr) auto auto auto;
|
|
}
|
|
|
|
.feedback-main-link {
|
|
min-width: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1.4rem;
|
|
}
|
|
|
|
.record-open-link:hover {
|
|
text-decoration: underline;
|
|
text-underline-offset: 0.2rem;
|
|
}
|
|
|
|
.feedback-status {
|
|
min-width: 5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
color: rgb(35 30 30 / 62%);
|
|
font-size: 0.78rem;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.feedback-status input {
|
|
width: 1rem;
|
|
height: 1rem;
|
|
margin: 0;
|
|
accent-color: #231e1e;
|
|
}
|
|
|
|
.record-open-link {
|
|
display: grid;
|
|
place-items: center;
|
|
padding: 0.5rem;
|
|
border-radius: 999px;
|
|
color: rgb(35 30 30 / 30%);
|
|
}
|
|
|
|
.card-link:hover .record-card {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 1.4rem 4.5rem rgb(35 30 30 / 12%);
|
|
}
|
|
|
|
.record-icon {
|
|
width: 3rem;
|
|
height: 3rem;
|
|
display: grid;
|
|
place-items: center;
|
|
border-radius: 999px;
|
|
color: #231e1e;
|
|
}
|
|
|
|
.report-icon {
|
|
background: #d7d72e;
|
|
}
|
|
|
|
.feedback-icon {
|
|
background: #d7e7f6;
|
|
}
|
|
|
|
.record-icon svg {
|
|
width: 1.35rem;
|
|
height: 1.35rem;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.7;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
.record-primary {
|
|
min-width: 0;
|
|
display: grid;
|
|
justify-items: start;
|
|
gap: 0.35rem;
|
|
}
|
|
|
|
.tag,
|
|
.status {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
border-radius: 999px;
|
|
background: #f2f2ed;
|
|
padding: 0.25rem 0.55rem;
|
|
color: rgb(35 30 30 / 65%);
|
|
font-size: 0.7rem;
|
|
letter-spacing: 0.04em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.tag {
|
|
gap: 0.3rem;
|
|
}
|
|
|
|
.tag svg {
|
|
width: 0.78rem;
|
|
height: 0.78rem;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.7;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
.record-primary strong {
|
|
max-width: 42rem;
|
|
overflow: hidden;
|
|
color: #231e1e;
|
|
font-size: 1rem;
|
|
font-weight: 400;
|
|
line-height: 1.35;
|
|
letter-spacing: -0.04em;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.feedback-card .record-primary strong {
|
|
display: -webkit-box;
|
|
overflow: hidden;
|
|
line-height: 1.35;
|
|
white-space: normal;
|
|
-webkit-box-orient: vertical;
|
|
-webkit-line-clamp: 2;
|
|
}
|
|
|
|
.record-provenance {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.65rem;
|
|
color: rgb(35 30 30 / 55%);
|
|
font-size: 0.78rem;
|
|
}
|
|
|
|
code {
|
|
color: rgb(35 30 30 / 50%);
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
font-size: 0.75rem;
|
|
word-break: break-all;
|
|
}
|
|
|
|
.record-provenance code {
|
|
padding-left: 0.65rem;
|
|
border-left: 1px solid rgb(35 30 30 / 14%);
|
|
}
|
|
|
|
.record-date {
|
|
display: grid;
|
|
justify-items: end;
|
|
gap: 0.3rem;
|
|
color: rgb(35 30 30 / 48%);
|
|
font-size: 0.78rem;
|
|
letter-spacing: -0.025em;
|
|
}
|
|
|
|
.record-date span {
|
|
color: rgb(35 30 30 / 32%);
|
|
font-size: 0.68rem;
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
}
|
|
|
|
.arrow-icon {
|
|
width: 1.25rem;
|
|
height: 1.25rem;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.7;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
.back-link .arrow-icon {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
.record-card > .arrow-icon {
|
|
color: rgb(35 30 30 / 30%);
|
|
}
|
|
|
|
.detail {
|
|
padding: 2rem;
|
|
}
|
|
|
|
.detail-heading {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
padding-bottom: 2rem;
|
|
border-bottom: 1px solid rgb(35 30 30 / 9%);
|
|
}
|
|
|
|
.detail-heading h2 {
|
|
margin: 0.45rem 0 0;
|
|
font-size: 1.5rem;
|
|
font-weight: 400;
|
|
letter-spacing: -0.05em;
|
|
}
|
|
|
|
dl {
|
|
display: grid;
|
|
grid-template-columns: 9rem minmax(0, 1fr);
|
|
gap: 1.4rem;
|
|
margin: 2rem 0 0;
|
|
}
|
|
|
|
dt {
|
|
color: rgb(35 30 30 / 48%);
|
|
font-size: 0.82rem;
|
|
}
|
|
|
|
dd {
|
|
min-width: 0;
|
|
margin: 0;
|
|
}
|
|
|
|
.reported-message {
|
|
display: grid;
|
|
justify-items: start;
|
|
gap: 1rem;
|
|
border-left: 3px solid #d7d72e;
|
|
border-radius: 0 0.8rem 0.8rem 0;
|
|
background: #f6f6f1;
|
|
padding: 1rem;
|
|
}
|
|
|
|
.reported-message p,
|
|
.message-unavailable {
|
|
margin: 0;
|
|
overflow-wrap: anywhere;
|
|
line-height: 1.5;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.reported-message-meta {
|
|
display: grid;
|
|
grid-template-columns: auto minmax(0, 1fr);
|
|
gap: 0.4rem 0.75rem;
|
|
width: 100%;
|
|
color: rgb(35 30 30 / 48%);
|
|
font-size: 0.78rem;
|
|
}
|
|
|
|
.message-unavailable {
|
|
color: rgb(35 30 30 / 60%);
|
|
font-style: italic;
|
|
}
|
|
|
|
.sensitive {
|
|
border-left: 3px solid #d7d72e;
|
|
border-radius: 0 0.8rem 0.8rem 0;
|
|
background: #f6f6f1;
|
|
padding: 1rem;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.feedback-body {
|
|
overflow-wrap: anywhere;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.attachments {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
|
|
gap: 0.75rem;
|
|
align-items: start;
|
|
}
|
|
|
|
.image-attachment {
|
|
overflow: hidden;
|
|
margin: 0;
|
|
border: 1px solid rgb(35 30 30 / 10%);
|
|
border-radius: 1rem;
|
|
background: #f6f6f1;
|
|
}
|
|
|
|
.image-attachment a {
|
|
display: block;
|
|
}
|
|
|
|
.image-attachment img {
|
|
width: 100%;
|
|
max-height: 32rem;
|
|
display: block;
|
|
object-fit: contain;
|
|
background: rgb(35 30 30 / 4%);
|
|
}
|
|
|
|
.image-attachment figcaption,
|
|
.file-attachment {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
padding: 0.85rem 1rem;
|
|
}
|
|
|
|
.image-attachment figcaption {
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.image-attachment figcaption span,
|
|
.file-attachment strong {
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
font-size: 0.82rem;
|
|
font-weight: 500;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.feedback-main-link:hover strong {
|
|
text-decoration: underline;
|
|
text-underline-offset: 0.2rem;
|
|
}
|
|
|
|
.image-attachment small,
|
|
.file-attachment small {
|
|
color: rgb(35 30 30 / 48%);
|
|
font-size: 0.7rem;
|
|
}
|
|
|
|
.file-attachment {
|
|
align-self: start;
|
|
border: 1px solid rgb(35 30 30 / 10%);
|
|
border-radius: 1rem;
|
|
background: #f6f6f1;
|
|
}
|
|
|
|
.file-attachment:hover strong {
|
|
text-decoration: underline;
|
|
text-underline-offset: 0.15rem;
|
|
}
|
|
|
|
.file-attachment > svg:first-child {
|
|
width: 1.5rem;
|
|
height: 1.5rem;
|
|
flex: none;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.5;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
.file-attachment > span {
|
|
min-width: 0;
|
|
display: grid;
|
|
flex: 1;
|
|
gap: 0.2rem;
|
|
}
|
|
|
|
.visually-hidden {
|
|
position: absolute;
|
|
width: 1px;
|
|
height: 1px;
|
|
overflow: hidden;
|
|
clip: rect(0 0 0 0);
|
|
clip-path: inset(50%);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.state {
|
|
min-height: 14rem;
|
|
display: grid;
|
|
place-content: center;
|
|
justify-items: center;
|
|
padding: 2rem;
|
|
color: rgb(35 30 30 / 56%);
|
|
text-align: center;
|
|
letter-spacing: -0.035em;
|
|
}
|
|
|
|
.state h2 {
|
|
margin: 0;
|
|
color: #231e1e;
|
|
font-size: 1.4rem;
|
|
font-weight: 400;
|
|
}
|
|
|
|
.state p {
|
|
margin: 0.75rem 0 1.25rem;
|
|
}
|
|
|
|
.state.error {
|
|
color: #9f2424;
|
|
}
|
|
|
|
@media (max-width: 720px) {
|
|
.app-header {
|
|
width: min(100% - 2rem, 1120px);
|
|
align-items: flex-start;
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
}
|
|
|
|
main {
|
|
width: min(100% - 2rem, 1120px);
|
|
padding-top: 3rem;
|
|
}
|
|
|
|
h1 {
|
|
font-size: clamp(3rem, 16vw, 4.5rem);
|
|
}
|
|
|
|
.record-card {
|
|
grid-template-columns: auto minmax(0, 1fr);
|
|
}
|
|
|
|
.feedback-filters {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.feedback-record {
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
}
|
|
|
|
.feedback-main-link {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.feedback-status {
|
|
grid-column: 1;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.feedback-record .record-date {
|
|
grid-column: 1;
|
|
}
|
|
|
|
.record-open-link {
|
|
grid-column: 2;
|
|
grid-row: 2 / span 2;
|
|
}
|
|
|
|
.record-date {
|
|
grid-column: 2;
|
|
justify-items: start;
|
|
}
|
|
|
|
.record-card > .arrow-icon {
|
|
display: none;
|
|
}
|
|
|
|
dl {
|
|
grid-template-columns: 1fr;
|
|
gap: 0.6rem;
|
|
}
|
|
|
|
dd + dt {
|
|
margin-top: 0.9rem;
|
|
}
|
|
}
|