mirror of
https://github.com/dpnmw/community-landing.git
synced 2026-03-18 09:27:16 +00:00
Major Improvements
Too numerous to mention
This commit is contained in:
@@ -1,5 +1,244 @@
|
|||||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
|
|
||||||
|
// Setting descriptions — injected into the admin DOM since the newer
|
||||||
|
// plugin settings page does not render .desc elements automatically.
|
||||||
|
const DESCRIPTIONS = {
|
||||||
|
// ── Master Switch ──
|
||||||
|
community_landing_enabled: "Enable the community landing page for logged-out visitors.",
|
||||||
|
|
||||||
|
// ── Layout ──
|
||||||
|
section_order: "Order of content sections. Drag to reorder. Available: hero, stats, about, participation, topics, groups, app_cta.",
|
||||||
|
custom_css: "Raw CSS injected after all plugin styles. Use for overrides and tweaks. No style tags needed.",
|
||||||
|
|
||||||
|
// ── SEO & Meta ──
|
||||||
|
meta_description: "Meta description for search engines and social sharing. If blank, the hero subtitle is used.",
|
||||||
|
og_image_url: "Open Graph image URL for social sharing (1200×630px recommended). If blank, the site logo is used.",
|
||||||
|
favicon_url: "Custom favicon URL (.ico, .png, .svg). If blank, the browser default is used.",
|
||||||
|
json_ld_enabled: "Add JSON-LD structured data (Organization + WebSite schema) for search engines.",
|
||||||
|
|
||||||
|
// ── Branding: Logo ──
|
||||||
|
logo_dark_url: "Logo image URL for dark mode. Shown in navbar and footer. Leave blank to show site name as text.",
|
||||||
|
logo_light_url: "Logo image URL for light mode. If not set, the dark logo is used for both themes.",
|
||||||
|
logo_height: "Logo height in pixels (16–80). Applies to both navbar and footer logos.",
|
||||||
|
footer_logo_url: "Override logo for the footer only. If not set, the navbar logo is reused.",
|
||||||
|
|
||||||
|
// ── Colors ──
|
||||||
|
accent_color: "Primary accent color: buttons, links, highlights, gradients, stat icons. Hex value.",
|
||||||
|
accent_hover_color: "Accent color on hover. Should be slightly lighter or darker than the accent.",
|
||||||
|
dark_bg_color: "Page background color for dark mode.",
|
||||||
|
light_bg_color: "Page background color for light mode.",
|
||||||
|
orb_color: "Color of decorative background orbs. Leave blank to use the accent color.",
|
||||||
|
orb_opacity: "Opacity of the background orbs (0–100). Default: 50.",
|
||||||
|
|
||||||
|
// ── Scroll Animations ──
|
||||||
|
scroll_animation: "How sections animate into view on scroll: fade_up, fade_in, slide_left, slide_right, zoom_in, flip_up, or none.",
|
||||||
|
staggered_reveal_enabled: "Animate child elements (cards, stats) with a staggered delay for a cascading reveal effect.",
|
||||||
|
dynamic_background_enabled: "Enable parallax background orbs that drift as the user scrolls.",
|
||||||
|
mouse_parallax_enabled: "Enable subtle parallax movement of background elements in response to mouse position.",
|
||||||
|
scroll_progress_enabled: "Show a thin progress bar at the top of the page indicating scroll position.",
|
||||||
|
|
||||||
|
// ── Fonts ──
|
||||||
|
google_font_name: "Google Font family for body text. Must match exact Google Fonts name (e.g. 'Inter', 'Poppins'). Default: Outfit.",
|
||||||
|
title_font_name: "Separate Google Font for titles and headings. Leave blank to use the body font.",
|
||||||
|
|
||||||
|
// ── Icons ──
|
||||||
|
fontawesome_enabled: "Load FontAwesome 6 Free icons from CDN for use on buttons.",
|
||||||
|
|
||||||
|
// ── Navbar ──
|
||||||
|
navbar_signin_label: "Text for the sign-in link in the navbar.",
|
||||||
|
navbar_signin_enabled: "Show the sign-in link in the navbar.",
|
||||||
|
navbar_signin_color_dark: "Sign-in link color for dark mode. Leave blank for default.",
|
||||||
|
navbar_signin_color_light: "Sign-in link color for light mode.",
|
||||||
|
navbar_join_label: "Text for the join/register CTA button in the navbar.",
|
||||||
|
navbar_join_enabled: "Show the join/register button in the navbar.",
|
||||||
|
navbar_join_color_dark: "Join button background color for dark mode. Leave blank for accent color.",
|
||||||
|
navbar_join_color_light: "Join button background color for light mode.",
|
||||||
|
navbar_bg_color: "Custom navbar background when scrolled. Leave blank for frosted glass effect.",
|
||||||
|
navbar_border_style: "Border style at the bottom of the navbar when scrolled.",
|
||||||
|
navbar_signin_icon: "FontAwesome icon name for sign-in (e.g. 'right-to-bracket'). Requires FontAwesome enabled.",
|
||||||
|
navbar_signin_icon_position: "Show the sign-in icon before or after the label.",
|
||||||
|
navbar_join_icon: "FontAwesome icon name for join button (e.g. 'user-plus'). Requires FontAwesome enabled.",
|
||||||
|
navbar_join_icon_position: "Show the join icon before or after the label.",
|
||||||
|
social_twitter_url: "Twitter / X profile URL. Leave blank to hide. Icons appear in navbar before auth buttons.",
|
||||||
|
social_facebook_url: "Facebook page or profile URL. Leave blank to hide.",
|
||||||
|
social_instagram_url: "Instagram profile URL. Leave blank to hide.",
|
||||||
|
social_youtube_url: "YouTube channel URL. Leave blank to hide.",
|
||||||
|
social_tiktok_url: "TikTok profile URL. Leave blank to hide.",
|
||||||
|
social_github_url: "GitHub organization or profile URL. Leave blank to hide.",
|
||||||
|
|
||||||
|
// ── Hero ──
|
||||||
|
hero_title: "Main headline text in the hero section.",
|
||||||
|
hero_title_size: "Hero title font size in pixels. 0 = use default responsive size.",
|
||||||
|
hero_accent_word: "Which word gets the accent shimmer. 0 = last word, 1 = first, 2 = second, etc.",
|
||||||
|
hero_subtitle: "Supporting text below the headline. Describe your community's purpose.",
|
||||||
|
hero_card_enabled: "Display hero content inside a rounded card with border and shadow.",
|
||||||
|
hero_image_first: "Show hero image above text on mobile / left on desktop. Off = text first.",
|
||||||
|
hero_background_image_url: "Full-bleed background image behind the hero. In card mode, fills the card with overlay.",
|
||||||
|
hero_image_urls: "Images for the right side of the hero. Up to 5 URLs — one shown randomly per page load.",
|
||||||
|
hero_image_max_height: "Maximum height for the hero image in pixels (100–1200).",
|
||||||
|
hero_primary_button_enabled: "Show the primary CTA button in the hero.",
|
||||||
|
hero_primary_button_label: "Text on the primary (filled, accent-colored) CTA button.",
|
||||||
|
hero_primary_button_url: "URL the primary button links to. Relative path or absolute URL.",
|
||||||
|
hero_secondary_button_enabled: "Show the secondary CTA button in the hero.",
|
||||||
|
hero_secondary_button_label: "Text on the secondary (outlined) CTA button.",
|
||||||
|
hero_secondary_button_url: "URL the secondary button links to.",
|
||||||
|
hero_primary_button_icon: "FontAwesome icon for primary button (e.g. 'rocket'). Leave blank for no icon.",
|
||||||
|
hero_primary_button_icon_position: "Show the primary button icon before or after the label.",
|
||||||
|
hero_secondary_button_icon: "FontAwesome icon for secondary button. Leave blank for no icon.",
|
||||||
|
hero_secondary_button_icon_position: "Show the secondary button icon before or after the label.",
|
||||||
|
hero_primary_btn_color_dark: "Primary button background for dark mode. Leave blank for accent color.",
|
||||||
|
hero_primary_btn_color_light: "Primary button background for light mode.",
|
||||||
|
hero_secondary_btn_color_dark: "Secondary button background for dark mode. Leave blank for glass style.",
|
||||||
|
hero_secondary_btn_color_light: "Secondary button background for light mode.",
|
||||||
|
hero_video_url: "Hero video URL (MP4 or YouTube). Play button opens a lightbox modal.",
|
||||||
|
hero_video_button_color: "Custom color for the video play button. Leave blank for accent color.",
|
||||||
|
hero_video_blur_on_hover: "Blur the hero image when hovering the play button.",
|
||||||
|
hero_bg_dark: "Hero section background for dark mode. Leave blank for default.",
|
||||||
|
hero_bg_light: "Hero section background for light mode.",
|
||||||
|
hero_min_height: "Minimum hero section height in pixels. 0 = auto height.",
|
||||||
|
hero_border_style: "Border style at the bottom of the hero section.",
|
||||||
|
hero_card_bg_dark: "Hero card overlay background for dark mode. Only in card mode.",
|
||||||
|
hero_card_bg_light: "Hero card overlay background for light mode.",
|
||||||
|
hero_card_opacity: "Hero card background opacity (0–1). Lower = more transparent. Default: 0.85.",
|
||||||
|
|
||||||
|
// ── Contributors (Hero Creators) ──
|
||||||
|
contributors_enabled: "Show top 3 creators in the hero with gold, silver, bronze badges.",
|
||||||
|
contributors_title: "Heading above the creators list.",
|
||||||
|
contributors_title_enabled: "Show the heading above the creators list.",
|
||||||
|
contributors_count_label: "Label before each creator's count (e.g. 'Cheers'). Blank = no prefix.",
|
||||||
|
contributors_count_label_enabled: "Show the count label prefix before activity counts.",
|
||||||
|
contributors_alignment: "Horizontal alignment of the creators list: center or left.",
|
||||||
|
contributors_pill_max_width: "Max width per creator pill card in pixels (200–600).",
|
||||||
|
contributors_pill_bg_dark: "Creator pill background for dark mode. Leave blank for glass styling.",
|
||||||
|
contributors_pill_bg_light: "Creator pill background for light mode.",
|
||||||
|
contributors_days: "Lookback period in days for calculating top contributors.",
|
||||||
|
contributors_count: "Number of top contributors to fetch (top 3 in hero, 4–10 in Participation).",
|
||||||
|
|
||||||
|
// ── Participation ──
|
||||||
|
participation_enabled: "Show Participation section: testimonial cards with leaderboard bios (positions 4–10).",
|
||||||
|
participation_title_enabled: "Show heading above participation cards.",
|
||||||
|
participation_title: "Heading text above participation cards.",
|
||||||
|
participation_bio_max_length: "Max characters from each user's bio (50–500). Longer bios are truncated.",
|
||||||
|
participation_icon_color: "Color for the decorative quote icon on cards. Leave blank for accent color.",
|
||||||
|
participation_card_bg_dark: "Participation card background for dark mode.",
|
||||||
|
participation_card_bg_light: "Participation card background for light mode.",
|
||||||
|
participation_bg_dark: "Section background for dark mode. Leave blank for default.",
|
||||||
|
participation_bg_light: "Section background for light mode.",
|
||||||
|
participation_min_height: "Minimum section height in pixels. 0 = auto.",
|
||||||
|
participation_border_style: "Border style at the bottom of the section.",
|
||||||
|
participation_title_size: "Section title font size in pixels. 0 = use default.",
|
||||||
|
|
||||||
|
// ── Stats ──
|
||||||
|
stats_enabled: "Show the stats section with live community counters.",
|
||||||
|
stat_labels_enabled: "Show text labels below stat counters (e.g. 'Members'). Off = numbers and icons only.",
|
||||||
|
stats_title_enabled: "Show section heading above the stats row.",
|
||||||
|
stats_title: "Section heading text above the stats.",
|
||||||
|
stats_title_size: "Stats title font size in pixels. 0 = use default.",
|
||||||
|
stat_card_style: "Stat card style: rectangle, rounded, pill, or minimal (no background).",
|
||||||
|
stat_icon_color: "Color for stat counter icons.",
|
||||||
|
stat_icon_bg_color: "Background behind each stat icon. Leave blank for subtle accent tint.",
|
||||||
|
stat_icon_shape: "Icon background shape: circle or rounded square.",
|
||||||
|
stat_counter_color: "Color for stat counter numbers. Leave blank for default text color.",
|
||||||
|
stat_members_label: "Custom label for the Members stat.",
|
||||||
|
stat_topics_label: "Custom label for the Topics stat.",
|
||||||
|
stat_posts_label: "Custom label for the Posts stat.",
|
||||||
|
stat_likes_label: "Custom label for the Likes stat.",
|
||||||
|
stat_chats_label: "Custom label for the Chats stat. Shows chat messages if Chat plugin is active.",
|
||||||
|
stat_round_numbers: "Round large numbers: 1000 → 1K, 12345 → 12.3K, 1234567 → 1.2M.",
|
||||||
|
stat_card_bg_dark: "Stat card background for dark mode.",
|
||||||
|
stat_card_bg_light: "Stat card background for light mode.",
|
||||||
|
stats_bg_dark: "Section background for dark mode. Leave blank for default.",
|
||||||
|
stats_bg_light: "Section background for light mode.",
|
||||||
|
stats_min_height: "Minimum section height in pixels. 0 = auto.",
|
||||||
|
stats_border_style: "Border style at the bottom of the stats section.",
|
||||||
|
|
||||||
|
// ── About ──
|
||||||
|
about_enabled: "Show the About section: card with heading, quote icon, description, and author attribution.",
|
||||||
|
about_heading_enabled: "Show the bold heading at the top of the About card.",
|
||||||
|
about_heading: "Heading text at the top of the About card (e.g. 'About Community').",
|
||||||
|
about_title: "Author or community name in the card's bottom attribution.",
|
||||||
|
about_title_size: "About heading font size in pixels. 0 = use default.",
|
||||||
|
about_role: "Subtitle below author name (e.g. 'Community Manager'). Blank = site name.",
|
||||||
|
about_body: "Main body text. Supports HTML: p, a, strong, em, ul, li, br.",
|
||||||
|
about_image_url: "Avatar image next to author name. Square images work best.",
|
||||||
|
about_card_color_dark: "About card background for dark mode.",
|
||||||
|
about_card_color_light: "About card background for light mode.",
|
||||||
|
about_background_image_url: "Background image on the card. Use a subtle pattern or texture.",
|
||||||
|
about_bg_dark: "Section background for dark mode. Leave blank for default.",
|
||||||
|
about_bg_light: "Section background for light mode.",
|
||||||
|
about_min_height: "Minimum section height in pixels. 0 = auto.",
|
||||||
|
about_border_style: "Border style at the bottom of the about section.",
|
||||||
|
|
||||||
|
// ── Trending ──
|
||||||
|
topics_enabled: "Show Trending Discussions: scrollable row of active topic cards with live data.",
|
||||||
|
topics_title_enabled: "Show heading above the topic cards.",
|
||||||
|
topics_title: "Heading text above the topic cards.",
|
||||||
|
topics_title_size: "Trending title font size in pixels. 0 = use default.",
|
||||||
|
topics_count: "Number of trending topic cards to display.",
|
||||||
|
topics_card_bg_dark: "Topic card background for dark mode.",
|
||||||
|
topics_card_bg_light: "Topic card background for light mode.",
|
||||||
|
topics_bg_dark: "Section background for dark mode. Leave blank for default.",
|
||||||
|
topics_bg_light: "Section background for light mode.",
|
||||||
|
topics_min_height: "Minimum section height in pixels. 0 = auto.",
|
||||||
|
topics_border_style: "Border style at the bottom of the trending section.",
|
||||||
|
|
||||||
|
// ── Spaces ──
|
||||||
|
groups_enabled: "Show Community Spaces: grid of group cards with icon, name, and member count.",
|
||||||
|
groups_title_enabled: "Show heading above group cards.",
|
||||||
|
groups_title: "Heading text above group cards.",
|
||||||
|
groups_title_size: "Spaces title font size in pixels. 0 = use default.",
|
||||||
|
groups_count: "Number of group cards to display.",
|
||||||
|
groups_selected: "Show only specific groups. Enter names separated by pipes (e.g. designers|developers). Blank = auto-select.",
|
||||||
|
groups_show_description: "Show group description text below the group name on each card.",
|
||||||
|
groups_description_max_length: "Max characters for group descriptions (30–500). Longer text is truncated.",
|
||||||
|
groups_card_bg_dark: "Space card background for dark mode.",
|
||||||
|
groups_card_bg_light: "Space card background for light mode.",
|
||||||
|
groups_bg_dark: "Section background for dark mode. Leave blank for default.",
|
||||||
|
groups_bg_light: "Section background for light mode.",
|
||||||
|
groups_min_height: "Minimum section height in pixels. 0 = auto.",
|
||||||
|
groups_border_style: "Border style at the bottom of the spaces section.",
|
||||||
|
|
||||||
|
// ── FAQ ──
|
||||||
|
faq_enabled: "Show FAQ accordion alongside the Spaces section. One item opens at a time.",
|
||||||
|
faq_title_enabled: "Show heading above the FAQ accordion.",
|
||||||
|
faq_title: "Heading text above the FAQ.",
|
||||||
|
faq_title_size: "FAQ title font size in pixels. 0 = use default.",
|
||||||
|
faq_items: 'FAQ items as JSON array: [{\"q\":\"Question\",\"a\":\"Answer\"}]. HTML supported in answers.',
|
||||||
|
faq_card_bg_dark: "FAQ card background for dark mode.",
|
||||||
|
faq_card_bg_light: "FAQ card background for light mode.",
|
||||||
|
|
||||||
|
// ── App CTA ──
|
||||||
|
show_app_ctas: "Show App Download CTA: gradient banner with headline, badges, and promo image.",
|
||||||
|
ios_app_url: "Apple App Store URL. Leave blank to hide iOS badge.",
|
||||||
|
android_app_url: "Google Play Store URL. Leave blank to hide Android badge.",
|
||||||
|
ios_app_badge_image_url: "Custom iOS badge image. Leave blank for default.",
|
||||||
|
android_app_badge_image_url: "Custom Android badge image. Leave blank for default.",
|
||||||
|
app_badge_height: "Badge height in pixels (30–80).",
|
||||||
|
app_badge_style: "Badge border-radius: rounded, pill, or square.",
|
||||||
|
app_cta_headline: "Bold headline in the app download banner.",
|
||||||
|
app_cta_title_size: "App CTA headline font size in pixels. 0 = use default.",
|
||||||
|
app_cta_subtext: "Supporting text below the headline.",
|
||||||
|
app_cta_gradient_start_dark: "Gradient start color for dark mode. Leave blank for accent.",
|
||||||
|
app_cta_gradient_start_light: "Gradient start color for light mode.",
|
||||||
|
app_cta_gradient_mid_dark: "Gradient middle color for dark mode.",
|
||||||
|
app_cta_gradient_mid_light: "Gradient middle color for light mode.",
|
||||||
|
app_cta_gradient_end_dark: "Gradient end color for dark mode.",
|
||||||
|
app_cta_gradient_end_light: "Gradient end color for light mode.",
|
||||||
|
app_cta_image_url: "Promo image on the right (e.g. phone mockup). PNG for transparent bg.",
|
||||||
|
app_cta_bg_dark: "Section background for dark mode. Leave blank for default.",
|
||||||
|
app_cta_bg_light: "Section background for light mode.",
|
||||||
|
app_cta_min_height: "Minimum section height in pixels. 0 = auto.",
|
||||||
|
app_cta_border_style: "Border style at the bottom of the app CTA section.",
|
||||||
|
|
||||||
|
// ── Footer ──
|
||||||
|
footer_description: "Description paragraph above the footer bar.",
|
||||||
|
footer_text: "Optional HTML text inside the footer bar. Supports: p, a, strong, em, ul, li, br.",
|
||||||
|
footer_links: 'Footer links as JSON array: [{\"label\":\"Terms\",\"url\":\"/tos\"}].',
|
||||||
|
footer_bg_dark: "Footer background for dark mode. Leave blank for default.",
|
||||||
|
footer_bg_light: "Footer background for light mode.",
|
||||||
|
footer_border_style: "Border style at the top of the footer bar.",
|
||||||
|
};
|
||||||
|
|
||||||
const TABS = [
|
const TABS = [
|
||||||
{
|
{
|
||||||
id: "settings",
|
id: "settings",
|
||||||
@@ -10,8 +249,10 @@ const TABS = [
|
|||||||
"meta_description", "og_image_url", "favicon_url", "json_ld_enabled",
|
"meta_description", "og_image_url", "favicon_url", "json_ld_enabled",
|
||||||
"logo_dark_url", "logo_light_url", "logo_height", "footer_logo_url",
|
"logo_dark_url", "logo_light_url", "logo_height", "footer_logo_url",
|
||||||
"accent_color", "accent_hover_color", "dark_bg_color", "light_bg_color",
|
"accent_color", "accent_hover_color", "dark_bg_color", "light_bg_color",
|
||||||
|
"orb_color", "orb_opacity",
|
||||||
"scroll_animation", "staggered_reveal_enabled", "dynamic_background_enabled",
|
"scroll_animation", "staggered_reveal_enabled", "dynamic_background_enabled",
|
||||||
"mouse_parallax_enabled", "scroll_progress_enabled"
|
"mouse_parallax_enabled", "scroll_progress_enabled",
|
||||||
|
"google_font_name", "title_font_name", "fontawesome_enabled"
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -22,6 +263,8 @@ const TABS = [
|
|||||||
"navbar_signin_color_dark", "navbar_signin_color_light",
|
"navbar_signin_color_dark", "navbar_signin_color_light",
|
||||||
"navbar_join_label", "navbar_join_enabled",
|
"navbar_join_label", "navbar_join_enabled",
|
||||||
"navbar_join_color_dark", "navbar_join_color_light",
|
"navbar_join_color_dark", "navbar_join_color_light",
|
||||||
|
"navbar_signin_icon", "navbar_signin_icon_position",
|
||||||
|
"navbar_join_icon", "navbar_join_icon_position",
|
||||||
"navbar_bg_color", "navbar_border_style",
|
"navbar_bg_color", "navbar_border_style",
|
||||||
"social_twitter_url", "social_facebook_url", "social_instagram_url",
|
"social_twitter_url", "social_facebook_url", "social_instagram_url",
|
||||||
"social_youtube_url", "social_tiktok_url", "social_github_url"
|
"social_youtube_url", "social_tiktok_url", "social_github_url"
|
||||||
@@ -31,11 +274,13 @@ const TABS = [
|
|||||||
id: "hero",
|
id: "hero",
|
||||||
label: "Hero",
|
label: "Hero",
|
||||||
settings: new Set([
|
settings: new Set([
|
||||||
"hero_title", "hero_accent_word", "hero_subtitle",
|
"hero_title", "hero_accent_word", "hero_subtitle", "hero_title_size",
|
||||||
"hero_card_enabled", "hero_image_first",
|
"hero_card_enabled", "hero_image_first",
|
||||||
"hero_background_image_url", "hero_image_urls", "hero_image_max_height",
|
"hero_background_image_url", "hero_image_urls", "hero_image_max_height",
|
||||||
"hero_primary_button_enabled", "hero_primary_button_label", "hero_primary_button_url",
|
"hero_primary_button_enabled", "hero_primary_button_label", "hero_primary_button_url",
|
||||||
|
"hero_primary_button_icon", "hero_primary_button_icon_position",
|
||||||
"hero_secondary_button_enabled", "hero_secondary_button_label", "hero_secondary_button_url",
|
"hero_secondary_button_enabled", "hero_secondary_button_label", "hero_secondary_button_url",
|
||||||
|
"hero_secondary_button_icon", "hero_secondary_button_icon_position",
|
||||||
"hero_primary_btn_color_dark", "hero_primary_btn_color_light",
|
"hero_primary_btn_color_dark", "hero_primary_btn_color_light",
|
||||||
"hero_secondary_btn_color_dark", "hero_secondary_btn_color_light",
|
"hero_secondary_btn_color_dark", "hero_secondary_btn_color_light",
|
||||||
"hero_video_url", "hero_video_button_color", "hero_video_blur_on_hover",
|
"hero_video_url", "hero_video_button_color", "hero_video_blur_on_hover",
|
||||||
@@ -53,7 +298,8 @@ const TABS = [
|
|||||||
label: "Participation",
|
label: "Participation",
|
||||||
settings: new Set([
|
settings: new Set([
|
||||||
"participation_enabled", "participation_title_enabled",
|
"participation_enabled", "participation_title_enabled",
|
||||||
"participation_title", "participation_bio_max_length",
|
"participation_title", "participation_title_size",
|
||||||
|
"participation_bio_max_length",
|
||||||
"participation_icon_color",
|
"participation_icon_color",
|
||||||
"participation_card_bg_dark", "participation_card_bg_light",
|
"participation_card_bg_dark", "participation_card_bg_light",
|
||||||
"participation_bg_dark", "participation_bg_light",
|
"participation_bg_dark", "participation_bg_light",
|
||||||
@@ -65,7 +311,7 @@ const TABS = [
|
|||||||
label: "Stats",
|
label: "Stats",
|
||||||
settings: new Set([
|
settings: new Set([
|
||||||
"stats_enabled", "stat_labels_enabled", "stats_title_enabled",
|
"stats_enabled", "stat_labels_enabled", "stats_title_enabled",
|
||||||
"stats_title", "stat_card_style",
|
"stats_title", "stats_title_size", "stat_card_style",
|
||||||
"stat_icon_color", "stat_icon_bg_color", "stat_icon_shape", "stat_counter_color",
|
"stat_icon_color", "stat_icon_bg_color", "stat_icon_shape", "stat_counter_color",
|
||||||
"stat_members_label", "stat_topics_label", "stat_posts_label",
|
"stat_members_label", "stat_topics_label", "stat_posts_label",
|
||||||
"stat_likes_label", "stat_chats_label", "stat_round_numbers",
|
"stat_likes_label", "stat_chats_label", "stat_round_numbers",
|
||||||
@@ -78,7 +324,7 @@ const TABS = [
|
|||||||
label: "About",
|
label: "About",
|
||||||
settings: new Set([
|
settings: new Set([
|
||||||
"about_enabled", "about_heading_enabled", "about_heading",
|
"about_enabled", "about_heading_enabled", "about_heading",
|
||||||
"about_title", "about_role", "about_body", "about_image_url",
|
"about_title", "about_title_size", "about_role", "about_body", "about_image_url",
|
||||||
"about_card_color_dark", "about_card_color_light",
|
"about_card_color_dark", "about_card_color_light",
|
||||||
"about_background_image_url",
|
"about_background_image_url",
|
||||||
"about_bg_dark", "about_bg_light", "about_min_height", "about_border_style"
|
"about_bg_dark", "about_bg_light", "about_min_height", "about_border_style"
|
||||||
@@ -88,21 +334,30 @@ const TABS = [
|
|||||||
id: "topics",
|
id: "topics",
|
||||||
label: "Trending",
|
label: "Trending",
|
||||||
settings: new Set([
|
settings: new Set([
|
||||||
"topics_enabled", "topics_title_enabled", "topics_title", "topics_count",
|
"topics_enabled", "topics_title_enabled", "topics_title", "topics_title_size",
|
||||||
|
"topics_count",
|
||||||
"topics_card_bg_dark", "topics_card_bg_light",
|
"topics_card_bg_dark", "topics_card_bg_light",
|
||||||
"topics_bg_dark", "topics_bg_light", "topics_min_height", "topics_border_style"
|
"topics_bg_dark", "topics_bg_light", "topics_min_height", "topics_border_style"
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "groups",
|
id: "groups",
|
||||||
label: "Spaces & FAQ",
|
label: "Spaces",
|
||||||
settings: new Set([
|
settings: new Set([
|
||||||
"groups_enabled", "groups_title_enabled", "groups_title", "groups_count",
|
"groups_enabled", "groups_title_enabled", "groups_title", "groups_title_size",
|
||||||
"groups_selected",
|
"groups_count", "groups_selected",
|
||||||
"groups_show_description", "groups_description_max_length",
|
"groups_show_description", "groups_description_max_length",
|
||||||
"groups_card_bg_dark", "groups_card_bg_light",
|
"groups_card_bg_dark", "groups_card_bg_light",
|
||||||
"groups_bg_dark", "groups_bg_light", "groups_min_height", "groups_border_style",
|
"groups_bg_dark", "groups_bg_light", "groups_min_height", "groups_border_style"
|
||||||
"faq_enabled", "faq_title_enabled", "faq_title", "faq_items"
|
])
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "faq",
|
||||||
|
label: "FAQ",
|
||||||
|
settings: new Set([
|
||||||
|
"faq_enabled", "faq_title_enabled", "faq_title", "faq_title_size",
|
||||||
|
"faq_items",
|
||||||
|
"faq_card_bg_dark", "faq_card_bg_light"
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -112,7 +367,7 @@ const TABS = [
|
|||||||
"show_app_ctas", "ios_app_url", "android_app_url",
|
"show_app_ctas", "ios_app_url", "android_app_url",
|
||||||
"ios_app_badge_image_url", "android_app_badge_image_url",
|
"ios_app_badge_image_url", "android_app_badge_image_url",
|
||||||
"app_badge_height", "app_badge_style",
|
"app_badge_height", "app_badge_style",
|
||||||
"app_cta_headline", "app_cta_subtext",
|
"app_cta_headline", "app_cta_title_size", "app_cta_subtext",
|
||||||
"app_cta_gradient_start_dark", "app_cta_gradient_start_light",
|
"app_cta_gradient_start_dark", "app_cta_gradient_start_light",
|
||||||
"app_cta_gradient_mid_dark", "app_cta_gradient_mid_light",
|
"app_cta_gradient_mid_dark", "app_cta_gradient_mid_light",
|
||||||
"app_cta_gradient_end_dark", "app_cta_gradient_end_light",
|
"app_cta_gradient_end_dark", "app_cta_gradient_end_light",
|
||||||
@@ -156,6 +411,8 @@ const BG_PAIRS = [
|
|||||||
// Spaces
|
// Spaces
|
||||||
["groups_card_bg_dark", "groups_card_bg_light"],
|
["groups_card_bg_dark", "groups_card_bg_light"],
|
||||||
["groups_bg_dark", "groups_bg_light"],
|
["groups_bg_dark", "groups_bg_light"],
|
||||||
|
// FAQ
|
||||||
|
["faq_card_bg_dark", "faq_card_bg_light"],
|
||||||
// App CTA
|
// App CTA
|
||||||
["app_cta_gradient_start_dark", "app_cta_gradient_start_light"],
|
["app_cta_gradient_start_dark", "app_cta_gradient_start_light"],
|
||||||
["app_cta_gradient_mid_dark", "app_cta_gradient_mid_light"],
|
["app_cta_gradient_mid_dark", "app_cta_gradient_mid_light"],
|
||||||
@@ -185,8 +442,6 @@ function applyTabFilter() {
|
|||||||
if (!tab) return;
|
if (!tab) return;
|
||||||
|
|
||||||
container.querySelectorAll(".row.setting[data-setting]").forEach((row) => {
|
container.querySelectorAll(".row.setting[data-setting]").forEach((row) => {
|
||||||
// Skip rows inside a merge wrapper — handled at wrapper level
|
|
||||||
if (row.closest(".cl-merge-wrapper")) return;
|
|
||||||
const name = row.getAttribute("data-setting");
|
const name = row.getAttribute("data-setting");
|
||||||
row.classList.toggle(
|
row.classList.toggle(
|
||||||
"cl-tab-hidden",
|
"cl-tab-hidden",
|
||||||
@@ -194,17 +449,6 @@ function applyTabFilter() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle merge wrappers — show/hide based on dark row's setting
|
|
||||||
container.querySelectorAll(".cl-merge-wrapper").forEach((wrapper) => {
|
|
||||||
const darkRow = wrapper.querySelector(".cl-merged-dark");
|
|
||||||
if (!darkRow) return;
|
|
||||||
const name = darkRow.getAttribute("data-setting");
|
|
||||||
wrapper.classList.toggle(
|
|
||||||
"cl-tab-hidden",
|
|
||||||
!filterActive && !tab.settings.has(name)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update filter-active dimming on native nav or standalone tab bar
|
// Update filter-active dimming on native nav or standalone tab bar
|
||||||
const nativeNav = document.querySelector(".d-nav-submenu__tabs");
|
const nativeNav = document.querySelector(".d-nav-submenu__tabs");
|
||||||
if (nativeNav) {
|
if (nativeNav) {
|
||||||
@@ -294,15 +538,9 @@ function cleanupTabs() {
|
|||||||
el.classList.remove("cl-tab-hidden");
|
el.classList.remove("cl-tab-hidden");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Unwrap merge wrappers — restore rows to their original position
|
// Remove merge classes
|
||||||
container.querySelectorAll(".cl-merge-wrapper").forEach((wrapper) => {
|
container.querySelectorAll(".cl-merged-dark, .cl-merged-light").forEach((el) => {
|
||||||
const parent = wrapper.parentNode;
|
el.classList.remove("cl-merged-dark", "cl-merged-light");
|
||||||
while (wrapper.firstChild) {
|
|
||||||
const child = wrapper.firstChild;
|
|
||||||
child.classList.remove("cl-merged-dark", "cl-merged-light");
|
|
||||||
parent.insertBefore(child, wrapper);
|
|
||||||
}
|
|
||||||
wrapper.remove();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,10 +549,37 @@ function cleanupTabs() {
|
|||||||
filterActive = false;
|
filterActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject description text into each setting row.
|
||||||
|
* The newer Discourse plugin admin page doesn't render .desc elements,
|
||||||
|
* so we add them from the DESCRIPTIONS map.
|
||||||
|
*/
|
||||||
|
function injectDescriptions() {
|
||||||
|
const container = getContainer();
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
container.querySelectorAll(".row.setting[data-setting]").forEach((row) => {
|
||||||
|
const name = row.getAttribute("data-setting");
|
||||||
|
const text = DESCRIPTIONS[name];
|
||||||
|
if (!text) return;
|
||||||
|
|
||||||
|
const valueDiv = row.querySelector(".setting-value");
|
||||||
|
if (!valueDiv) return;
|
||||||
|
|
||||||
|
// Already injected
|
||||||
|
if (valueDiv.querySelector(".cl-desc")) return;
|
||||||
|
|
||||||
|
const desc = document.createElement("div");
|
||||||
|
desc.className = "cl-desc";
|
||||||
|
desc.textContent = text;
|
||||||
|
valueDiv.appendChild(desc);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge dark/light bg color pairs into a single visual row.
|
* Merge dark/light bg color pairs into a single visual row.
|
||||||
* Uses a CSS wrapper approach — both rows stay intact in the DOM
|
* CSS-only approach — elements stay in their original DOM positions
|
||||||
* (preserving Ember bindings and undo/reset buttons).
|
* (preserving Ember bindings, undo/reset buttons, and re-renders).
|
||||||
*/
|
*/
|
||||||
function mergeBgPairs() {
|
function mergeBgPairs() {
|
||||||
const container = getContainer();
|
const container = getContainer();
|
||||||
@@ -349,17 +614,9 @@ function mergeBgPairs() {
|
|||||||
lightValue.insertBefore(lbl, lightValue.firstChild);
|
lightValue.insertBefore(lbl, lightValue.firstChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap both rows in a flex container
|
// Just add classes — NO DOM moves, preserves all Ember bindings
|
||||||
const wrapper = document.createElement("div");
|
|
||||||
wrapper.className = "cl-merge-wrapper";
|
|
||||||
darkRow.parentNode.insertBefore(wrapper, darkRow);
|
|
||||||
wrapper.appendChild(darkRow);
|
|
||||||
wrapper.appendChild(lightRow);
|
|
||||||
|
|
||||||
// Mark rows for CSS styling
|
|
||||||
darkRow.classList.add("cl-merged-dark");
|
darkRow.classList.add("cl-merged-dark");
|
||||||
lightRow.classList.add("cl-merged-light");
|
lightRow.classList.add("cl-merged-light");
|
||||||
// Light row is NOT hidden — it stays in the DOM with full Ember bindings
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,6 +680,7 @@ function buildTabsUI() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
container.classList.add("cl-tabs-active");
|
container.classList.add("cl-tabs-active");
|
||||||
|
injectDescriptions();
|
||||||
mergeBgPairs();
|
mergeBgPairs();
|
||||||
applyTabFilter();
|
applyTabFilter();
|
||||||
return true;
|
return true;
|
||||||
@@ -468,6 +726,7 @@ function buildTabsUI() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
container.classList.add("cl-tabs-active");
|
container.classList.add("cl-tabs-active");
|
||||||
|
injectDescriptions();
|
||||||
mergeBgPairs();
|
mergeBgPairs();
|
||||||
applyTabFilter();
|
applyTabFilter();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -82,37 +82,76 @@ html.dark-scheme .cl-admin-tabs .cl-admin-tab:hover {
|
|||||||
color: var(--primary, #ddd);
|
color: var(--primary, #ddd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Merged dark/light color pairs (wrapper approach) ── */
|
/* ── Merged dark/light color pairs (CSS-only, no DOM moves) ── */
|
||||||
|
|
||||||
.cl-merge-wrapper {
|
.cl-tabs-active .row.setting.cl-merged-dark {
|
||||||
display: flex;
|
float: left;
|
||||||
gap: 16px;
|
width: calc(50% - 8px);
|
||||||
width: 100%;
|
margin-right: 16px;
|
||||||
padding-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cl-merge-wrapper > .row.setting {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
padding-bottom: 0 !important;
|
padding-bottom: 0 !important;
|
||||||
margin-bottom: 0 !important;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cl-tabs-active .row.setting.cl-merged-light {
|
||||||
|
float: left;
|
||||||
|
width: calc(50% - 8px);
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
margin-bottom: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* Hide the light row's label + description — dark row's label covers both */
|
/* Hide the light row's label + description — dark row's label covers both */
|
||||||
.cl-merge-wrapper > .cl-merged-light > .setting-label {
|
.cl-tabs-active .row.setting.cl-merged-light > .setting-label {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cl-merge-wrapper > .cl-merged-light .desc {
|
.cl-tabs-active .row.setting.cl-merged-light .desc {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Light row's value area fills the full width since label is hidden */
|
/* Light row's value area fills the full width since label is hidden */
|
||||||
.cl-tabs-active .cl-merge-wrapper > .cl-merged-light > .setting-value {
|
.cl-tabs-active .row.setting.cl-merged-light > .setting-value {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
float: none;
|
float: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dark row: label + value stack vertically inside the half-width */
|
||||||
|
.cl-tabs-active .row.setting.cl-merged-dark > .setting-label {
|
||||||
|
float: none;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cl-tabs-active .row.setting.cl-merged-dark > .setting-value {
|
||||||
|
float: none;
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Controls (reset/undo) inside merged rows — inline after the color picker */
|
||||||
|
.cl-tabs-active .row.setting.cl-merged-dark > .setting-controls,
|
||||||
|
.cl-tabs-active .row.setting.cl-merged-light > .setting-controls {
|
||||||
|
float: none;
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clearfix after the light row to restore normal flow */
|
||||||
|
.cl-tabs-active .row.setting.cl-merged-light::after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert a clear break after each pair to prevent stacking issues */
|
||||||
|
.cl-tabs-active .row.setting.cl-merged-light + .row.setting:not(.cl-merged-light) {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also clear when a merged-light is followed by anything else */
|
||||||
|
.cl-tabs-active .cl-merged-light + *:not(.cl-merged-light):not(.cl-tab-hidden) {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
.cl-color-col__label {
|
.cl-color-col__label {
|
||||||
display: block;
|
display: block;
|
||||||
font-size: var(--font-down-1);
|
font-size: var(--font-down-1);
|
||||||
@@ -124,12 +163,14 @@ html.dark-scheme .cl-admin-tabs .cl-admin-tab:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
.cl-merge-wrapper {
|
.cl-tabs-active .row.setting.cl-merged-dark,
|
||||||
flex-direction: column;
|
.cl-tabs-active .row.setting.cl-merged-light {
|
||||||
gap: 0;
|
float: none;
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cl-merge-wrapper > .cl-merged-light > .setting-label {
|
.cl-tabs-active .row.setting.cl-merged-light > .setting-label {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +215,10 @@ html.dark-scheme .cl-admin-tabs .cl-admin-tab:hover {
|
|||||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="android_"],
|
.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^="app_"],
|
||||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="social_"],
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="social_"],
|
||||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="footer_"] {
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="footer_"],
|
||||||
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="google_"],
|
||||||
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting^="title_font"],
|
||||||
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="fontawesome_enabled"] {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +229,8 @@ html.dark-scheme .cl-admin-tabs .cl-admin-tab:hover {
|
|||||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="logo_dark_url"],
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="logo_dark_url"],
|
||||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="accent_color"],
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="accent_color"],
|
||||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="scroll_animation"],
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="scroll_animation"],
|
||||||
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="google_font_name"],
|
||||||
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="fontawesome_enabled"],
|
||||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="social_twitter_url"],
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="social_twitter_url"],
|
||||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="navbar_signin_label"],
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="navbar_signin_label"],
|
||||||
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="hero_title"],
|
.admin-detail:not(.cl-tabs-active) .row.setting[data-setting="hero_title"],
|
||||||
@@ -208,6 +254,8 @@ html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="m
|
|||||||
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="logo_dark_url"],
|
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="logo_dark_url"],
|
||||||
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="accent_color"],
|
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="accent_color"],
|
||||||
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="scroll_animation"],
|
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="scroll_animation"],
|
||||||
|
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="google_font_name"],
|
||||||
|
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="fontawesome_enabled"],
|
||||||
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="social_twitter_url"],
|
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="social_twitter_url"],
|
||||||
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="navbar_signin_label"],
|
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="navbar_signin_label"],
|
||||||
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="hero_title"],
|
html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="hero_title"],
|
||||||
@@ -298,13 +346,15 @@ html.dark-scheme .admin-detail:not(.cl-tabs-active) .row.setting[data-setting="f
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cl-tabs-active .row.setting .desc,
|
.cl-tabs-active .row.setting .desc,
|
||||||
|
.cl-tabs-active .row.setting .cl-desc,
|
||||||
.cl-tabs-active .row.setting .validation-error {
|
.cl-tabs-active .row.setting .validation-error {
|
||||||
padding-top: 3px;
|
padding-top: 3px;
|
||||||
font-size: var(--font-down-1);
|
font-size: var(--font-down-1);
|
||||||
line-height: var(--line-height-large);
|
line-height: var(--line-height-large);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cl-tabs-active .row.setting .desc {
|
.cl-tabs-active .row.setting .desc,
|
||||||
|
.cl-tabs-active .row.setting .cl-desc {
|
||||||
color: var(--primary-medium);
|
color: var(--primary-medium);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
background: var(--cl-bg);
|
background: var(--cl-bg);
|
||||||
color: var(--cl-text);
|
color: var(--cl-text);
|
||||||
font-family: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
font-family: var(--cl-font-body, 'Outfit'), -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
@@ -177,7 +177,7 @@ html {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
filter: blur(100px);
|
filter: blur(100px);
|
||||||
opacity: 0.5;
|
opacity: var(--cl-orb-opacity, 0.5);
|
||||||
animation: cl-orb-float 20s infinite alternate ease-in-out;
|
animation: cl-orb-float 20s infinite alternate ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,6 +223,7 @@ html {
|
|||||||
.cl-section-title {
|
.cl-section-title {
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
font-weight: 800;
|
font-weight: 800;
|
||||||
|
font-family: var(--cl-font-title, var(--cl-font-body, 'Outfit')), sans-serif;
|
||||||
color: var(--cl-text-strong);
|
color: var(--cl-text-strong);
|
||||||
margin: 0 0 2.5rem;
|
margin: 0 0 2.5rem;
|
||||||
letter-spacing: -0.02em;
|
letter-spacing: -0.02em;
|
||||||
@@ -380,6 +381,11 @@ html {
|
|||||||
font-size: 1.05rem;
|
font-size: 1.05rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* FontAwesome icon spacing inside buttons */
|
||||||
|
.cl-btn i.fa-solid {
|
||||||
|
margin: 0 0.35em;
|
||||||
|
}
|
||||||
|
|
||||||
/* ═══════════════════════════════════════════════════════════════════
|
/* ═══════════════════════════════════════════════════════════════════
|
||||||
1. NAVBAR — logo left, theme toggle + auth right
|
1. NAVBAR — logo left, theme toggle + auth right
|
||||||
═══════════════════════════════════════════════════════════════════ */
|
═══════════════════════════════════════════════════════════════════ */
|
||||||
@@ -731,6 +737,7 @@ html {
|
|||||||
.cl-hero__title {
|
.cl-hero__title {
|
||||||
font-size: clamp(2.5rem, 8vw, 4.5rem);
|
font-size: clamp(2.5rem, 8vw, 4.5rem);
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
|
font-family: var(--cl-font-title, var(--cl-font-body, 'Outfit')), sans-serif;
|
||||||
color: var(--cl-hero-text);
|
color: var(--cl-hero-text);
|
||||||
margin: 0 0 1.5rem;
|
margin: 0 0 1.5rem;
|
||||||
line-height: 0.95;
|
line-height: 0.95;
|
||||||
@@ -1552,6 +1559,15 @@ html {
|
|||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cl-spaces__col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cl-spaces__col .cl-section-title {
|
||||||
|
font-size: 1.3rem;
|
||||||
|
}
|
||||||
|
|
||||||
.cl-spaces__full {
|
.cl-spaces__full {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@@ -1663,26 +1679,28 @@ html {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── FAQ Accordion ── */
|
/* ── FAQ Card Accordion ── */
|
||||||
.cl-faq {
|
.cl-faq {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0;
|
gap: 0.6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cl-faq__title {
|
.cl-faq__card {
|
||||||
font-size: 1.2rem;
|
background: var(--cl-faq-card-bg, var(--cl-card));
|
||||||
font-weight: 800;
|
border: 1px solid var(--cl-border);
|
||||||
color: var(--cl-text-strong);
|
border-radius: var(--cl-radius-sm);
|
||||||
margin: 0 0 1rem;
|
padding: 0 1.2rem;
|
||||||
|
transition: border-color 0.3s, box-shadow 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cl-faq__item {
|
.cl-faq__card:hover {
|
||||||
border-bottom: 1px solid var(--cl-border);
|
border-color: var(--cl-border-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cl-faq__item:first-of-type {
|
.cl-faq__card[open] {
|
||||||
border-top: 1px solid var(--cl-border);
|
border-color: var(--cl-border-hover);
|
||||||
|
box-shadow: 0 4px 16px var(--cl-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cl-faq__question {
|
.cl-faq__question {
|
||||||
@@ -1719,7 +1737,7 @@ html {
|
|||||||
transition: transform 0.3s ease, border-color 0.2s;
|
transition: transform 0.3s ease, border-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cl-faq__item[open] > .cl-faq__question::after {
|
.cl-faq__card[open] > .cl-faq__question::after {
|
||||||
transform: translateY(-30%) rotate(-135deg);
|
transform: translateY(-30%) rotate(-135deg);
|
||||||
border-color: var(--cl-accent);
|
border-color: var(--cl-accent);
|
||||||
}
|
}
|
||||||
@@ -1930,7 +1948,6 @@ html {
|
|||||||
color: var(--cl-muted);
|
color: var(--cl-muted);
|
||||||
font-size: 0.88rem;
|
font-size: 0.88rem;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
max-width: 700px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ═══════════════════════════════════════════════════════════════════
|
/* ═══════════════════════════════════════════════════════════════════
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ en:
|
|||||||
community_landing_enabled: "Enable the community landing page."
|
community_landing_enabled: "Enable the community landing page."
|
||||||
|
|
||||||
# ── Layout ──
|
# ── Layout ──
|
||||||
section_order: "━━ LAYOUT ━━ — Order of content sections, pipe-separated. IDs: hero, stats, about, participation, topics, groups, app_cta. Navbar and footer are always fixed."
|
section_order: "━━ LAYOUT ━━ — Order of content sections. Use the arrows to reorder. Available sections: hero, stats, about, participation, topics, groups, app_cta. Navbar and footer are always fixed."
|
||||||
|
|
||||||
# ── Custom CSS ──
|
# ── Custom CSS ──
|
||||||
custom_css: "━━ CUSTOM CSS ━━ — Raw CSS injected after all plugin styles. Use for overrides and tweaks. No style tags needed."
|
custom_css: "━━ CUSTOM CSS ━━ — Raw CSS injected after all plugin styles. Use for overrides and tweaks. No style tags needed."
|
||||||
@@ -26,10 +26,19 @@ en:
|
|||||||
accent_hover_color: "Accent color on hover states. Should be slightly lighter or darker than the primary accent. Hex value."
|
accent_hover_color: "Accent color on hover states. Should be slightly lighter or darker than the primary accent. Hex value."
|
||||||
dark_bg_color: "Overall page background color for dark mode. Hex value."
|
dark_bg_color: "Overall page background color for dark mode. Hex value."
|
||||||
light_bg_color: "Overall page background color for light mode. Hex value."
|
light_bg_color: "Overall page background color for light mode. Hex value."
|
||||||
|
orb_color: "Color of the decorative background orbs. Leave blank to use the accent color."
|
||||||
|
orb_opacity: "Opacity of the background orbs (0–100). Default: 50."
|
||||||
|
|
||||||
# ── Scroll Animations ──
|
# ── Scroll Animations ──
|
||||||
scroll_animation: "━━ SCROLL ANIMATIONS ━━ — How sections animate into view on scroll. Options: fade_up, fade_in, slide_left, slide_right, zoom_in, flip_up, or none."
|
scroll_animation: "━━ SCROLL ANIMATIONS ━━ — How sections animate into view on scroll. Options: fade_up, fade_in, slide_left, slide_right, zoom_in, flip_up, or none."
|
||||||
|
|
||||||
|
# ── Fonts ──
|
||||||
|
google_font_name: "━━ FONTS ━━ — Google Font family name for body text. Must match exact Google Fonts name (e.g. 'Inter', 'Poppins'). Default: Outfit."
|
||||||
|
title_font_name: "Separate Google Font for section titles and headings. Leave blank to use the body font. Must match exact Google Fonts name."
|
||||||
|
|
||||||
|
# ── Icons ──
|
||||||
|
fontawesome_enabled: "━━ ICONS ━━ — Enable FontAwesome 6 Free icons. Loads the icon library from CDN for use on buttons."
|
||||||
|
|
||||||
# ── 1. Navbar ──
|
# ── 1. Navbar ──
|
||||||
navbar_signin_label: "━━ ROW 1: NAVBAR ━━ — Fixed navigation bar at the top with logo, theme toggle, sign-in link, and join button. This setting controls the sign-in link text."
|
navbar_signin_label: "━━ ROW 1: NAVBAR ━━ — Fixed navigation bar at the top with logo, theme toggle, sign-in link, and join button. This setting controls the sign-in link text."
|
||||||
navbar_signin_enabled: "Show the sign-in link in the navbar."
|
navbar_signin_enabled: "Show the sign-in link in the navbar."
|
||||||
@@ -47,9 +56,14 @@ en:
|
|||||||
social_youtube_url: "YouTube channel URL. Leave blank to hide."
|
social_youtube_url: "YouTube channel URL. Leave blank to hide."
|
||||||
social_tiktok_url: "TikTok profile URL. Leave blank to hide."
|
social_tiktok_url: "TikTok profile URL. Leave blank to hide."
|
||||||
social_github_url: "GitHub organization or profile URL. Leave blank to hide."
|
social_github_url: "GitHub organization or profile URL. Leave blank to hide."
|
||||||
|
navbar_signin_icon: "FontAwesome icon name for the sign-in button (e.g. 'right-to-bracket'). Leave blank for no icon. Requires FontAwesome enabled."
|
||||||
|
navbar_signin_icon_position: "Show the icon before or after the sign-in button label."
|
||||||
|
navbar_join_icon: "FontAwesome icon name for the join button (e.g. 'user-plus'). Leave blank for no icon. Requires FontAwesome enabled."
|
||||||
|
navbar_join_icon_position: "Show the icon before or after the join button label."
|
||||||
|
|
||||||
# ── 2. Hero Section ──
|
# ── 2. Hero Section ──
|
||||||
hero_title: "━━ ROW 2: HERO ━━ — Large welcome area at the top with headline, subtitle, CTA buttons, and optional imagery. This is the main headline text."
|
hero_title: "━━ ROW 2: HERO ━━ — Large welcome area at the top with headline, subtitle, CTA buttons, and optional imagery. This is the main headline text."
|
||||||
|
hero_title_size: "Hero title font size in pixels. 0 = use default responsive size."
|
||||||
hero_accent_word: "Which word in the title gets the accent shimmer animation. 0 = last word (default). 1 = first word, 2 = second word, etc."
|
hero_accent_word: "Which word in the title gets the accent shimmer animation. 0 = last word (default). 1 = first word, 2 = second word, etc."
|
||||||
hero_subtitle: "Supporting text below the hero headline. Describe your community's purpose or value proposition."
|
hero_subtitle: "Supporting text below the hero headline. Describe your community's purpose or value proposition."
|
||||||
hero_card_enabled: "Display the hero content inside a rounded card container with border and shadow. When off, the hero uses a flat full-width layout."
|
hero_card_enabled: "Display the hero content inside a rounded card container with border and shadow. When off, the hero uses a flat full-width layout."
|
||||||
@@ -63,6 +77,10 @@ en:
|
|||||||
hero_secondary_button_enabled: "Show the secondary CTA button in the hero section."
|
hero_secondary_button_enabled: "Show the secondary CTA button in the hero section."
|
||||||
hero_secondary_button_label: "Text on the secondary (outlined) CTA button."
|
hero_secondary_button_label: "Text on the secondary (outlined) CTA button."
|
||||||
hero_secondary_button_url: "URL the secondary button links to."
|
hero_secondary_button_url: "URL the secondary button links to."
|
||||||
|
hero_primary_button_icon: "FontAwesome icon name for the primary hero button (e.g. 'rocket', 'arrow-right'). Leave blank for no icon."
|
||||||
|
hero_primary_button_icon_position: "Show the icon before or after the primary button label."
|
||||||
|
hero_secondary_button_icon: "FontAwesome icon name for the secondary hero button. Leave blank for no icon."
|
||||||
|
hero_secondary_button_icon_position: "Show the icon before or after the secondary button label."
|
||||||
hero_primary_btn_color_dark: "Primary button background color. Dark (left) and light (right) pickers. Leave blank for accent color."
|
hero_primary_btn_color_dark: "Primary button background color. Dark (left) and light (right) pickers. Leave blank for accent color."
|
||||||
hero_primary_btn_color_light: "Light mode background for the primary button."
|
hero_primary_btn_color_light: "Light mode background for the primary button."
|
||||||
hero_secondary_btn_color_dark: "Secondary button background color. Dark (left) and light (right) pickers. Leave blank for default glass style."
|
hero_secondary_btn_color_dark: "Secondary button background color. Dark (left) and light (right) pickers. Leave blank for default glass style."
|
||||||
@@ -100,6 +118,7 @@ en:
|
|||||||
stats_bg_light: "Light mode background for the stats section."
|
stats_bg_light: "Light mode background for the stats section."
|
||||||
stats_min_height: "Minimum height for the stats section in pixels. Set to 0 for auto height."
|
stats_min_height: "Minimum height for the stats section in pixels. Set to 0 for auto height."
|
||||||
stats_border_style: "Border style at the bottom of the stats section."
|
stats_border_style: "Border style at the bottom of the stats section."
|
||||||
|
stats_title_size: "Stats section title font size in pixels. 0 = use default."
|
||||||
|
|
||||||
# ── 4. About Section ──
|
# ── 4. About Section ──
|
||||||
about_enabled: "━━ ROW 4: ABOUT ━━ — Show the About section: a card with bold heading, decorative quote icon, community description, and author attribution (avatar, name, role)."
|
about_enabled: "━━ ROW 4: ABOUT ━━ — Show the About section: a card with bold heading, decorative quote icon, community description, and author attribution (avatar, name, role)."
|
||||||
@@ -116,6 +135,7 @@ en:
|
|||||||
about_bg_light: "Light mode background for the about section."
|
about_bg_light: "Light mode background for the about section."
|
||||||
about_min_height: "Minimum height for the about section in pixels. Set to 0 for auto height."
|
about_min_height: "Minimum height for the about section in pixels. Set to 0 for auto height."
|
||||||
about_border_style: "Border style at the bottom of the about section."
|
about_border_style: "Border style at the bottom of the about section."
|
||||||
|
about_title_size: "About section heading font size in pixels. 0 = use default."
|
||||||
|
|
||||||
# ── 5. Trending Discussions ──
|
# ── 5. Trending Discussions ──
|
||||||
topics_enabled: "━━ ROW 5: TRENDING ━━ — Show the Trending Discussions section: a horizontally scrollable row of topic cards showing the most active discussions. Each card displays category badge, title, reply count, and like count — all live data. Supports drag-to-scroll and native swipe."
|
topics_enabled: "━━ ROW 5: TRENDING ━━ — Show the Trending Discussions section: a horizontally scrollable row of topic cards showing the most active discussions. Each card displays category badge, title, reply count, and like count — all live data. Supports drag-to-scroll and native swipe."
|
||||||
@@ -128,6 +148,7 @@ en:
|
|||||||
topics_bg_light: "Light mode background for the trending section."
|
topics_bg_light: "Light mode background for the trending section."
|
||||||
topics_min_height: "Minimum height for the trending section in pixels. Set to 0 for auto height."
|
topics_min_height: "Minimum height for the trending section in pixels. Set to 0 for auto height."
|
||||||
topics_border_style: "Border style at the bottom of the trending section."
|
topics_border_style: "Border style at the bottom of the trending section."
|
||||||
|
topics_title_size: "Trending section title font size in pixels. 0 = use default."
|
||||||
|
|
||||||
# ── 6. Hero Creators ──
|
# ── 6. Hero Creators ──
|
||||||
contributors_enabled: "Show top 3 creators in the hero section with gold, silver, and bronze rank badges."
|
contributors_enabled: "Show top 3 creators in the hero section with gold, silver, and bronze rank badges."
|
||||||
@@ -154,6 +175,7 @@ en:
|
|||||||
participation_bg_light: "Light mode background for the participation section."
|
participation_bg_light: "Light mode background for the participation section."
|
||||||
participation_min_height: "Minimum height for the participation section in pixels. Set to 0 for auto height."
|
participation_min_height: "Minimum height for the participation section in pixels. Set to 0 for auto height."
|
||||||
participation_border_style: "Border style at the bottom of the participation section."
|
participation_border_style: "Border style at the bottom of the participation section."
|
||||||
|
participation_title_size: "Participation section title font size in pixels. 0 = use default."
|
||||||
|
|
||||||
# ── 7. Community Spaces ──
|
# ── 7. Community Spaces ──
|
||||||
groups_enabled: "━━ ROW 7: SPACES ━━ — Show the Community Spaces section: a grid of colorful cards representing your public groups. Each card shows a colored icon (with group's first letter or flair), group name, and member count. Only public, non-automatic groups are shown."
|
groups_enabled: "━━ ROW 7: SPACES ━━ — Show the Community Spaces section: a grid of colorful cards representing your public groups. Each card shows a colored icon (with group's first letter or flair), group name, and member count. Only public, non-automatic groups are shown."
|
||||||
@@ -169,12 +191,16 @@ en:
|
|||||||
groups_border_style: "Border style at the bottom of the spaces section."
|
groups_border_style: "Border style at the bottom of the spaces section."
|
||||||
groups_show_description: "Show group description text (from the group's bio) below the group name on each card."
|
groups_show_description: "Show group description text (from the group's bio) below the group name on each card."
|
||||||
groups_description_max_length: "Maximum characters for group description text (30–500). Longer descriptions are truncated."
|
groups_description_max_length: "Maximum characters for group description text (30–500). Longer descriptions are truncated."
|
||||||
|
groups_title_size: "Spaces section title font size in pixels. 0 = use default."
|
||||||
|
|
||||||
# ── 7b. FAQ Accordion ──
|
# ── 7b. FAQ Accordion ──
|
||||||
faq_enabled: "━━ FAQ ACCORDION ━━ — Show an FAQ accordion alongside the Spaces section. Only one item opens at a time."
|
faq_enabled: "━━ FAQ ACCORDION ━━ — Show an FAQ accordion alongside the Spaces section. Only one item opens at a time."
|
||||||
faq_title_enabled: "Show a heading above the FAQ accordion."
|
faq_title_enabled: "Show a heading above the FAQ accordion."
|
||||||
faq_title: "Heading text above the FAQ accordion."
|
faq_title: "Heading text above the FAQ accordion."
|
||||||
faq_items: 'FAQ items as a JSON array. Format: [{"q":"Question","a":"Answer"}]. HTML is supported in answers.'
|
faq_items: 'FAQ items as a JSON array. Format: [{"q":"Question","a":"Answer"}]. HTML is supported in answers.'
|
||||||
|
faq_title_size: "FAQ section title font size in pixels. 0 = use default."
|
||||||
|
faq_card_bg_dark: "FAQ card background color (dark mode). Leave blank for default card styling."
|
||||||
|
faq_card_bg_light: "FAQ card background color (light mode). Leave blank for default."
|
||||||
|
|
||||||
# ── 8. App Download CTA ──
|
# ── 8. App Download CTA ──
|
||||||
show_app_ctas: "━━ ROW 8: APP CTA ━━ — Show the App Download CTA: a gradient banner promoting your mobile app with headline, subtitle, download badges (App Store / Google Play), and optional promotional image. Requires at least one app store URL."
|
show_app_ctas: "━━ ROW 8: APP CTA ━━ — Show the App Download CTA: a gradient banner promoting your mobile app with headline, subtitle, download badges (App Store / Google Play), and optional promotional image. Requires at least one app store URL."
|
||||||
@@ -197,6 +223,7 @@ en:
|
|||||||
app_cta_bg_light: "Light mode background for the app CTA section."
|
app_cta_bg_light: "Light mode background for the app CTA section."
|
||||||
app_cta_min_height: "Minimum height for the app CTA section in pixels. Set to 0 for auto height."
|
app_cta_min_height: "Minimum height for the app CTA section in pixels. Set to 0 for auto height."
|
||||||
app_cta_border_style: "Border style at the bottom of the app CTA section."
|
app_cta_border_style: "Border style at the bottom of the app CTA section."
|
||||||
|
app_cta_title_size: "App CTA headline font size in pixels. 0 = use default."
|
||||||
|
|
||||||
# ── 9. Footer ──
|
# ── 9. Footer ──
|
||||||
footer_description: "━━ ROW 9: FOOTER ━━ — Bottom of the page with logo, navigation links, copyright, and optional description. This adds a description paragraph above the footer bar."
|
footer_description: "━━ ROW 9: FOOTER ━━ — Bottom of the page with logo, navigation links, copyright, and optional description. This adds a description paragraph above the footer bar."
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ plugins:
|
|||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
section_order:
|
section_order:
|
||||||
default: "hero|stats|about|participation|topics|groups|app_cta"
|
default: "hero|stats|about|participation|topics|groups|app_cta"
|
||||||
type: string
|
type: list
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# Custom CSS
|
# Custom CSS
|
||||||
@@ -67,8 +67,16 @@ plugins:
|
|||||||
default: "06060f"
|
default: "06060f"
|
||||||
type: color
|
type: color
|
||||||
light_bg_color:
|
light_bg_color:
|
||||||
default: "faf6f0"
|
default: "F2F4F7"
|
||||||
type: color
|
type: color
|
||||||
|
orb_color:
|
||||||
|
default: ""
|
||||||
|
type: color
|
||||||
|
orb_opacity:
|
||||||
|
default: 50
|
||||||
|
type: integer
|
||||||
|
min: 0
|
||||||
|
max: 100
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# Scroll Animations & Effects
|
# Scroll Animations & Effects
|
||||||
@@ -101,6 +109,23 @@ plugins:
|
|||||||
default: true
|
default: true
|
||||||
type: bool
|
type: bool
|
||||||
|
|
||||||
|
# ══════════════════════════════════════════
|
||||||
|
# Fonts
|
||||||
|
# ══════════════════════════════════════════
|
||||||
|
google_font_name:
|
||||||
|
default: "Outfit"
|
||||||
|
type: string
|
||||||
|
title_font_name:
|
||||||
|
default: ""
|
||||||
|
type: string
|
||||||
|
|
||||||
|
# ══════════════════════════════════════════
|
||||||
|
# Icons (FontAwesome)
|
||||||
|
# ══════════════════════════════════════════
|
||||||
|
fontawesome_enabled:
|
||||||
|
default: false
|
||||||
|
type: bool
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# 1. Navbar
|
# 1. Navbar
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
@@ -157,6 +182,24 @@ plugins:
|
|||||||
social_github_url:
|
social_github_url:
|
||||||
default: ""
|
default: ""
|
||||||
type: string
|
type: string
|
||||||
|
navbar_signin_icon:
|
||||||
|
default: ""
|
||||||
|
type: string
|
||||||
|
navbar_signin_icon_position:
|
||||||
|
default: "before"
|
||||||
|
type: enum
|
||||||
|
choices:
|
||||||
|
- before
|
||||||
|
- after
|
||||||
|
navbar_join_icon:
|
||||||
|
default: ""
|
||||||
|
type: string
|
||||||
|
navbar_join_icon_position:
|
||||||
|
default: "before"
|
||||||
|
type: enum
|
||||||
|
choices:
|
||||||
|
- before
|
||||||
|
- after
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# 2. Hero Section
|
# 2. Hero Section
|
||||||
@@ -169,6 +212,11 @@ plugins:
|
|||||||
type: integer
|
type: integer
|
||||||
min: 0
|
min: 0
|
||||||
max: 50
|
max: 50
|
||||||
|
hero_title_size:
|
||||||
|
default: 0
|
||||||
|
type: integer
|
||||||
|
min: 0
|
||||||
|
max: 120
|
||||||
hero_subtitle:
|
hero_subtitle:
|
||||||
default: "Are you ready to start your creative journey?"
|
default: "Are you ready to start your creative journey?"
|
||||||
type: string
|
type: string
|
||||||
@@ -207,6 +255,24 @@ plugins:
|
|||||||
hero_secondary_button_url:
|
hero_secondary_button_url:
|
||||||
default: "/login"
|
default: "/login"
|
||||||
type: string
|
type: string
|
||||||
|
hero_primary_button_icon:
|
||||||
|
default: ""
|
||||||
|
type: string
|
||||||
|
hero_primary_button_icon_position:
|
||||||
|
default: "before"
|
||||||
|
type: enum
|
||||||
|
choices:
|
||||||
|
- before
|
||||||
|
- after
|
||||||
|
hero_secondary_button_icon:
|
||||||
|
default: ""
|
||||||
|
type: string
|
||||||
|
hero_secondary_button_icon_position:
|
||||||
|
default: "before"
|
||||||
|
type: enum
|
||||||
|
choices:
|
||||||
|
- before
|
||||||
|
- after
|
||||||
hero_primary_btn_color_dark:
|
hero_primary_btn_color_dark:
|
||||||
default: ""
|
default: ""
|
||||||
type: color
|
type: color
|
||||||
@@ -338,6 +404,11 @@ plugins:
|
|||||||
- solid
|
- solid
|
||||||
- dashed
|
- dashed
|
||||||
- dotted
|
- dotted
|
||||||
|
stats_title_size:
|
||||||
|
default: 0
|
||||||
|
type: integer
|
||||||
|
min: 0
|
||||||
|
max: 80
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# 4. About Community Section
|
# 4. About Community Section
|
||||||
@@ -391,6 +462,11 @@ plugins:
|
|||||||
- solid
|
- solid
|
||||||
- dashed
|
- dashed
|
||||||
- dotted
|
- dotted
|
||||||
|
about_title_size:
|
||||||
|
default: 0
|
||||||
|
type: integer
|
||||||
|
min: 0
|
||||||
|
max: 80
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# 5. Trending Discussions Section
|
# 5. Trending Discussions Section
|
||||||
@@ -432,6 +508,11 @@ plugins:
|
|||||||
- solid
|
- solid
|
||||||
- dashed
|
- dashed
|
||||||
- dotted
|
- dotted
|
||||||
|
topics_title_size:
|
||||||
|
default: 0
|
||||||
|
type: integer
|
||||||
|
min: 0
|
||||||
|
max: 80
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# 6. Hero Creators (Top 3 in Hero)
|
# 6. Hero Creators (Top 3 in Hero)
|
||||||
@@ -469,7 +550,7 @@ plugins:
|
|||||||
default: ""
|
default: ""
|
||||||
type: color
|
type: color
|
||||||
contributors_days:
|
contributors_days:
|
||||||
default: 90
|
default: 30
|
||||||
type: integer
|
type: integer
|
||||||
contributors_count:
|
contributors_count:
|
||||||
default: 10
|
default: 10
|
||||||
@@ -520,6 +601,11 @@ plugins:
|
|||||||
- solid
|
- solid
|
||||||
- dashed
|
- dashed
|
||||||
- dotted
|
- dotted
|
||||||
|
participation_title_size:
|
||||||
|
default: 0
|
||||||
|
type: integer
|
||||||
|
min: 0
|
||||||
|
max: 80
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# 7. Community Spaces Section
|
# 7. Community Spaces Section
|
||||||
@@ -572,6 +658,11 @@ plugins:
|
|||||||
type: integer
|
type: integer
|
||||||
min: 30
|
min: 30
|
||||||
max: 500
|
max: 500
|
||||||
|
groups_title_size:
|
||||||
|
default: 0
|
||||||
|
type: integer
|
||||||
|
min: 0
|
||||||
|
max: 80
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# 7b. FAQ Accordion
|
# 7b. FAQ Accordion
|
||||||
@@ -588,6 +679,17 @@ plugins:
|
|||||||
faq_items:
|
faq_items:
|
||||||
default: '[{"q":"What is this community about?","a":"A creative community focused on sharing knowledge and building together."},{"q":"How do I join?","a":"Click the Get Started button to create your free account."},{"q":"Is it free?","a":"Yes! Basic membership is completely free."}]'
|
default: '[{"q":"What is this community about?","a":"A creative community focused on sharing knowledge and building together."},{"q":"How do I join?","a":"Click the Get Started button to create your free account."},{"q":"Is it free?","a":"Yes! Basic membership is completely free."}]'
|
||||||
type: text_area
|
type: text_area
|
||||||
|
faq_title_size:
|
||||||
|
default: 0
|
||||||
|
type: integer
|
||||||
|
min: 0
|
||||||
|
max: 80
|
||||||
|
faq_card_bg_dark:
|
||||||
|
default: ""
|
||||||
|
type: color
|
||||||
|
faq_card_bg_light:
|
||||||
|
default: ""
|
||||||
|
type: color
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# 8. App Download CTA Section
|
# 8. App Download CTA Section
|
||||||
@@ -665,6 +767,11 @@ plugins:
|
|||||||
- solid
|
- solid
|
||||||
- dashed
|
- dashed
|
||||||
- dotted
|
- dotted
|
||||||
|
app_cta_title_size:
|
||||||
|
default: 0
|
||||||
|
type: integer
|
||||||
|
min: 0
|
||||||
|
max: 80
|
||||||
|
|
||||||
# ══════════════════════════════════════════
|
# ══════════════════════════════════════════
|
||||||
# 9. Footer
|
# 9. Footer
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ module CommunityLanding
|
|||||||
|
|
||||||
# Top contributors
|
# Top contributors
|
||||||
data[:contributors] = begin
|
data[:contributors] = begin
|
||||||
if s.contributors_enabled
|
if s.contributors_enabled || (s.participation_enabled rescue true)
|
||||||
User
|
User
|
||||||
.joins(:posts)
|
.joins(:posts)
|
||||||
.includes(:user_profile)
|
.includes(:user_profile)
|
||||||
|
|||||||
@@ -68,9 +68,18 @@ module CommunityLanding
|
|||||||
html << " data-parallax=\"#{@s.mouse_parallax_enabled}\""
|
html << " data-parallax=\"#{@s.mouse_parallax_enabled}\""
|
||||||
html << ">\n<head>\n"
|
html << ">\n<head>\n"
|
||||||
html << "<meta charset=\"UTF-8\">\n"
|
html << "<meta charset=\"UTF-8\">\n"
|
||||||
|
body_font = (@s.google_font_name.presence rescue nil) || "Outfit"
|
||||||
|
title_font = (@s.title_font_name.presence rescue nil)
|
||||||
|
font_families = [body_font]
|
||||||
|
font_families << title_font if title_font && title_font != body_font
|
||||||
|
font_params = font_families.map { |f| "family=#{f.gsub(' ', '+')}:wght@400;500;600;700;800;900" }.join("&")
|
||||||
|
|
||||||
html << "<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n"
|
html << "<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\">\n"
|
||||||
html << "<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n"
|
html << "<link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin>\n"
|
||||||
html << "<link href=\"https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&display=swap\" rel=\"stylesheet\">\n"
|
html << "<link href=\"https://fonts.googleapis.com/css2?#{font_params}&display=swap\" rel=\"stylesheet\">\n"
|
||||||
|
if @s.fontawesome_enabled rescue false
|
||||||
|
html << "<link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css\" crossorigin=\"anonymous\">\n"
|
||||||
|
end
|
||||||
html << "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, viewport-fit=cover\">\n"
|
html << "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, viewport-fit=cover\">\n"
|
||||||
html << "<meta name=\"color-scheme\" content=\"dark light\">\n"
|
html << "<meta name=\"color-scheme\" content=\"dark light\">\n"
|
||||||
|
|
||||||
@@ -113,6 +122,17 @@ module CommunityLanding
|
|||||||
html << @styles.color_overrides
|
html << @styles.color_overrides
|
||||||
html << @styles.section_backgrounds
|
html << @styles.section_backgrounds
|
||||||
|
|
||||||
|
# Font overrides
|
||||||
|
font_css = +""
|
||||||
|
font_css << ":root { --cl-font-body: \"#{body_font}\", sans-serif;"
|
||||||
|
if title_font
|
||||||
|
font_css << " --cl-font-title: \"#{title_font}\", serif;"
|
||||||
|
else
|
||||||
|
font_css << " --cl-font-title: var(--cl-font-body);"
|
||||||
|
end
|
||||||
|
font_css << " }\n"
|
||||||
|
html << "<style>#{font_css}</style>\n"
|
||||||
|
|
||||||
# Custom CSS (injected last so it can override everything)
|
# Custom CSS (injected last so it can override everything)
|
||||||
custom_css = @s.custom_css.presence rescue nil
|
custom_css = @s.custom_css.presence rescue nil
|
||||||
if custom_css
|
if custom_css
|
||||||
@@ -159,10 +179,10 @@ module CommunityLanding
|
|||||||
html << theme_toggle
|
html << theme_toggle
|
||||||
html << render_social_icons
|
html << render_social_icons
|
||||||
if signin_enabled
|
if signin_enabled
|
||||||
html << "<a href=\"#{login_url}\" class=\"cl-navbar__link cl-btn--ghost\">#{e(signin_label)}</a>\n"
|
html << "<a href=\"#{login_url}\" class=\"cl-navbar__link cl-btn--ghost\">#{button_with_icon(signin_label, :navbar_signin_icon, :navbar_signin_icon_position)}</a>\n"
|
||||||
end
|
end
|
||||||
if join_enabled
|
if join_enabled
|
||||||
html << "<a href=\"#{login_url}\" class=\"cl-navbar__link cl-btn--primary\">#{e(join_label)}</a>\n"
|
html << "<a href=\"#{login_url}\" class=\"cl-navbar__link cl-btn--primary\">#{button_with_icon(join_label, :navbar_join_icon, :navbar_join_icon_position)}</a>\n"
|
||||||
end
|
end
|
||||||
html << "</div>"
|
html << "</div>"
|
||||||
|
|
||||||
@@ -170,8 +190,8 @@ module CommunityLanding
|
|||||||
html << "<div class=\"cl-navbar__mobile-menu\" id=\"cl-nav-links\">\n"
|
html << "<div class=\"cl-navbar__mobile-menu\" id=\"cl-nav-links\">\n"
|
||||||
html << theme_toggle
|
html << theme_toggle
|
||||||
html << render_social_icons
|
html << render_social_icons
|
||||||
html << "<a href=\"#{login_url}\" class=\"cl-navbar__link cl-btn--ghost\">#{e(signin_label)}</a>\n"
|
html << "<a href=\"#{login_url}\" class=\"cl-navbar__link cl-btn--ghost\">#{button_with_icon(signin_label, :navbar_signin_icon, :navbar_signin_icon_position)}</a>\n"
|
||||||
html << "<a href=\"#{login_url}\" class=\"cl-navbar__link cl-btn--primary\">#{e(join_label)}</a>\n"
|
html << "<a href=\"#{login_url}\" class=\"cl-navbar__link cl-btn--primary\">#{button_with_icon(join_label, :navbar_join_icon, :navbar_join_icon_position)}</a>\n"
|
||||||
html << "</div>"
|
html << "</div>"
|
||||||
html << "</div></nav>\n"
|
html << "</div></nav>\n"
|
||||||
html
|
html
|
||||||
@@ -214,9 +234,9 @@ module CommunityLanding
|
|||||||
parts << "#{e(before.join(' '))} " if before.any?
|
parts << "#{e(before.join(' '))} " if before.any?
|
||||||
parts << "<span class=\"cl-hero__title-accent\">#{e(accent)}</span>"
|
parts << "<span class=\"cl-hero__title-accent\">#{e(accent)}</span>"
|
||||||
parts << " #{e(after.join(' '))}" if after.any?
|
parts << " #{e(after.join(' '))}" if after.any?
|
||||||
html << "<h1 class=\"cl-hero__title\">#{parts}</h1>\n"
|
html << "<h1 class=\"cl-hero__title\"#{title_style(:hero_title_size)}>#{parts}</h1>\n"
|
||||||
else
|
else
|
||||||
html << "<h1 class=\"cl-hero__title\"><span class=\"cl-hero__title-accent\">#{e(@s.hero_title)}</span></h1>\n"
|
html << "<h1 class=\"cl-hero__title\"#{title_style(:hero_title_size)}><span class=\"cl-hero__title-accent\">#{e(@s.hero_title)}</span></h1>\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
html << "<p class=\"cl-hero__subtitle\">#{e(@s.hero_subtitle)}</p>\n"
|
html << "<p class=\"cl-hero__subtitle\">#{e(@s.hero_subtitle)}</p>\n"
|
||||||
@@ -230,8 +250,8 @@ module CommunityLanding
|
|||||||
|
|
||||||
if primary_on || secondary_on
|
if primary_on || secondary_on
|
||||||
html << "<div class=\"cl-hero__actions\">\n"
|
html << "<div class=\"cl-hero__actions\">\n"
|
||||||
html << "<a href=\"#{primary_url}\" class=\"cl-btn cl-btn--primary cl-btn--lg\">#{e(primary_label)}</a>\n" if primary_on
|
html << "<a href=\"#{primary_url}\" class=\"cl-btn cl-btn--primary cl-btn--lg\">#{button_with_icon(primary_label, :hero_primary_button_icon, :hero_primary_button_icon_position)}</a>\n" if primary_on
|
||||||
html << "<a href=\"#{secondary_url}\" class=\"cl-btn cl-btn--ghost cl-btn--lg\">#{e(secondary_label)}</a>\n" if secondary_on
|
html << "<a href=\"#{secondary_url}\" class=\"cl-btn cl-btn--ghost cl-btn--lg\">#{button_with_icon(secondary_label, :hero_secondary_button_icon, :hero_secondary_button_icon_position)}</a>\n" if secondary_on
|
||||||
html << "</div>\n"
|
html << "</div>\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -321,7 +341,7 @@ module CommunityLanding
|
|||||||
|
|
||||||
html = +""
|
html = +""
|
||||||
html << "<section class=\"cl-stats cl-anim\" id=\"cl-stats-row\"#{section_style(border, min_h)}><div class=\"cl-container\">\n"
|
html << "<section class=\"cl-stats cl-anim\" id=\"cl-stats-row\"#{section_style(border, min_h)}><div class=\"cl-container\">\n"
|
||||||
html << "<h2 class=\"cl-section-title\">#{e(stats_title)}</h2>\n" if show_title
|
html << "<h2 class=\"cl-section-title\"#{title_style(:stats_title_size)}>#{e(stats_title)}</h2>\n" if show_title
|
||||||
html << "<div class=\"cl-stats__grid\">\n"
|
html << "<div class=\"cl-stats__grid\">\n"
|
||||||
html << stat_card(Icons::STAT_MEMBERS_SVG, stats[:members], @s.stat_members_label, icon_shape, card_style, round_nums, show_labels)
|
html << stat_card(Icons::STAT_MEMBERS_SVG, stats[:members], @s.stat_members_label, icon_shape, card_style, round_nums, show_labels)
|
||||||
html << stat_card(Icons::STAT_TOPICS_SVG, stats[:topics], @s.stat_topics_label, icon_shape, card_style, round_nums, show_labels)
|
html << stat_card(Icons::STAT_TOPICS_SVG, stats[:topics], @s.stat_topics_label, icon_shape, card_style, round_nums, show_labels)
|
||||||
@@ -359,7 +379,7 @@ module CommunityLanding
|
|||||||
|
|
||||||
# Right side — text content
|
# Right side — text content
|
||||||
html << "<div class=\"cl-about__right\">\n"
|
html << "<div class=\"cl-about__right\">\n"
|
||||||
html << "<h2 class=\"cl-about__heading\">#{e(about_heading)}</h2>\n" if about_heading_on
|
html << "<h2 class=\"cl-about__heading\"#{title_style(:about_title_size)}>#{e(about_heading)}</h2>\n" if about_heading_on
|
||||||
html << Icons::QUOTE_SVG
|
html << Icons::QUOTE_SVG
|
||||||
html << "<div class=\"cl-about__body\">#{about_body}</div>\n" if about_body.present?
|
html << "<div class=\"cl-about__body\">#{about_body}</div>\n" if about_body.present?
|
||||||
html << "<div class=\"cl-about__meta\">\n"
|
html << "<div class=\"cl-about__meta\">\n"
|
||||||
@@ -379,11 +399,19 @@ module CommunityLanding
|
|||||||
return "" unless (@s.participation_enabled rescue true)
|
return "" unless (@s.participation_enabled rescue true)
|
||||||
|
|
||||||
contributors = @data[:contributors]
|
contributors = @data[:contributors]
|
||||||
return "" unless contributors&.length.to_i > 3
|
hero_contributors_on = (@s.contributors_enabled rescue false)
|
||||||
|
|
||||||
# Positions 4–10: users with a public bio
|
if hero_contributors_on
|
||||||
bio_max = (@s.participation_bio_max_length rescue 150).to_i
|
# Hero shows top 3, participation shows 4–10
|
||||||
candidates = contributors[3..9] || []
|
return "" unless contributors&.length.to_i > 3
|
||||||
|
candidates = contributors[3..9] || []
|
||||||
|
else
|
||||||
|
# Hero contributors disabled, participation shows 1–10
|
||||||
|
return "" unless contributors&.any?
|
||||||
|
candidates = contributors[0..9] || []
|
||||||
|
end
|
||||||
|
|
||||||
|
bio_max = (@s.participation_bio_max_length rescue 150).to_i
|
||||||
users_with_bio = candidates.select { |u| u.user_profile&.bio_excerpt.present? rescue false }
|
users_with_bio = candidates.select { |u| u.user_profile&.bio_excerpt.present? rescue false }
|
||||||
return "" if users_with_bio.empty?
|
return "" if users_with_bio.empty?
|
||||||
|
|
||||||
@@ -396,7 +424,7 @@ module CommunityLanding
|
|||||||
|
|
||||||
html = +""
|
html = +""
|
||||||
html << "<section class=\"cl-participation cl-anim\" id=\"cl-participation\"#{section_style(border, min_h)}><div class=\"cl-container\">\n"
|
html << "<section class=\"cl-participation cl-anim\" id=\"cl-participation\"#{section_style(border, min_h)}><div class=\"cl-container\">\n"
|
||||||
html << "<h2 class=\"cl-section-title\">#{e(title_text)}</h2>\n" if show_title
|
html << "<h2 class=\"cl-section-title\"#{title_style(:participation_title_size)}>#{e(title_text)}</h2>\n" if show_title
|
||||||
stagger_class = @s.staggered_reveal_enabled ? " cl-stagger" : ""
|
stagger_class = @s.staggered_reveal_enabled ? " cl-stagger" : ""
|
||||||
html << "<div class=\"cl-participation__grid#{stagger_class}\">\n"
|
html << "<div class=\"cl-participation__grid#{stagger_class}\">\n"
|
||||||
|
|
||||||
@@ -437,7 +465,7 @@ module CommunityLanding
|
|||||||
|
|
||||||
html = +""
|
html = +""
|
||||||
html << "<section class=\"cl-topics cl-anim\" id=\"cl-topics\"#{section_style(border, min_h)}><div class=\"cl-container\">\n"
|
html << "<section class=\"cl-topics cl-anim\" id=\"cl-topics\"#{section_style(border, min_h)}><div class=\"cl-container\">\n"
|
||||||
html << "<h2 class=\"cl-section-title\">#{e(@s.topics_title)}</h2>\n" if show_title
|
html << "<h2 class=\"cl-section-title\"#{title_style(:topics_title_size)}>#{e(@s.topics_title)}</h2>\n" if show_title
|
||||||
stagger_class = @s.staggered_reveal_enabled ? " cl-stagger" : ""
|
stagger_class = @s.staggered_reveal_enabled ? " cl-stagger" : ""
|
||||||
html << "<div class=\"cl-topics__grid#{stagger_class}\">\n"
|
html << "<div class=\"cl-topics__grid#{stagger_class}\">\n"
|
||||||
|
|
||||||
@@ -477,57 +505,76 @@ module CommunityLanding
|
|||||||
|
|
||||||
html = +""
|
html = +""
|
||||||
html << "<section class=\"cl-spaces cl-anim\" id=\"cl-groups\"#{section_style(border, min_h)}><div class=\"cl-container\">\n"
|
html << "<section class=\"cl-spaces cl-anim\" id=\"cl-groups\"#{section_style(border, min_h)}><div class=\"cl-container\">\n"
|
||||||
html << "<h2 class=\"cl-section-title\">#{e(@s.groups_title)}</h2>\n" if show_title
|
|
||||||
|
|
||||||
layout_class = (has_groups && faq_on) ? "cl-spaces__split" : "cl-spaces__full"
|
if has_groups && faq_on
|
||||||
html << "<div class=\"#{layout_class}\">\n"
|
# ── Split layout: both titles at same level ──
|
||||||
|
html << "<div class=\"cl-spaces__split\">\n"
|
||||||
|
|
||||||
# ── Left: Groups Grid ──
|
# Left column: Groups
|
||||||
if has_groups
|
html << "<div class=\"cl-spaces__col\">\n"
|
||||||
stagger_class = @s.staggered_reveal_enabled ? " cl-stagger" : ""
|
html << "<h2 class=\"cl-section-title\"#{title_style(:groups_title_size)}>#{e(@s.groups_title)}</h2>\n" if show_title
|
||||||
html << "<div class=\"cl-spaces__left\">\n"
|
html << render_groups_grid(groups, show_desc, desc_max)
|
||||||
html << "<div class=\"cl-spaces__grid#{stagger_class}\">\n"
|
html << "</div>\n"
|
||||||
|
|
||||||
groups.each do |group|
|
# Right column: FAQ
|
||||||
display_name = group.full_name.presence || group.name.tr("_-", " ").gsub(/\b\w/, &:upcase)
|
html << "<div class=\"cl-spaces__col\">\n"
|
||||||
hue = group.name.bytes.sum % 360
|
html << render_faq
|
||||||
sat = 55 + (group.name.bytes.first.to_i % 15)
|
html << "</div>\n"
|
||||||
light = 45 + (group.name.bytes.last.to_i % 12)
|
|
||||||
icon_color = "hsl(#{hue}, #{sat}%, #{light}%)"
|
|
||||||
|
|
||||||
# Group description from bio_raw
|
html << "</div>\n"
|
||||||
desc_text = nil
|
elsif has_groups
|
||||||
if show_desc
|
# ── Groups only (full width) ──
|
||||||
raw_bio = (group.bio_raw.to_s.strip rescue "")
|
html << "<h2 class=\"cl-section-title\"#{title_style(:groups_title_size)}>#{e(@s.groups_title)}</h2>\n" if show_title
|
||||||
if raw_bio.present?
|
html << "<div class=\"cl-spaces__full\">\n"
|
||||||
plain = raw_bio.gsub(/<[^>]*>/, "").strip
|
html << render_groups_grid(groups, show_desc, desc_max)
|
||||||
desc_text = plain.length > desc_max ? "#{plain[0...desc_max]}..." : plain
|
html << "</div>\n"
|
||||||
end
|
else
|
||||||
end
|
# ── FAQ only (full width) ──
|
||||||
|
html << render_faq
|
||||||
html << "<a href=\"#{login_url}\" class=\"cl-space-card\" style=\"--space-color: #{icon_color}\">\n"
|
|
||||||
html << "<div class=\"cl-space-card__icon\">"
|
|
||||||
if group.flair_url.present?
|
|
||||||
html << "<img src=\"#{group.flair_url}\" alt=\"\">"
|
|
||||||
else
|
|
||||||
html << "<span class=\"cl-space-card__letter\">#{group.name[0].upcase}</span>"
|
|
||||||
end
|
|
||||||
html << "</div>\n"
|
|
||||||
html << "<div class=\"cl-space-card__body\">\n"
|
|
||||||
html << "<span class=\"cl-space-card__name\">#{e(display_name)}</span>\n"
|
|
||||||
html << "<span class=\"cl-space-card__sub\">#{group.user_count} members</span>\n"
|
|
||||||
html << "<p class=\"cl-space-card__desc\">#{e(desc_text)}</p>\n" if desc_text
|
|
||||||
html << "</div>\n"
|
|
||||||
html << "</a>\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
html << "</div>\n</div>\n"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# ── Right: FAQ Accordion ──
|
html << "</div></section>\n"
|
||||||
html << render_faq if faq_on
|
html
|
||||||
|
end
|
||||||
|
|
||||||
html << "</div>\n</div></section>\n"
|
def render_groups_grid(groups, show_desc, desc_max)
|
||||||
|
stagger_class = @s.staggered_reveal_enabled ? " cl-stagger" : ""
|
||||||
|
html = +""
|
||||||
|
html << "<div class=\"cl-spaces__grid#{stagger_class}\">\n"
|
||||||
|
|
||||||
|
groups.each do |group|
|
||||||
|
display_name = group.full_name.presence || group.name.tr("_-", " ").gsub(/\b\w/, &:upcase)
|
||||||
|
hue = group.name.bytes.sum % 360
|
||||||
|
sat = 55 + (group.name.bytes.first.to_i % 15)
|
||||||
|
light = 45 + (group.name.bytes.last.to_i % 12)
|
||||||
|
icon_color = "hsl(#{hue}, #{sat}%, #{light}%)"
|
||||||
|
|
||||||
|
desc_text = nil
|
||||||
|
if show_desc
|
||||||
|
raw_bio = (group.bio_raw.to_s.strip rescue "")
|
||||||
|
if raw_bio.present?
|
||||||
|
plain = raw_bio.gsub(/<[^>]*>/, "").strip
|
||||||
|
desc_text = plain.length > desc_max ? "#{plain[0...desc_max]}..." : plain
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
html << "<a href=\"#{login_url}\" class=\"cl-space-card\" style=\"--space-color: #{icon_color}\">\n"
|
||||||
|
html << "<div class=\"cl-space-card__icon\">"
|
||||||
|
if group.flair_url.present?
|
||||||
|
html << "<img src=\"#{group.flair_url}\" alt=\"\">"
|
||||||
|
else
|
||||||
|
html << "<span class=\"cl-space-card__letter\">#{group.name[0].upcase}</span>"
|
||||||
|
end
|
||||||
|
html << "</div>\n"
|
||||||
|
html << "<div class=\"cl-space-card__body\">\n"
|
||||||
|
html << "<span class=\"cl-space-card__name\">#{e(display_name)}</span>\n"
|
||||||
|
html << "<span class=\"cl-space-card__sub\">#{group.user_count} members</span>\n"
|
||||||
|
html << "<p class=\"cl-space-card__desc\">#{e(desc_text)}</p>\n" if desc_text
|
||||||
|
html << "</div>\n"
|
||||||
|
html << "</a>\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
html << "</div>\n"
|
||||||
html
|
html
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -537,8 +584,8 @@ module CommunityLanding
|
|||||||
faq_raw = @s.faq_items.presence rescue nil
|
faq_raw = @s.faq_items.presence rescue nil
|
||||||
|
|
||||||
html = +""
|
html = +""
|
||||||
|
html << "<h2 class=\"cl-section-title\"#{title_style(:faq_title_size)}>#{e(faq_title)}</h2>\n" if faq_title_on
|
||||||
html << "<div class=\"cl-faq\">\n"
|
html << "<div class=\"cl-faq\">\n"
|
||||||
html << "<h3 class=\"cl-faq__title\">#{e(faq_title)}</h3>\n" if faq_title_on
|
|
||||||
|
|
||||||
if faq_raw
|
if faq_raw
|
||||||
begin
|
begin
|
||||||
@@ -547,7 +594,7 @@ module CommunityLanding
|
|||||||
q = item["q"].to_s
|
q = item["q"].to_s
|
||||||
a = item["a"].to_s
|
a = item["a"].to_s
|
||||||
next if q.blank?
|
next if q.blank?
|
||||||
html << "<details class=\"cl-faq__item\" data-faq-exclusive>\n"
|
html << "<details class=\"cl-faq__card\" data-faq-exclusive>\n"
|
||||||
html << "<summary class=\"cl-faq__question\">#{e(q)}</summary>\n"
|
html << "<summary class=\"cl-faq__question\">#{e(q)}</summary>\n"
|
||||||
html << "<div class=\"cl-faq__answer\">#{a}</div>\n"
|
html << "<div class=\"cl-faq__answer\">#{a}</div>\n"
|
||||||
html << "</details>\n"
|
html << "</details>\n"
|
||||||
@@ -577,7 +624,7 @@ module CommunityLanding
|
|||||||
html = +""
|
html = +""
|
||||||
html << "<section class=\"cl-app-cta cl-anim\" id=\"cl-app-cta\"#{section_style(border, min_h)}><div class=\"cl-container\">\n"
|
html << "<section class=\"cl-app-cta cl-anim\" id=\"cl-app-cta\"#{section_style(border, min_h)}><div class=\"cl-container\">\n"
|
||||||
html << "<div class=\"cl-app-cta__inner\">\n<div class=\"cl-app-cta__content\">\n"
|
html << "<div class=\"cl-app-cta__inner\">\n<div class=\"cl-app-cta__content\">\n"
|
||||||
html << "<h2 class=\"cl-app-cta__headline\">#{e(@s.app_cta_headline)}</h2>\n"
|
html << "<h2 class=\"cl-app-cta__headline\"#{title_style(:app_cta_title_size)}>#{e(@s.app_cta_headline)}</h2>\n"
|
||||||
html << "<p class=\"cl-app-cta__subtext\">#{e(@s.app_cta_subtext)}</p>\n" if @s.app_cta_subtext.present?
|
html << "<p class=\"cl-app-cta__subtext\">#{e(@s.app_cta_subtext)}</p>\n" if @s.app_cta_subtext.present?
|
||||||
html << "<div class=\"cl-app-cta__badges\">\n"
|
html << "<div class=\"cl-app-cta__badges\">\n"
|
||||||
|
|
||||||
@@ -757,5 +804,20 @@ module CommunityLanding
|
|||||||
def logo_height
|
def logo_height
|
||||||
@logo_height ||= (@s.logo_height rescue 30)
|
@logo_height ||= (@s.logo_height rescue 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def title_style(setting_name)
|
||||||
|
size = (@s.public_send(setting_name) rescue 0).to_i
|
||||||
|
size > 0 ? " style=\"font-size: #{size}px\"" : ""
|
||||||
|
end
|
||||||
|
|
||||||
|
def button_with_icon(label, icon_setting, position_setting)
|
||||||
|
icon_name = (@s.public_send(icon_setting).presence rescue nil)
|
||||||
|
fa_enabled = (@s.fontawesome_enabled rescue false)
|
||||||
|
return e(label) unless icon_name && fa_enabled
|
||||||
|
|
||||||
|
position = (@s.public_send(position_setting) rescue "before")
|
||||||
|
icon_html = "<i class=\"fa-solid fa-#{e(icon_name)}\"></i>"
|
||||||
|
position == "after" ? "#{e(label)} #{icon_html}" : "#{icon_html} #{e(label)}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -51,11 +51,18 @@ module CommunityLanding
|
|||||||
topic_card_light = safe_hex(:topics_card_bg_light)
|
topic_card_light = safe_hex(:topics_card_bg_light)
|
||||||
space_card_dark = safe_hex(:groups_card_bg_dark)
|
space_card_dark = safe_hex(:groups_card_bg_dark)
|
||||||
space_card_light = safe_hex(:groups_card_bg_light)
|
space_card_light = safe_hex(:groups_card_bg_light)
|
||||||
|
faq_card_dark = safe_hex(:faq_card_bg_dark)
|
||||||
|
faq_card_light = safe_hex(:faq_card_bg_light)
|
||||||
part_card_dark = safe_hex(:participation_card_bg_dark)
|
part_card_dark = safe_hex(:participation_card_bg_dark)
|
||||||
part_card_light = safe_hex(:participation_card_bg_light)
|
part_card_light = safe_hex(:participation_card_bg_light)
|
||||||
part_icon_color = safe_hex(:participation_icon_color)
|
part_icon_color = safe_hex(:participation_icon_color)
|
||||||
|
|
||||||
|
orb_color = safe_hex(:orb_color)
|
||||||
|
orb_opacity = [[@s.orb_opacity.to_i, 0].max, 100].min rescue 50
|
||||||
|
orb_opacity = 50 if orb_opacity == 0 && (@s.orb_opacity.to_s.strip.empty? rescue true)
|
||||||
|
|
||||||
accent_rgb = hex_to_rgb(accent)
|
accent_rgb = hex_to_rgb(accent)
|
||||||
|
orb_rgb = orb_color ? hex_to_rgb(orb_color) : accent_rgb
|
||||||
stat_icon_rgb = hex_to_rgb(stat_icon)
|
stat_icon_rgb = hex_to_rgb(stat_icon)
|
||||||
|
|
||||||
stat_icon_bg_val = stat_icon_bg || "rgba(#{stat_icon_rgb}, 0.1)"
|
stat_icon_bg_val = stat_icon_bg || "rgba(#{stat_icon_rgb}, 0.1)"
|
||||||
@@ -108,7 +115,9 @@ module CommunityLanding
|
|||||||
--cl-hero-bg: #{dark_bg};
|
--cl-hero-bg: #{dark_bg};
|
||||||
--cl-gradient-text: linear-gradient(135deg, #{accent_hover}, #{accent}, #{accent_hover});
|
--cl-gradient-text: linear-gradient(135deg, #{accent_hover}, #{accent}, #{accent_hover});
|
||||||
--cl-border-hover: rgba(#{accent_rgb}, 0.25);
|
--cl-border-hover: rgba(#{accent_rgb}, 0.25);
|
||||||
--cl-orb-1: rgba(#{accent_rgb}, 0.12);
|
--cl-orb-1: rgba(#{orb_rgb}, 0.12);
|
||||||
|
--cl-orb-2: rgba(#{orb_rgb}, 0.08);
|
||||||
|
--cl-orb-opacity: #{orb_opacity / 100.0};
|
||||||
--cl-stat-icon-color: #{stat_icon};
|
--cl-stat-icon-color: #{stat_icon};
|
||||||
--cl-stat-icon-bg: #{stat_icon_bg_val};
|
--cl-stat-icon-bg: #{stat_icon_bg_val};
|
||||||
--cl-stat-counter-color: #{stat_counter_val};
|
--cl-stat-counter-color: #{stat_counter_val};
|
||||||
@@ -119,6 +128,7 @@ module CommunityLanding
|
|||||||
--cl-about-card-bg: #{about_dark_css};
|
--cl-about-card-bg: #{about_dark_css};
|
||||||
--cl-participation-card-bg: #{part_card_dark || 'var(--cl-card)'};
|
--cl-participation-card-bg: #{part_card_dark || 'var(--cl-card)'};
|
||||||
--cl-participation-icon-color: #{part_icon_color || 'var(--cl-accent)'};
|
--cl-participation-icon-color: #{part_icon_color || 'var(--cl-accent)'};
|
||||||
|
--cl-faq-card-bg: #{faq_card_dark || 'var(--cl-card)'};
|
||||||
--cl-app-gradient: linear-gradient(135deg, #{app_g1_dark}, #{app_g2_dark}, #{app_g3_dark});#{dark_extras}
|
--cl-app-gradient: linear-gradient(135deg, #{app_g1_dark}, #{app_g2_dark}, #{app_g3_dark});#{dark_extras}
|
||||||
}
|
}
|
||||||
[data-theme=\"light\"] {
|
[data-theme=\"light\"] {
|
||||||
@@ -130,7 +140,9 @@ module CommunityLanding
|
|||||||
--cl-hero-bg: #{light_bg};
|
--cl-hero-bg: #{light_bg};
|
||||||
--cl-gradient-text: linear-gradient(135deg, #{accent}, #{accent_hover}, #{accent});
|
--cl-gradient-text: linear-gradient(135deg, #{accent}, #{accent_hover}, #{accent});
|
||||||
--cl-border-hover: rgba(#{accent_rgb}, 0.3);
|
--cl-border-hover: rgba(#{accent_rgb}, 0.3);
|
||||||
--cl-orb-1: rgba(#{accent_rgb}, 0.08);
|
--cl-orb-1: rgba(#{orb_rgb}, 0.08);
|
||||||
|
--cl-orb-2: rgba(#{orb_rgb}, 0.05);
|
||||||
|
--cl-orb-opacity: #{orb_opacity / 100.0};
|
||||||
--cl-stat-icon-color: #{stat_icon};
|
--cl-stat-icon-color: #{stat_icon};
|
||||||
--cl-stat-icon-bg: #{stat_icon_bg_val};
|
--cl-stat-icon-bg: #{stat_icon_bg_val};
|
||||||
--cl-stat-counter-color: #{stat_counter_val};
|
--cl-stat-counter-color: #{stat_counter_val};
|
||||||
@@ -141,6 +153,7 @@ module CommunityLanding
|
|||||||
--cl-about-card-bg: #{about_light_css};
|
--cl-about-card-bg: #{about_light_css};
|
||||||
--cl-participation-card-bg: #{part_card_light || part_card_dark || 'var(--cl-card)'};
|
--cl-participation-card-bg: #{part_card_light || part_card_dark || 'var(--cl-card)'};
|
||||||
--cl-participation-icon-color: #{part_icon_color || 'var(--cl-accent)'};
|
--cl-participation-icon-color: #{part_icon_color || 'var(--cl-accent)'};
|
||||||
|
--cl-faq-card-bg: #{faq_card_light || faq_card_dark || 'var(--cl-card)'};
|
||||||
--cl-app-gradient: linear-gradient(135deg, #{app_g1_light || app_g1_dark}, #{app_g2_light || app_g2_dark}, #{app_g3_light || app_g3_dark});#{light_extras}
|
--cl-app-gradient: linear-gradient(135deg, #{app_g1_light || app_g1_dark}, #{app_g2_light || app_g2_dark}, #{app_g3_light || app_g3_dark});#{light_extras}
|
||||||
}
|
}
|
||||||
@media (prefers-color-scheme: light) {
|
@media (prefers-color-scheme: light) {
|
||||||
@@ -153,7 +166,9 @@ module CommunityLanding
|
|||||||
--cl-hero-bg: #{light_bg};
|
--cl-hero-bg: #{light_bg};
|
||||||
--cl-gradient-text: linear-gradient(135deg, #{accent}, #{accent_hover}, #{accent});
|
--cl-gradient-text: linear-gradient(135deg, #{accent}, #{accent_hover}, #{accent});
|
||||||
--cl-border-hover: rgba(#{accent_rgb}, 0.3);
|
--cl-border-hover: rgba(#{accent_rgb}, 0.3);
|
||||||
--cl-orb-1: rgba(#{accent_rgb}, 0.08);
|
--cl-orb-1: rgba(#{orb_rgb}, 0.08);
|
||||||
|
--cl-orb-2: rgba(#{orb_rgb}, 0.05);
|
||||||
|
--cl-orb-opacity: #{orb_opacity / 100.0};
|
||||||
--cl-stat-icon-color: #{stat_icon};
|
--cl-stat-icon-color: #{stat_icon};
|
||||||
--cl-stat-card-bg: #{stat_card_light || stat_card_dark || 'var(--cl-card)'};
|
--cl-stat-card-bg: #{stat_card_light || stat_card_dark || 'var(--cl-card)'};
|
||||||
--cl-space-card-bg: #{space_card_light || space_card_dark || 'var(--cl-card)'};
|
--cl-space-card-bg: #{space_card_light || space_card_dark || 'var(--cl-card)'};
|
||||||
@@ -161,6 +176,7 @@ module CommunityLanding
|
|||||||
--cl-about-card-bg: #{about_light_css};
|
--cl-about-card-bg: #{about_light_css};
|
||||||
--cl-participation-card-bg: #{part_card_light || part_card_dark || 'var(--cl-card)'};
|
--cl-participation-card-bg: #{part_card_light || part_card_dark || 'var(--cl-card)'};
|
||||||
--cl-participation-icon-color: #{part_icon_color || 'var(--cl-accent)'};
|
--cl-participation-icon-color: #{part_icon_color || 'var(--cl-accent)'};
|
||||||
|
--cl-faq-card-bg: #{faq_card_light || faq_card_dark || 'var(--cl-card)'};
|
||||||
--cl-app-gradient: linear-gradient(135deg, #{app_g1_light || app_g1_dark}, #{app_g2_light || app_g2_dark}, #{app_g3_light || app_g3_dark});#{light_extras}
|
--cl-app-gradient: linear-gradient(135deg, #{app_g1_light || app_g1_dark}, #{app_g2_light || app_g2_dark}, #{app_g3_light || app_g3_dark});#{light_extras}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ after_initialize do
|
|||||||
base_url = Discourse.base_url
|
base_url = Discourse.base_url
|
||||||
csp = "default-src 'self' #{base_url}; " \
|
csp = "default-src 'self' #{base_url}; " \
|
||||||
"script-src 'self' 'unsafe-inline'; " \
|
"script-src 'self' 'unsafe-inline'; " \
|
||||||
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " \
|
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdnjs.cloudflare.com; " \
|
||||||
"style-src-elem 'self' 'unsafe-inline' https://fonts.googleapis.com; " \
|
"style-src-elem 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdnjs.cloudflare.com; " \
|
||||||
"img-src 'self' #{base_url} data: https:; " \
|
"img-src 'self' #{base_url} data: https:; " \
|
||||||
"font-src 'self' #{base_url} https://fonts.gstatic.com; " \
|
"font-src 'self' #{base_url} https://fonts.gstatic.com https://cdnjs.cloudflare.com; " \
|
||||||
"media-src 'self' https:; " \
|
"media-src 'self' https:; " \
|
||||||
"connect-src 'self' #{base_url}; " \
|
"connect-src 'self' #{base_url}; " \
|
||||||
"frame-src https://www.youtube.com https://www.youtube-nocookie.com; " \
|
"frame-src https://www.youtube.com https://www.youtube-nocookie.com; " \
|
||||||
|
|||||||
Reference in New Issue
Block a user