Browse Source

bug-fixes

imwald
Silberengel 7 days ago
parent
commit
a155bebd05
  1. 7
      assets/styles/app.css
  2. 242
      assets/styles/layout.css
  3. 5
      src/Twig/Components/UserMenu.php
  4. 5
      templates/components/Header.html.twig
  5. 2
      templates/components/UserMenu.html.twig
  6. 8
      templates/pages/featured_authors.html.twig
  7. 2
      templates/partial/author_profile_header.html.twig

7
assets/styles/app.css

@ -325,16 +325,21 @@ div:nth-child(odd) .featured-list {
.header__logo .brand { .header__logo .brand {
font-size: clamp(1rem, 4.2vw, 1.45rem); font-size: clamp(1rem, 4.2vw, 1.45rem);
gap: 0.35rem; gap: 0.35rem;
line-height: 1.2; /* Tight line-height + overflow:hidden on .brand__title clip ascenders; keep room for type. */
line-height: 1.35;
justify-content: flex-start; justify-content: flex-start;
text-align: left; text-align: left;
} }
.brand__title { .brand__title {
flex: 1; flex: 1;
min-width: 0;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
line-height: 1.35;
/* Padding inside the clipping box so Lobster/serif caps aren’t sheared at the top */
padding: 0.2em 0 0.12em;
} }
.header__logo-circle { .header__logo-circle {

242
assets/styles/layout.css

@ -50,7 +50,9 @@ nav a:hover {
text-decoration: none; text-decoration: none;
} }
header { /* Only the app chrome in Header.html.twig (#site-header). A bare `header` rule also
matched <header class="featured-authors__intro"> and fixed it under the real bar, hiding it. */
#site-header {
position: fixed; position: fixed;
/* Use inset instead of 100vw: 100vw includes the vertical scrollbar and causes horizontal overflow on many viewports. */ /* Use inset instead of 100vw: 100vw includes the vertical scrollbar and causes horizontal overflow on many viewports. */
left: 0; left: 0;
@ -63,7 +65,7 @@ header {
/* Desktop: breathing room under the browser chrome. Mobile gets inset via /* Desktop: breathing room under the browser chrome. Mobile gets inset via
.header__logo padding in the max-width block below. */ .header__logo padding in the max-width block below. */
@media (min-width: 1025px) { @media (min-width: 1025px) {
header { #site-header {
padding-top: max(0.65rem, env(safe-area-inset-top, 0px)); padding-top: max(0.65rem, env(safe-area-inset-top, 0px));
} }
} }
@ -136,7 +138,8 @@ header {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
padding: 0.4rem max(0.65rem, env(safe-area-inset-left)) 0.4rem max(0.65rem, env(safe-area-inset-right)); /* Top: safe area (notch) + room so the site title isn’t flush under the browser chrome */
padding: max(0.5rem, env(safe-area-inset-top, 0px)) max(0.65rem, env(safe-area-inset-left)) 0.45rem max(0.65rem, env(safe-area-inset-right));
} }
.header__brand { .header__brand {
@ -150,6 +153,7 @@ header {
display: none; display: none;
flex-direction: column; flex-direction: column;
padding-top: 10px; padding-top: 10px;
padding-bottom: max(1rem, env(safe-area-inset-bottom, 0px));
} }
.header__categories.active { .header__categories.active {
@ -165,6 +169,24 @@ header {
flex-direction: column; flex-direction: column;
gap: 10px; gap: 10px;
} }
/* Log in / account block below category links in the hamburger */
.header__mobile-account {
align-self: stretch;
text-align: left;
width: 100%;
max-width: 32rem;
margin: 0 auto;
padding: 0.75rem 0.25rem 0;
border-top: 1px solid var(--color-border);
}
}
/* Hide the duplicate hamburger user menu on wide screens (sidebar <nav> has the real menu). */
@media (min-width: 1025px) {
.header__mobile-account {
display: none;
}
} }
/* Main content */ /* Main content */
@ -195,6 +217,16 @@ main {
} }
} }
/* After .user-menu so this wins: hamburger copy stays in flow, not position:fixed. */
.user-menu.user-menu--inline {
position: static;
width: 100%;
min-width: 0;
max-width: none;
top: auto;
left: auto;
}
.user-nav { .user-nav {
padding: 10px; padding: 10px;
margin: 10px 0; margin: 10px 0;
@ -236,8 +268,10 @@ dt {
aside { aside {
display: none; /* Hide the sidebars on small screens */ display: none; /* Hide the sidebars on small screens */
} }
/* Fixed header is taller than 90px (safe-area + logo row + title padding). Match it or the first
main content (e.g. featured authors intro) sits under the bar and looks cut off at the top. */
main { main {
margin-top: 90px; margin-top: max(7.25rem, calc(4.8rem + env(safe-area-inset-top, 0px)));
width: 100%; width: 100%;
} }
} }
@ -281,9 +315,18 @@ footer {
max-width: 40rem; max-width: 40rem;
} }
/* Footer <nav> must not use the main-column nav rule (width: 21vw), or the list stays ~1/5 of the screen. */
.site-footer__nav { .site-footer__nav {
max-width: min(44rem, 100%); width: 100%;
max-width: 100%;
min-width: 0; min-width: 0;
flex-shrink: 1;
padding: 0;
overflow-y: visible;
}
.site-footer__nav li {
margin: 0; /* not nav li { margin: 0.5em 0 } */
} }
.site-footer__syndication { .site-footer__syndication {
@ -305,12 +348,14 @@ footer {
max-width: 100%; max-width: 100%;
} }
/* Do not set min-width:0 on <li> with flex it lets items shrink to a hairline and
forces one-word-per-line wrapping. Use natural (content) size per item instead. */
.site-footer__syndication-list > li { .site-footer__syndication-list > li {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center; align-items: center;
gap: 0.4rem 0.45rem; gap: 0.4rem 0.45rem;
min-width: 0; flex: 0 0 auto;
max-width: 100%; max-width: 100%;
} }
@ -346,14 +391,82 @@ footer {
gap: 0.4rem 0.45rem; gap: 0.4rem 0.45rem;
min-width: 0; min-width: 0;
max-width: 100%; max-width: 100%;
overflow-wrap: anywhere; /* long category names / URLs can’t keep the page wider than the screen */ /* Break only unbroken long words; avoid overflow-wrap:anywhere (splits at every symbol). */
word-break: break-word; word-break: break-word;
overflow-wrap: break-word;
}
/* Narrow / tablet: feeds row full width; tighter footer so it doesn’t dominate the viewport. */
@media (max-width: 1024px) {
footer {
padding: 0.65rem 0.75rem 0.75rem;
}
.site-footer {
gap: 0.65rem;
}
.site-footer__syndication-title {
font-size: 0.95rem;
margin: 0 0 0.15rem;
}
.site-footer__syndication-hint {
margin: 0 0 0.35rem;
font-size: 0.8rem;
line-height: 1.35;
}
.site-footer__syndication-list {
row-gap: 0.15rem;
font-size: 0.88rem;
line-height: 1.35;
}
.site-footer__syndication-list > li {
gap: 0.25rem 0.35rem;
}
.site-footer__syndication-list__feeds {
flex: 1 1 100%;
gap: 0.25rem 0.35rem;
}
.site-footer__main {
margin-top: 0;
}
.site-footer__legal {
margin: 0.35rem 0 0;
font-size: 0.85rem;
line-height: 1.35;
}
footer .footer-links {
margin: 0 0 0.3rem;
}
.footer-links .footer-link {
margin: 0.2rem 0;
line-height: 1.35;
font-size: 0.88rem;
}
} }
/* Narrow viewports: put feeds on their own row with full line width so links wrap inside the viewport, not off-screen. */ /* Single-column footer: center both syndication and main. (900px+ uses side-by-side layout.) */
@media (max-width: 700px) { @media (max-width: 899px) {
.site-footer {
text-align: center;
}
.site-footer__syndication-hint {
margin-left: auto;
margin-right: auto;
}
.site-footer__syndication-list,
.site-footer__syndication-list__feeds { .site-footer__syndication-list__feeds {
flex-basis: 100%; justify-content: center;
} }
} }
@ -419,28 +532,131 @@ footer .footer-links {
.featured-authors__intro { .featured-authors__intro {
margin-bottom: 2rem; margin-bottom: 2rem;
overflow: visible; /* do not clip heading ascenders */
} }
/* Override global h1 (3.2rem + tight line box); keep full glyphs visible */
.featured-authors__intro h1 { .featured-authors__intro h1 {
margin-top: 0; margin: 0 0 0.5rem;
font-size: clamp(1.35rem, 2.6vw, 2.05rem);
line-height: 1.28;
font-weight: 500;
font-family: var(--heading-font), serif;
color: var(--color-primary);
padding: 0.2em 0 0.05em;
overflow: visible;
} }
.featured-authors__card { .featured-authors__card {
margin-bottom: 2.5rem; margin-bottom: 2.5rem;
padding-bottom: 1.5rem; padding-bottom: 1.5rem;
border-bottom: 1px solid var(--color-border); border-bottom: 1px solid var(--color-border);
box-sizing: border-box;
width: 100%;
} }
.featured-authors__card:last-of-type { .featured-authors__card:last-of-type {
border-bottom: none; border-bottom: none;
} }
/* One shared content width: drop the 40rem cap so label/value grid lines line up with the card edges */
.featured-authors__card .author-profile.author-profile--featured {
max-width: none;
width: 100%;
margin-left: 0;
margin-right: 0;
box-sizing: border-box;
}
.author-profile--featured .author-profile__header-meta {
max-width: none;
width: 100%;
}
/* Same first-column width for section blocks and per-row fields so dividers don’t “jump” between cards */
.author-profile--featured .author-profile__section--label-value,
.author-profile--featured .author-profile__meta-line,
.author-profile--featured .author-profile__identity-row,
.author-profile--featured .author-profile__payment {
grid-template-columns: minmax(5.25rem, 8.5rem) minmax(0, 1fr);
align-items: start;
column-gap: 0.65rem;
}
.author-profile--featured .author-profile__title { .author-profile--featured .author-profile__title {
font-size: 1.5rem; font-size: 1.5rem;
} }
.featured-authors__more { /* Very narrow: single column so tiny two-column cells don’t look skewed */
margin: 0.75rem 0 0; @media (max-width: 30rem) {
.author-profile--featured .author-profile__section--label-value,
.author-profile--featured .author-profile__meta-line,
.author-profile--featured .author-profile__identity-row,
.author-profile--featured .author-profile__payment {
grid-template-columns: 1fr;
row-gap: 0.2rem;
}
.author-profile--featured .author-profile__meta-line,
.author-profile--featured .author-profile__identity-row,
.author-profile--featured .author-profile__payment {
margin: 0.5rem 0;
}
.author-profile--featured .author-profile__meta-value,
.author-profile--featured .author-profile__identity-link,
.author-profile--featured .author-profile__payment-addr {
white-space: normal;
word-break: break-word;
}
}
.featured-authors__actions {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
flex-shrink: 0;
align-items: center;
justify-content: center;
column-gap: 0.75rem;
margin: 1rem 0 0;
width: 100%;
box-sizing: border-box;
}
.featured-authors__actions .btn {
flex: 0 1 auto;
text-align: center;
}
/* Narrow: smaller page title + intro; flex gap avoids margin collapse with first author card. */
@media (max-width: 1024px) {
.featured-authors {
display: flex;
flex-direction: column;
align-items: stretch;
gap: 1.75rem;
}
.featured-authors__intro {
margin-bottom: 0;
/* Contain the intro <p> margin so it doesn’t collapse with the first author block */
display: flow-root;
}
.featured-authors__card {
margin-bottom: 0;
}
.featured-authors__intro h1 {
/* Slightly smaller in the max-1024 layout; same visible box as the base h1 */
font-size: clamp(1.3rem, 4.2vw, 1.95rem);
}
.featured-authors__intro p {
font-size: 0.9rem;
line-height: 1.45;
}
} }
.footer-links a { .footer-links a {

5
src/Twig/Components/UserMenu.php

@ -3,10 +3,15 @@
namespace App\Twig\Components; namespace App\Twig\Components;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\DefaultActionTrait; use Symfony\UX\LiveComponent\DefaultActionTrait;
#[AsLiveComponent] #[AsLiveComponent]
class UserMenu class UserMenu
{ {
use DefaultActionTrait; use DefaultActionTrait;
/** When true, render for the mobile header menu (not fixed in the left column). */
#[LiveProp]
public bool $inline = false;
} }

5
templates/components/Header.html.twig

@ -1,4 +1,4 @@
<header class="header" data-controller="menu" {{ attributes }}> <header id="site-header" class="header" data-controller="menu" {{ attributes }}>
<div class="header__logo"> <div class="header__logo">
<a href="/" class="header__brand"> <a href="/" class="header__brand">
<h1 class="brand"> <h1 class="brand">
@ -21,6 +21,9 @@
</li> </li>
{% endif %} {% endif %}
</ul> </ul>
<div class="header__mobile-account">
<twig:UserMenu :inline="true" />
</div>
</div> </div>
<div data-controller="progress-bar"> <div data-controller="progress-bar">
<div id="progress-bar" data-progress-bar-target="bar"></div> <div id="progress-bar" data-progress-bar-target="bar"></div>

2
templates/components/UserMenu.html.twig

@ -1,4 +1,4 @@
<div class="user-menu" {{ attributes.defaults(stimulus_controller('login')) }}> <div class="user-menu{{ inline ? ' user-menu--inline' : '' }}" {{ attributes.defaults(stimulus_controller('login')) }}>
{% if app.user %} {% if app.user %}
<div class="notice info"> <div class="notice info">
<twig:Molecules:UserFromNpub ident="{{ app.user.npub }}" /> <twig:Molecules:UserFromNpub ident="{{ app.user.npub }}" />

8
templates/pages/featured_authors.html.twig

@ -27,11 +27,15 @@
profile_websites: row.profile_websites, profile_websites: row.profile_websites,
profile_payment_links: row.profile_payment_links, profile_payment_links: row.profile_payment_links,
jumble_profile_href: row.jumble_profile_href, jumble_profile_href: row.jumble_profile_href,
omit_jumble_button: true,
} only %} } only %}
</div> </div>
<p class="featured-authors__more"> <div class="featured-authors__actions">
{% if row.jumble_profile_href is not null and row.jumble_profile_href != '' %}
<a class="btn btn-secondary" href="{{ row.jumble_profile_href|e('html_attr') }}" target="_blank" rel="nofollow noopener noreferrer">View on Jumble</a>
{% endif %}
<a class="btn btn-secondary" href="{{ path('author-profile', { npub: row.npub }) }}">Full profile</a> <a class="btn btn-secondary" href="{{ path('author-profile', { npub: row.npub }) }}">Full profile</a>
</p> </div>
</article> </article>
{% else %} {% else %}
<p class="text-subtle">No featured authors are listed yet. They appear when authors are added to magazine category indices and synced.</p> <p class="text-subtle">No featured authors are listed yet. They appear when authors are added to magazine category indices and synced.</p>

2
templates/partial/author_profile_header.html.twig

@ -78,7 +78,7 @@
{% endif %} {% endif %}
</div> </div>
{% if jumble_profile_href is not null and jumble_profile_href != '' %} {% if not omit_jumble_button|default(false) and jumble_profile_href is not null and jumble_profile_href != '' %}
<p class="author-profile__jumble"> <p class="author-profile__jumble">
<a class="btn btn-secondary" href="{{ jumble_profile_href|e('html_attr') }}" target="_blank" rel="nofollow noopener noreferrer">View on Jumble</a> <a class="btn btn-secondary" href="{{ jumble_profile_href|e('html_attr') }}" target="_blank" rel="nofollow noopener noreferrer">View on Jumble</a>
</p> </p>

Loading…
Cancel
Save