Files
ridebus-website/modules/home/changesCard/changesCard.module.scss
Zakhar Timoshenko 142ec97959 feat: add Open Graph image generation and SEO metadata
- Introduced `PageSeo` component for managing page metadata for social sharing.
- Created Open Graph image templates using SVG and static fonts for better visual representation.
- Implemented service alert management with functions to check active alerts and format route numbers.
- Added utility functions for generating and watching alert validity.
- Developed a script to generate Open Graph images dynamically based on page content.
- Included tests for service alert functionalities to ensure correctness and reliability.
2026-10-05 13:02:06 +03:00

239 lines
3.8 KiB
SCSS

.card {
--on-background: #2c4678;
--on-background-secondary: #455e91;
--background: #f3f3fa;
position: relative;
min-width: 0;
}
.content {
position: relative;
margin-top: 32px;
justify-content: flex-start;
}
.star {
position: absolute;
width: 300px;
height: 300px;
bottom: -130px;
left: -170px;
color: #d8e2ff;
transform: rotate(-12deg);
pointer-events: none;
}
.layout {
position: relative;
z-index: 1;
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 24px;
}
.controls {
display: flex;
flex-direction: column;
gap: 16px;
min-width: 0;
}
.note {
color: var(--on-background-secondary);
font-size: 0.9rem;
line-height: 1.6;
font-weight: 600;
}
.updated {
color: var(--on-background-secondary);
font-size: 0.75rem;
font-weight: 600;
}
.notices {
display: flex;
flex-direction: column;
gap: 16px;
min-width: 0;
align-items: flex-start;
}
.notice,
.state {
width: 100%;
padding: 24px;
border-radius: 24px;
background: #fff;
color: #2c4678;
animation: noticeIn 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.notice {
h4 {
margin-top: 16px;
font-size: 1.25rem;
line-height: 1.45;
font-weight: 800;
overflow-wrap: anywhere;
}
&:nth-child(2) {
animation-delay: 0.05s;
}
&:nth-child(3) {
animation-delay: 0.1s;
}
}
.badges {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.type,
.route {
min-width: 0;
max-width: 100%;
overflow-wrap: anywhere;
padding: 8px 12px;
border-radius: 40px;
font-size: 0.75rem;
font-weight: 700;
line-height: 1.4;
}
.info,
.route {
color: #2c4678;
background: #d8e2ff;
}
.delay,
.cancellation {
color: #861118;
background: #ffeef2;
}
.detour {
color: #254817;
background: #ddf9d0;
}
.message {
margin-top: 10px;
color: #455e91;
font-size: 0.95rem;
font-weight: 600;
line-height: 1.65;
white-space: pre-line;
overflow-wrap: anywhere;
}
.dates {
display: flex;
flex-wrap: wrap;
gap: 8px 20px;
margin-top: 20px;
font-size: 0.7rem;
line-height: 1.6;
font-weight: 600;
color: #455e91;
}
.state {
min-height: 240px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
gap: 16px;
h4 {
font-size: 1.25rem;
font-weight: 800;
}
p {
font-size: 0.95rem;
font-weight: 600;
line-height: 1.65;
color: #455e91;
}
}
.emptyIcon {
width: 56px;
height: 56px;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
background: #ddf9d0;
color: #254817;
transform: rotate(-6deg);
svg {
width: 28px;
height: 28px;
fill: currentColor;
}
}
.action {
padding: 14px 18px;
border: 0;
border-radius: 16px;
background: #d8e2ff;
color: #2c4678;
font: inherit;
font-size: 0.9rem;
font-weight: 700;
}
.action:focus-visible {
outline: 3px solid #2c4678;
outline-offset: 3px;
}
.loadingDots {
display: flex;
gap: 7px;
i {
width: 9px;
height: 9px;
border-radius: 50%;
background: #aec6ff;
animation: dotBounce 1.1s ease-in-out infinite;
}
i:nth-child(2) {
animation-delay: 0.12s;
}
i:nth-child(3) {
animation-delay: 0.24s;
}
}
@keyframes noticeIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes dotBounce {
0%,
100% {
transform: translateY(0);
opacity: 0.5;
}
50% {
transform: translateY(-4px);
opacity: 1;
}
}
@media (max-width: 500px) {
.card {
padding: 24px;
}
.notice,
.state {
padding: 20px;
}
.notice h4,
.state h4 {
font-size: 1.1rem;
}
.message,
.state p,
.note {
font-size: 0.85rem;
}
}
@media (prefers-reduced-motion: reduce) {
.notice,
.state,
.loadingDots i {
animation: none;
}
}