mirror of
https://github.com/dpnmw/community-landing.git
synced 2026-03-18 09:27:16 +00:00
Settings Navigation Repositioned
This commit is contained in:
@@ -153,90 +153,7 @@
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// 6. SMOOTH HORIZONTAL DRAG — trending discussions
|
||||
// Prevents link clicks during drag, smooth momentum scrolling
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
$$(".cl-topics__scroll").forEach(function (scrollEl) {
|
||||
var isDown = false;
|
||||
var startX = 0;
|
||||
var scrollStart = 0;
|
||||
var moved = false;
|
||||
var velX = 0;
|
||||
var lastX = 0;
|
||||
var lastTime = 0;
|
||||
var momentumId = null;
|
||||
|
||||
function stopMomentum() {
|
||||
if (momentumId) {
|
||||
cancelAnimationFrame(momentumId);
|
||||
momentumId = null;
|
||||
}
|
||||
}
|
||||
|
||||
function doMomentum() {
|
||||
if (Math.abs(velX) < 0.5) return;
|
||||
scrollEl.scrollLeft -= velX;
|
||||
velX *= 0.92;
|
||||
momentumId = requestAnimationFrame(doMomentum);
|
||||
}
|
||||
|
||||
scrollEl.addEventListener("mousedown", function (ev) {
|
||||
stopMomentum();
|
||||
isDown = true;
|
||||
moved = false;
|
||||
startX = ev.pageX;
|
||||
scrollStart = scrollEl.scrollLeft;
|
||||
lastX = ev.pageX;
|
||||
lastTime = Date.now();
|
||||
velX = 0;
|
||||
scrollEl.style.scrollSnapType = "none";
|
||||
scrollEl.style.userSelect = "none";
|
||||
});
|
||||
|
||||
window.addEventListener("mousemove", function (ev) {
|
||||
if (!isDown) return;
|
||||
var dx = ev.pageX - startX;
|
||||
if (Math.abs(dx) > 3) moved = true;
|
||||
var now = Date.now();
|
||||
var dt = now - lastTime;
|
||||
if (dt > 0) {
|
||||
velX = (ev.pageX - lastX) / dt * 16;
|
||||
}
|
||||
lastX = ev.pageX;
|
||||
lastTime = now;
|
||||
scrollEl.scrollLeft = scrollStart - dx;
|
||||
});
|
||||
|
||||
function endDrag() {
|
||||
if (!isDown) return;
|
||||
isDown = false;
|
||||
scrollEl.style.userSelect = "";
|
||||
if (Math.abs(velX) > 1) {
|
||||
doMomentum();
|
||||
}
|
||||
// Re-enable snap after a tick
|
||||
setTimeout(function () {
|
||||
scrollEl.style.scrollSnapType = "";
|
||||
}, 100);
|
||||
}
|
||||
|
||||
window.addEventListener("mouseup", endDrag);
|
||||
scrollEl.addEventListener("mouseleave", endDrag);
|
||||
|
||||
// Prevent link navigation if we dragged
|
||||
scrollEl.addEventListener("click", function (ev) {
|
||||
if (moved) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
moved = false;
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Touch support — native scrolling works, no extra handling needed
|
||||
});
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// 7. APP BADGE DETECTION
|
||||
// 6. APP BADGE DETECTION
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
var ua = navigator.userAgent || "";
|
||||
if (/iPhone|iPad|iPod/.test(ua)) $$(".cl-app-badge--ios").forEach(function (e) { e.classList.add("highlighted"); });
|
||||
|
||||
@@ -33,7 +33,7 @@ const TABS = [
|
||||
id: "stats",
|
||||
label: "Stats",
|
||||
settings: new Set([
|
||||
"stats_title", "stat_icon_color",
|
||||
"stats_title", "stat_icon_color", "stat_icon_bg_color", "stat_icon_shape", "stat_counter_color",
|
||||
"stat_members_label", "stat_topics_label", "stat_posts_label",
|
||||
"stat_likes_label", "stat_chats_label",
|
||||
"stats_bg_dark", "stats_bg_light", "stats_min_height", "stats_border_style"
|
||||
@@ -70,7 +70,7 @@ const TABS = [
|
||||
id: "groups",
|
||||
label: "Spaces",
|
||||
settings: new Set([
|
||||
"groups_enabled", "groups_title", "groups_count",
|
||||
"groups_enabled", "groups_title", "groups_count", "groups_selected", "groups_card_bg_color",
|
||||
"groups_bg_dark", "groups_bg_light", "groups_min_height", "groups_border_style"
|
||||
])
|
||||
},
|
||||
@@ -94,46 +94,73 @@ const TABS = [
|
||||
"footer_description", "footer_text", "footer_links",
|
||||
"footer_bg_dark", "footer_bg_light", "footer_border_style"
|
||||
])
|
||||
},
|
||||
{
|
||||
id: "css",
|
||||
label: "Custom CSS",
|
||||
settings: new Set(["custom_css"])
|
||||
}
|
||||
];
|
||||
|
||||
let currentTab = "general";
|
||||
let filterActive = false;
|
||||
let isActive = false;
|
||||
let recheckTimer = null;
|
||||
|
||||
function getContainer() {
|
||||
return (
|
||||
document.querySelector(".admin-plugin-config-area") ||
|
||||
document.querySelector(".admin-detail")
|
||||
);
|
||||
}
|
||||
|
||||
function applyTabFilter() {
|
||||
const container = getContainer();
|
||||
if (!container) return;
|
||||
|
||||
function applyTabFilter(container) {
|
||||
const tab = TABS.find((t) => t.id === currentTab);
|
||||
if (!tab) return;
|
||||
|
||||
container.querySelectorAll(".row.setting[data-setting]").forEach((row) => {
|
||||
const name = row.getAttribute("data-setting");
|
||||
row.style.display = tab.settings.has(name) ? "" : "none";
|
||||
row.classList.toggle(
|
||||
"cl-tab-hidden",
|
||||
!filterActive && !tab.settings.has(name)
|
||||
);
|
||||
});
|
||||
|
||||
const tabBar = container.querySelector(".cl-admin-tabs");
|
||||
if (tabBar) {
|
||||
tabBar.classList.toggle("filter-active", filterActive);
|
||||
}
|
||||
}
|
||||
|
||||
function findFilterInput(container) {
|
||||
for (const input of container.querySelectorAll("input")) {
|
||||
if (input.closest(".row.setting") || input.closest(".cl-admin-tabs")) {
|
||||
continue;
|
||||
}
|
||||
const t = (input.type || "text").toLowerCase();
|
||||
if (t === "text" || t === "search") return input;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function buildTabsUI() {
|
||||
const container =
|
||||
document.querySelector(".admin-plugin-config-area") ||
|
||||
document.querySelector(".admin-detail");
|
||||
const container = getContainer();
|
||||
if (!container) return false;
|
||||
|
||||
// Already injected?
|
||||
if (container.querySelector(".cl-admin-tabs")) return true;
|
||||
// Already injected — just re-apply filter
|
||||
if (container.querySelector(".cl-admin-tabs")) {
|
||||
applyTabFilter();
|
||||
return true;
|
||||
}
|
||||
|
||||
const allRows = container.querySelectorAll(".row.setting[data-setting]");
|
||||
if (allRows.length < 5) return false;
|
||||
|
||||
// Verify our settings are present
|
||||
const firstTab = TABS[0];
|
||||
// Verify our plugin settings are present
|
||||
const hasOurs = Array.from(allRows).some((row) =>
|
||||
firstTab.settings.has(row.getAttribute("data-setting"))
|
||||
TABS[0].settings.has(row.getAttribute("data-setting"))
|
||||
);
|
||||
if (!hasOurs) return false;
|
||||
|
||||
// Create tab bar
|
||||
// Build tab bar
|
||||
const tabBar = document.createElement("div");
|
||||
tabBar.className = "cl-admin-tabs";
|
||||
|
||||
@@ -141,30 +168,85 @@ function buildTabsUI() {
|
||||
const btn = document.createElement("button");
|
||||
btn.className = "cl-admin-tab" + (tab.id === currentTab ? " active" : "");
|
||||
btn.textContent = tab.label;
|
||||
btn.setAttribute("data-tab", tab.id);
|
||||
btn.dataset.tab = tab.id;
|
||||
btn.addEventListener("click", () => {
|
||||
currentTab = tab.id;
|
||||
filterActive = false;
|
||||
|
||||
// Clear Discourse filter input so it doesn't conflict
|
||||
const fi = findFilterInput(container);
|
||||
if (fi && fi.value) {
|
||||
fi.value = "";
|
||||
fi.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
}
|
||||
|
||||
tabBar
|
||||
.querySelectorAll(".cl-admin-tab")
|
||||
.forEach((b) => b.classList.remove("active"));
|
||||
btn.classList.add("active");
|
||||
applyTabFilter(container);
|
||||
applyTabFilter();
|
||||
});
|
||||
tabBar.appendChild(btn);
|
||||
});
|
||||
|
||||
// Insert tab bar before the first setting row
|
||||
const settingsParent = allRows[0].parentNode;
|
||||
settingsParent.insertBefore(tabBar, allRows[0]);
|
||||
// ── Insertion strategy: place tabs as high as possible ──
|
||||
|
||||
let inserted = false;
|
||||
|
||||
// Strategy 1: Top of .admin-plugin-config-area__content (above filter bar)
|
||||
const contentArea = container.querySelector(
|
||||
".admin-plugin-config-area__content"
|
||||
);
|
||||
if (contentArea) {
|
||||
const form = contentArea.querySelector("form");
|
||||
const target = form || contentArea;
|
||||
target.insertBefore(tabBar, target.firstChild);
|
||||
inserted = true;
|
||||
}
|
||||
|
||||
// Strategy 2: Before the filter controls
|
||||
if (!inserted) {
|
||||
const filterArea = container.querySelector(
|
||||
".admin-site-settings-filter-controls, .setting-filter"
|
||||
);
|
||||
if (filterArea) {
|
||||
filterArea.parentNode.insertBefore(tabBar, filterArea);
|
||||
inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Strategy 3: Before the first setting row (fallback)
|
||||
if (!inserted) {
|
||||
allRows[0].parentNode.insertBefore(tabBar, allRows[0]);
|
||||
}
|
||||
|
||||
// Add class to disable separator borders
|
||||
container.classList.add("cl-tabs-active");
|
||||
|
||||
// Apply initial filter
|
||||
applyTabFilter(container);
|
||||
applyTabFilter();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ── Global filter detection via event delegation ──
|
||||
// This survives DOM re-renders because it's on document, not on a specific input
|
||||
document.addEventListener(
|
||||
"input",
|
||||
(e) => {
|
||||
if (!isActive) return;
|
||||
const t = e.target;
|
||||
if (!t || !t.closest) return;
|
||||
if (t.closest(".row.setting") || t.closest(".cl-admin-tabs")) return;
|
||||
|
||||
const container = getContainer();
|
||||
if (!container || !container.contains(t)) return;
|
||||
|
||||
const hasText = t.value.trim().length > 0;
|
||||
if (hasText !== filterActive) {
|
||||
filterActive = hasText;
|
||||
applyTabFilter();
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
export default {
|
||||
name: "community-landing-admin-tabs",
|
||||
|
||||
@@ -175,6 +257,10 @@ export default {
|
||||
url.includes("community-landing") ||
|
||||
url.includes("community_landing")
|
||||
) {
|
||||
isActive = true;
|
||||
filterActive = false;
|
||||
|
||||
// Initial injection with retries
|
||||
let attempts = 0;
|
||||
const tryInject = () => {
|
||||
if (buildTabsUI() || attempts > 15) return;
|
||||
@@ -182,6 +268,28 @@ export default {
|
||||
setTimeout(tryInject, 200);
|
||||
};
|
||||
tryInject();
|
||||
|
||||
// Periodic re-check: re-injects tab bar if Discourse re-renders the DOM
|
||||
if (!recheckTimer) {
|
||||
recheckTimer = setInterval(() => {
|
||||
if (!isActive) {
|
||||
clearInterval(recheckTimer);
|
||||
recheckTimer = null;
|
||||
return;
|
||||
}
|
||||
const c = getContainer();
|
||||
if (c && !c.querySelector(".cl-admin-tabs")) {
|
||||
buildTabsUI();
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
} else {
|
||||
// Left plugin settings page — clean up
|
||||
isActive = false;
|
||||
if (recheckTimer) {
|
||||
clearInterval(recheckTimer);
|
||||
recheckTimer = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,13 +3,19 @@
|
||||
Tab navigation + fallback separators
|
||||
═══════════════════════════════════════════════════════════════════ */
|
||||
|
||||
/* ── Tab-hidden class (used instead of inline display:none) ── */
|
||||
|
||||
.cl-tab-hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* ── Tab Navigation ── */
|
||||
|
||||
.cl-admin-tabs {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0;
|
||||
margin: 0 0 24px 0;
|
||||
margin: 0 0 20px 0;
|
||||
padding: 0;
|
||||
border-bottom: 1px solid var(--primary-low, rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
@@ -24,7 +30,7 @@
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -1px;
|
||||
transition: color 0.15s ease, border-color 0.15s ease;
|
||||
transition: color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
|
||||
}
|
||||
|
||||
.cl-admin-tab:hover {
|
||||
@@ -36,6 +42,15 @@
|
||||
border-bottom-color: var(--tertiary, #0088cc);
|
||||
}
|
||||
|
||||
/* Dimmed state when Discourse filter/search is active */
|
||||
.cl-admin-tabs.filter-active .cl-admin-tab {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.cl-admin-tabs.filter-active .cl-admin-tab.active {
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
/* Dark mode tabs */
|
||||
html.dark-scheme .cl-admin-tabs {
|
||||
border-bottom-color: rgba(255, 255, 255, 0.1);
|
||||
@@ -75,8 +90,7 @@ html.dark-scheme .cl-admin-tab:hover {
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="ios_"],
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="android_"],
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="app_"],
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="footer_"],
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="custom_css"] {
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="footer_"] {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@@ -92,8 +106,7 @@ html.dark-scheme .cl-admin-tab:hover {
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="contributors_enabled"],
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="groups_enabled"],
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="show_app_ctas"],
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="footer_description"],
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="custom_css"] {
|
||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="footer_description"] {
|
||||
border-top: 2px solid rgba(0, 0, 0, 0.12);
|
||||
margin-top: 28px;
|
||||
padding-top: 24px;
|
||||
|
||||
@@ -329,7 +329,7 @@
|
||||
.cl-hero__actions { display: flex; flex-wrap: wrap; gap: 0.6rem; }
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════
|
||||
3. PREMIUM STATS — icon + label on one line, counter below
|
||||
3. PREMIUM STATS — icon with bg, label, animated counter
|
||||
═══════════════════════════════════════════════════════════════════ */
|
||||
.cl-stats { padding: 2.5rem 0 2rem; }
|
||||
|
||||
@@ -340,7 +340,7 @@
|
||||
@media (min-width: 1024px) { .cl-stats__grid { grid-template-columns: repeat(5, 1fr); } }
|
||||
|
||||
.cl-stat-card {
|
||||
display: flex; flex-direction: column; align-items: center; gap: 0.5rem;
|
||||
display: flex; flex-direction: column; align-items: center; gap: 0.6rem;
|
||||
padding: 1.5rem 1rem;
|
||||
background: var(--cl-card); border: 1px solid var(--cl-border);
|
||||
border-radius: var(--cl-radius); text-align: center;
|
||||
@@ -348,42 +348,74 @@
|
||||
}
|
||||
.cl-stat-card:hover { border-color: var(--cl-border-hover); transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0,0,0,0.08); }
|
||||
|
||||
/* Icon + Label on same line */
|
||||
.cl-stat-card__top {
|
||||
display: flex; align-items: center; gap: 0.4rem;
|
||||
/* Icon with background */
|
||||
.cl-stat-card__icon-wrap {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
width: 48px; height: 48px;
|
||||
background: var(--cl-stat-icon-bg);
|
||||
color: var(--cl-stat-icon-color);
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
.cl-stat-card__icon { color: var(--cl-stat-icon-color); display: flex; align-items: center; }
|
||||
.cl-stat-card__icon svg { width: 22px; height: 22px; }
|
||||
.cl-stat-card:hover .cl-stat-card__icon-wrap { transform: scale(1.08); }
|
||||
.cl-stat-card__icon-wrap svg { width: 24px; height: 24px; }
|
||||
.cl-stat-icon--circle { border-radius: 50%; }
|
||||
.cl-stat-icon--rounded { border-radius: 12px; }
|
||||
|
||||
.cl-stat-card__label {
|
||||
font-size: 0.78rem; color: var(--cl-muted);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Counter below */
|
||||
/* Counter */
|
||||
.cl-stat-card__value {
|
||||
font-size: 1.75rem; font-weight: 800;
|
||||
color: var(--cl-text-strong); letter-spacing: -0.02em;
|
||||
color: var(--cl-stat-counter-color); letter-spacing: -0.02em;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════
|
||||
4. ABOUT COMMUNITY — full-width gradient card
|
||||
4. ABOUT — split layout: image left on gradient, text right
|
||||
═══════════════════════════════════════════════════════════════════ */
|
||||
.cl-about { padding: 1rem 0 2rem; }
|
||||
.cl-about { padding: 1.5rem 0 2rem; }
|
||||
|
||||
.cl-about__card {
|
||||
background: var(--cl-about-gradient);
|
||||
border: 1px solid var(--cl-border);
|
||||
border-radius: 20px;
|
||||
padding: 2rem 2.5rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 16px rgba(0,0,0,0.04);
|
||||
background-size: cover; background-position: center;
|
||||
display: flex; flex-direction: column;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.cl-about__card { flex-direction: row; min-height: 340px; }
|
||||
}
|
||||
|
||||
/* Left side — image on gradient */
|
||||
.cl-about__left {
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding: 2rem;
|
||||
position: relative;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.cl-about__left { flex: 0 0 40%; max-width: 40%; }
|
||||
}
|
||||
.cl-about__image {
|
||||
width: 100%; max-width: 280px; height: auto;
|
||||
border-radius: 16px; object-fit: cover;
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,0.15);
|
||||
position: relative; z-index: 1;
|
||||
}
|
||||
|
||||
/* Right side — text content */
|
||||
.cl-about__right {
|
||||
flex: 1; padding: 2rem 2.5rem;
|
||||
display: flex; flex-direction: column; justify-content: center;
|
||||
}
|
||||
|
||||
.cl-about__heading {
|
||||
font-size: 1.35rem; font-weight: 800; color: var(--cl-text-strong);
|
||||
margin: 0 0 1rem;
|
||||
margin: 0 0 0.75rem;
|
||||
}
|
||||
|
||||
.cl-about__quote-mark {
|
||||
@@ -393,43 +425,32 @@
|
||||
|
||||
.cl-about__body {
|
||||
color: var(--cl-text); font-size: 0.95rem; line-height: 1.75;
|
||||
margin-bottom: 1rem; max-width: 800px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.cl-about__body p { margin: 0 0 0.75rem; }
|
||||
.cl-about__body a { color: var(--cl-accent); }
|
||||
|
||||
.cl-about__meta {
|
||||
display: flex; align-items: center; gap: 0.75rem;
|
||||
padding-top: 1rem; border-top: 1px solid var(--cl-border);
|
||||
}
|
||||
.cl-about__avatar {
|
||||
width: 44px; height: 44px; border-radius: 50%; object-fit: cover;
|
||||
border: 2px solid var(--cl-border);
|
||||
padding-top: 1rem; border-top: 1px solid rgba(0,0,0,0.08);
|
||||
}
|
||||
.cl-about__meta-text { display: flex; flex-direction: column; }
|
||||
.cl-about__author { font-size: 0.88rem; font-weight: 600; color: var(--cl-text-strong); }
|
||||
.cl-about__role { font-size: 0.78rem; color: var(--cl-muted); }
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════
|
||||
5. TRENDING DISCUSSIONS — horizontal scrollable cards
|
||||
5. TRENDING DISCUSSIONS — 4-per-row grid
|
||||
═══════════════════════════════════════════════════════════════════ */
|
||||
.cl-topics { padding: 1.5rem 0 2rem; }
|
||||
|
||||
.cl-topics__scroll {
|
||||
display: flex; gap: 0.75rem;
|
||||
overflow-x: auto; overflow-y: hidden;
|
||||
scroll-snap-type: x mandatory;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding-bottom: 0.75rem;
|
||||
scrollbar-width: none;
|
||||
cursor: grab;
|
||||
.cl-topics__grid {
|
||||
display: grid; grid-template-columns: repeat(1, 1fr); gap: 0.75rem;
|
||||
}
|
||||
.cl-topics__scroll::-webkit-scrollbar { display: none; }
|
||||
.cl-topics__scroll:active { cursor: grabbing; }
|
||||
@media (min-width: 480px) { .cl-topics__grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 768px) { .cl-topics__grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
@media (min-width: 1024px) { .cl-topics__grid { grid-template-columns: repeat(4, 1fr); } }
|
||||
|
||||
.cl-topic-card {
|
||||
flex: 0 0 230px;
|
||||
scroll-snap-align: start;
|
||||
display: flex; flex-direction: column;
|
||||
padding: 1.15rem 1.25rem;
|
||||
background: var(--cl-card);
|
||||
@@ -439,7 +460,6 @@
|
||||
transition: all 0.2s ease;
|
||||
min-height: 145px;
|
||||
}
|
||||
@media (min-width: 640px) { .cl-topic-card { flex: 0 0 250px; } }
|
||||
.cl-topic-card:hover { border-color: var(--cl-border-hover); transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0,0,0,0.08); }
|
||||
|
||||
.cl-topic-card__cat {
|
||||
@@ -500,7 +520,7 @@
|
||||
}
|
||||
|
||||
/* ═══════════════════════════════════════════════════════════════════
|
||||
7. COMMUNITY SPACES — large colored icon cards
|
||||
7. COMMUNITY SPACES — colored header cards
|
||||
═══════════════════════════════════════════════════════════════════ */
|
||||
.cl-spaces { padding: 1.5rem 0 2rem; }
|
||||
|
||||
@@ -512,31 +532,50 @@
|
||||
@media (min-width: 1024px) { .cl-spaces__grid { grid-template-columns: repeat(5, 1fr); } }
|
||||
|
||||
.cl-space-card {
|
||||
display: flex; flex-direction: column; align-items: center; gap: 0.6rem;
|
||||
padding: 1.5rem 1rem 1.25rem;
|
||||
background: var(--cl-card); border: 1px solid var(--cl-border);
|
||||
display: flex; flex-direction: column;
|
||||
background: var(--cl-space-card-bg); border: 1px solid var(--cl-border);
|
||||
border-radius: var(--cl-radius);
|
||||
text-decoration: none; text-align: center;
|
||||
text-decoration: none; overflow: hidden;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
.cl-space-card:hover { border-color: var(--cl-border-hover); transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0,0,0,0.08); }
|
||||
|
||||
/* Colored header band */
|
||||
.cl-space-card__header {
|
||||
background: var(--space-color);
|
||||
padding: 1.25rem 1rem;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
.cl-space-card__header::after {
|
||||
content: ""; position: absolute; inset: 0;
|
||||
background: linear-gradient(180deg, rgba(255,255,255,0.1), rgba(0,0,0,0.05));
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.cl-space-card__icon {
|
||||
width: 64px; height: 64px; border-radius: 16px;
|
||||
width: 52px; height: 52px; border-radius: 14px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
background: rgba(255,255,255,0.2);
|
||||
backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
|
||||
position: relative; z-index: 1;
|
||||
}
|
||||
.cl-space-card__icon img { width: 100%; height: 100%; object-fit: cover; }
|
||||
|
||||
.cl-space-card__letter {
|
||||
font-size: 1.6rem; font-weight: 800; color: #fff;
|
||||
font-size: 1.4rem; font-weight: 800; color: #fff;
|
||||
line-height: 1; text-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
/* Card body */
|
||||
.cl-space-card__body {
|
||||
padding: 0.85rem 1rem;
|
||||
display: flex; flex-direction: column; gap: 0.15rem;
|
||||
}
|
||||
.cl-space-card__name {
|
||||
font-size: 0.85rem; font-weight: 700; color: var(--cl-text-strong);
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
|
||||
font-size: 0.82rem; font-weight: 700; color: var(--cl-text-strong);
|
||||
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
||||
}
|
||||
.cl-space-card__sub { font-size: 0.72rem; color: var(--cl-muted); font-weight: 500; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user