mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 17:43:47 +00:00
fix: add light theme support to connection page
Add isLight-aware styling to all block renderers (cards, timeline, accordion, minimal), BlockButtons, and InstallationGuide. Update colorParser gradient functions to generate light-appropriate backgrounds. Reduce wave blob opacity on light theme for better content readability.
This commit is contained in:
@@ -8,6 +8,7 @@ import type {
|
||||
RemnawavePlatformData,
|
||||
RemnawaveButtonClient,
|
||||
} from '@/types';
|
||||
import { useTheme } from '@/hooks/useTheme';
|
||||
import { CardsBlock, TimelineBlock, AccordionBlock, MinimalBlock, BlockButtons } from './blocks';
|
||||
import type { BlockRendererProps } from './blocks';
|
||||
|
||||
@@ -51,6 +52,7 @@ export default function InstallationGuide({
|
||||
onGoBack,
|
||||
}: Props) {
|
||||
const { t, i18n } = useTranslation();
|
||||
const { isLight } = useTheme();
|
||||
|
||||
const detectedPlatform = useMemo(() => detectPlatform(), []);
|
||||
const isMobile = typeof window !== 'undefined' && window.innerWidth < 768;
|
||||
@@ -127,6 +129,7 @@ export default function InstallationGuide({
|
||||
<BlockButtons
|
||||
buttons={buttons}
|
||||
variant={variant}
|
||||
isLight={isLight}
|
||||
subscriptionUrl={appConfig.subscriptionUrl}
|
||||
hideLink={appConfig.hideLink}
|
||||
deepLink={selectedApp?.deepLink}
|
||||
@@ -140,6 +143,7 @@ export default function InstallationGuide({
|
||||
appConfig.subscriptionUrl,
|
||||
appConfig.hideLink,
|
||||
selectedApp?.deepLink,
|
||||
isLight,
|
||||
getLocalizedText,
|
||||
getBaseTranslation,
|
||||
getSvgHtml,
|
||||
@@ -221,9 +225,11 @@ export default function InstallationGuide({
|
||||
if (app) setSelectedApp(app);
|
||||
}
|
||||
}}
|
||||
className={`appearance-none rounded-xl border border-dark-700 bg-dark-800 py-2 pr-8 text-sm font-medium text-dark-200 outline-none transition-colors hover:border-dark-600 ${
|
||||
currentPlatformSvg ? 'pl-10' : 'pl-4'
|
||||
}`}
|
||||
className={`appearance-none rounded-xl border py-2 pr-8 text-sm font-medium outline-none transition-colors ${
|
||||
isLight
|
||||
? 'border-dark-700/60 bg-white/80 text-dark-200 shadow-sm hover:border-dark-600'
|
||||
: 'border-dark-700 bg-dark-800 text-dark-200 hover:border-dark-600'
|
||||
} ${currentPlatformSvg ? 'pl-10' : 'pl-4'}`}
|
||||
>
|
||||
{availablePlatforms.map((p) => (
|
||||
<option key={p} value={p}>
|
||||
@@ -258,8 +264,12 @@ export default function InstallationGuide({
|
||||
onClick={() => setSelectedApp(app)}
|
||||
className={`relative flex min-w-[calc(50%-0.25rem)] items-center gap-2 overflow-hidden rounded-xl px-4 py-2 text-sm font-medium transition-all active:scale-[0.97] ${
|
||||
isSelected
|
||||
? 'bg-accent-500/15 text-accent-400 ring-1 ring-accent-500/40'
|
||||
: 'border border-dark-700/50 bg-dark-800/80 text-dark-200 hover:border-dark-600/50 hover:bg-dark-700/80'
|
||||
? isLight
|
||||
? 'bg-accent-500/15 text-accent-600 ring-1 ring-accent-500/40'
|
||||
: 'bg-accent-500/15 text-accent-400 ring-1 ring-accent-500/40'
|
||||
: isLight
|
||||
? 'border border-dark-700/60 bg-white/80 text-dark-200 shadow-sm hover:border-dark-600/50 hover:bg-white'
|
||||
: 'border border-dark-700/50 bg-dark-800/80 text-dark-200 hover:border-dark-600/50 hover:bg-dark-700/80'
|
||||
}`}
|
||||
>
|
||||
{app.featured && <span className="h-2 w-2 shrink-0 rounded-full bg-amber-400" />}
|
||||
@@ -306,6 +316,7 @@ export default function InstallationGuide({
|
||||
<Renderer
|
||||
blocks={selectedApp.blocks}
|
||||
isMobile={isMobile}
|
||||
isLight={isLight}
|
||||
getLocalizedText={getLocalizedText}
|
||||
getSvgHtml={getSvgHtml}
|
||||
renderBlockButtons={renderBlockButtons}
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { BlockRendererProps } from './types';
|
||||
export function AccordionBlock({
|
||||
blocks,
|
||||
isMobile,
|
||||
isLight,
|
||||
getLocalizedText,
|
||||
getSvgHtml,
|
||||
renderBlockButtons,
|
||||
@@ -15,14 +16,20 @@ export function AccordionBlock({
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
{blocks.map((block, index) => {
|
||||
const gradientStyle = getColorGradient(block.svgIconColor || 'cyan');
|
||||
const gradientStyle = getColorGradient(block.svgIconColor || 'cyan', isLight);
|
||||
const isOpen = openIndex === index;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={`overflow-hidden rounded-2xl border bg-dark-800/50 transition-colors ${
|
||||
isOpen ? 'border-accent-500/30' : 'border-dark-700/50'
|
||||
className={`overflow-hidden rounded-2xl border transition-colors ${
|
||||
isLight
|
||||
? isOpen
|
||||
? 'border-accent-500/30 bg-white/80 shadow-sm'
|
||||
: 'border-dark-700/60 bg-white/60'
|
||||
: isOpen
|
||||
? 'border-accent-500/30 bg-dark-800/50'
|
||||
: 'border-dark-700/50 bg-dark-800/50'
|
||||
}`}
|
||||
>
|
||||
{/* Control */}
|
||||
|
||||
@@ -38,6 +38,7 @@ const CheckIcon = () => (
|
||||
interface BlockButtonsProps {
|
||||
buttons: RemnawaveButtonClient[] | undefined;
|
||||
variant: 'light' | 'subtle';
|
||||
isLight?: boolean;
|
||||
subscriptionUrl: string | null;
|
||||
hideLink?: boolean;
|
||||
deepLink?: string | null;
|
||||
@@ -50,6 +51,7 @@ interface BlockButtonsProps {
|
||||
export function BlockButtons({
|
||||
buttons,
|
||||
variant,
|
||||
isLight,
|
||||
subscriptionUrl,
|
||||
hideLink,
|
||||
deepLink,
|
||||
@@ -80,8 +82,12 @@ export function BlockButtons({
|
||||
|
||||
const baseClass =
|
||||
variant === 'light'
|
||||
? 'rounded-xl border border-accent-500/40 px-4 py-2 text-sm font-medium text-accent-400 transition-all hover:bg-accent-500/10'
|
||||
: 'rounded-xl px-3 py-1.5 text-sm font-medium text-dark-300 transition-all hover:bg-dark-700/50';
|
||||
? isLight
|
||||
? 'rounded-xl border border-accent-500/50 px-4 py-2 text-sm font-medium text-accent-600 shadow-sm transition-all hover:bg-accent-500/10'
|
||||
: 'rounded-xl border border-accent-500/40 px-4 py-2 text-sm font-medium text-accent-400 transition-all hover:bg-accent-500/10'
|
||||
: isLight
|
||||
? 'rounded-xl px-3 py-1.5 text-sm font-medium text-dark-300 transition-all hover:bg-dark-700/30'
|
||||
: 'rounded-xl px-3 py-1.5 text-sm font-medium text-dark-300 transition-all hover:bg-dark-700/50';
|
||||
|
||||
return (
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
@@ -120,7 +126,7 @@ export function BlockButtons({
|
||||
onClick={() => handleCopy(url)}
|
||||
className={`flex items-center gap-2 ${
|
||||
copied
|
||||
? 'rounded-xl border border-success-500 bg-success-500/10 px-4 py-2 text-sm font-medium text-success-400'
|
||||
? `rounded-xl border border-success-500 bg-success-500/10 px-4 py-2 text-sm font-medium ${isLight ? 'text-success-600' : 'text-success-400'}`
|
||||
: baseClass
|
||||
}`}
|
||||
>
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { BlockRendererProps } from './types';
|
||||
export function CardsBlock({
|
||||
blocks,
|
||||
isMobile,
|
||||
isLight,
|
||||
getLocalizedText,
|
||||
getSvgHtml,
|
||||
renderBlockButtons,
|
||||
@@ -12,12 +13,16 @@ export function CardsBlock({
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
{blocks.map((block, index) => {
|
||||
const gradientStyle = getColorGradient(block.svgIconColor || 'cyan');
|
||||
const gradientStyle = getColorGradient(block.svgIconColor || 'cyan', isLight);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="rounded-2xl border border-dark-700/50 bg-dark-800/50 p-4 sm:p-5"
|
||||
className={`rounded-2xl border p-4 sm:p-5 ${
|
||||
isLight
|
||||
? 'border-dark-700/60 bg-white/80 shadow-sm'
|
||||
: 'border-dark-700/50 bg-dark-800/50'
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start gap-3 sm:gap-4">
|
||||
<ThemeIcon
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { BlockRendererProps } from './types';
|
||||
export function MinimalBlock({
|
||||
blocks,
|
||||
isMobile,
|
||||
isLight,
|
||||
getLocalizedText,
|
||||
getSvgHtml,
|
||||
renderBlockButtons,
|
||||
@@ -12,11 +13,18 @@ export function MinimalBlock({
|
||||
return (
|
||||
<div>
|
||||
{blocks.map((block, index) => {
|
||||
const gradientStyle = getColorGradient(block.svgIconColor || 'cyan');
|
||||
const gradientStyle = getColorGradient(block.svgIconColor || 'cyan', isLight);
|
||||
const isLast = index === blocks.length - 1;
|
||||
|
||||
return (
|
||||
<div key={index} className={isLast ? 'pb-4' : 'mb-4 border-b border-dark-700/50 pb-4'}>
|
||||
<div
|
||||
key={index}
|
||||
className={
|
||||
isLast
|
||||
? 'pb-4'
|
||||
: `mb-4 border-b pb-4 ${isLight ? 'border-dark-700/40' : 'border-dark-700/50'}`
|
||||
}
|
||||
>
|
||||
<div className="mb-2 flex items-center gap-3">
|
||||
<ThemeIcon
|
||||
getSvgHtml={getSvgHtml}
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { BlockRendererProps } from './types';
|
||||
export function TimelineBlock({
|
||||
blocks,
|
||||
isMobile,
|
||||
isLight,
|
||||
getLocalizedText,
|
||||
getSvgHtml,
|
||||
renderBlockButtons,
|
||||
@@ -12,7 +13,7 @@ export function TimelineBlock({
|
||||
return (
|
||||
<div className="space-y-0">
|
||||
{blocks.map((block, index) => {
|
||||
const gradientStyle = getColorGradientSolid(block.svgIconColor || 'cyan');
|
||||
const gradientStyle = getColorGradientSolid(block.svgIconColor || 'cyan', isLight);
|
||||
const isLast = index === blocks.length - 1;
|
||||
|
||||
return (
|
||||
@@ -25,7 +26,9 @@ export function TimelineBlock({
|
||||
gradientStyle={gradientStyle}
|
||||
isMobile={isMobile}
|
||||
/>
|
||||
{!isLast && <div className="w-0.5 flex-1 bg-dark-700" />}
|
||||
{!isLast && (
|
||||
<div className={`w-0.5 flex-1 ${isLight ? 'bg-dark-700/40' : 'bg-dark-700'}`} />
|
||||
)}
|
||||
</div>
|
||||
{/* Right column: content */}
|
||||
<div className={`min-w-0 flex-1 ${isLast ? '' : 'pb-6'}`}>
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { RemnawaveBlockClient, RemnawaveButtonClient, LocalizedText } from
|
||||
export interface BlockRendererProps {
|
||||
blocks: RemnawaveBlockClient[];
|
||||
isMobile: boolean;
|
||||
isLight: boolean;
|
||||
getLocalizedText: (text: LocalizedText | undefined) => string;
|
||||
getSvgHtml: (key: string | undefined) => string;
|
||||
renderBlockButtons: (
|
||||
|
||||
@@ -1512,8 +1512,8 @@ input[type='checkbox']:hover:not(:checked) {
|
||||
|
||||
/* Light theme adjustments */
|
||||
.light .wave-blob {
|
||||
opacity: 0.6;
|
||||
filter: blur(70px);
|
||||
opacity: 0.35;
|
||||
filter: blur(80px);
|
||||
}
|
||||
|
||||
.light .wave-blob-1 {
|
||||
|
||||
@@ -31,16 +31,37 @@ export interface ColorGradientStyle {
|
||||
boxShadow?: string;
|
||||
}
|
||||
|
||||
export const getColorGradient = (color: string): ColorGradientStyle => {
|
||||
export const getColorGradient = (color: string, light?: boolean): ColorGradientStyle => {
|
||||
const [r, g, b] = getRgb(color);
|
||||
if (light) {
|
||||
return {
|
||||
background: `linear-gradient(135deg, rgba(${r},${g},${b},0.12) 0%, rgba(${r},${g},${b},0.05) 100%)`,
|
||||
border: `1px solid rgba(${r},${g},${b},0.2)`,
|
||||
boxShadow: `0 1px 3px rgba(${r},${g},${b},0.1)`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
background: `linear-gradient(135deg, rgba(${r},${g},${b},0.15) 0%, rgba(${r},${g},${b},0.08) 100%)`,
|
||||
border: `1px solid rgba(${r},${g},${b},0.3)`,
|
||||
};
|
||||
};
|
||||
|
||||
export const getColorGradientSolid = (color: string): ColorGradientStyle => {
|
||||
export const getColorGradientSolid = (color: string, light?: boolean): ColorGradientStyle => {
|
||||
const [r, g, b] = getRgb(color);
|
||||
if (light) {
|
||||
// Light theme: soft tinted background instead of dark solid
|
||||
const light1 = [245 + r * 0.02, 243 + g * 0.02, 240 + b * 0.02].map((v) =>
|
||||
Math.min(255, Math.floor(v)),
|
||||
);
|
||||
const light2 = [240 + r * 0.03, 237 + g * 0.03, 233 + b * 0.03].map((v) =>
|
||||
Math.min(255, Math.floor(v)),
|
||||
);
|
||||
return {
|
||||
background: `linear-gradient(135deg, rgb(${light1}) 0%, rgb(${light2}) 100%)`,
|
||||
border: `1px solid rgba(${r},${g},${b},0.25)`,
|
||||
boxShadow: `0 1px 4px rgba(${r},${g},${b},0.12)`,
|
||||
};
|
||||
}
|
||||
const dark1 = [22 + r * 0.08, 27 + g * 0.08, 35 + b * 0.08].map(Math.floor);
|
||||
const dark2 = [20 + r * 0.05, 24 + g * 0.05, 30 + b * 0.05].map(Math.floor);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user