Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e0a588a
fix
DarianM Oct 10, 2025
922c516
proper derive state from valtio; fix valtio reactivity in store
DarianM Oct 10, 2025
fbfea73
fix banner render
DarianM Oct 10, 2025
00b4d19
revert config subscription
DarianM Oct 10, 2025
7800552
revert subscribe
DarianM Oct 10, 2025
ed31ecb
add refresh back
DarianM Oct 10, 2025
ee1de2f
improve
DarianM Oct 10, 2025
2a38f1c
Merge branch 'subscribe' into banner-render
DarianM Oct 10, 2025
56fa9a4
fix the state
DarianM Oct 10, 2025
6c4e03d
persevere
DarianM Oct 10, 2025
feb4851
cleanup
DarianM Oct 10, 2025
9d8ce10
cleanup harder!:mango:
DarianM Oct 10, 2025
a2dc1f6
forgot this
DarianM Oct 10, 2025
2aa2391
aaand format!
DarianM Oct 10, 2025
e433455
Merge branch 'main' into banner-render
DarianM Oct 13, 2025
6ff921a
Merge branch 'main' into banner-render
DarianM Oct 14, 2025
53a2c57
Merge branch 'main' into banner-render
DarianM Oct 14, 2025
f8a2fb4
clean
DarianM Oct 14, 2025
a859f5d
use proxySet valtio util instead of Set
DarianM Oct 14, 2025
624e599
fix errors in widget so we can preview test
DarianM Oct 14, 2025
d952d9f
perf
DarianM Oct 15, 2025
e50637b
perf naming
DarianM Oct 15, 2025
69d0bb7
clean
DarianM Oct 15, 2025
65b750f
naming
DarianM Oct 15, 2025
5e89171
fix the preview
DarianM Oct 18, 2025
3426a13
persist
DarianM Oct 18, 2025
970a384
Merge branch 'main' into banner-render
DarianM Oct 18, 2025
2f19b0a
perf 'hooks'
DarianM Oct 18, 2025
dbe86be
add action back
DarianM Oct 18, 2025
949a223
add hook function
DarianM Oct 18, 2025
688baca
widget route
DarianM Oct 20, 2025
edea53a
no use for sync true in preview
DarianM Oct 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions frontend/app/components/banner/BannerAnimationSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useEffect } from 'react'
import { useState } from 'react'
import { type SlideAnimationType, SLIDE_ANIMATION } from '@shared/types'
import { Checkbox, ToolsDropdown } from '@/components'

Expand All @@ -24,21 +24,13 @@ export function BannerAnimationSelector({
? SLIDE_ANIMATION.Slide
: validated
})

const [isAnimated, setIsAnimated] = useState(
() => value !== SLIDE_ANIMATION.None
)

useEffect(() => {
setIsAnimated(value !== SLIDE_ANIMATION.None)
}, [value])
const isAnimated = value !== SLIDE_ANIMATION.None

return (
<div className="flex gap-md xl:flex-row flex-col xl:items-center items-start">
<Checkbox
checked={isAnimated}
onChange={(visible) => {
setIsAnimated(visible)
const animation = visible
? lastSelectedAnimation
: SLIDE_ANIMATION.None
Expand Down
49 changes: 21 additions & 28 deletions frontend/app/components/banner/BannerBuilder.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import {
BANNER_FONT_SIZES,
FONT_FAMILY_OPTIONS,
type BannerConfig
} from '@shared/types'
import { BANNER_FONT_SIZES, FONT_FAMILY_OPTIONS } from '@shared/types'
import {
BannerColorsSelector,
Divider,
ToolsDropdown,
CornerRadiusSelector
} from '@/components'
import { useUI } from '~/stores/uiStore'
import BuilderAccordion from '@/components/BuilderAccordion'
import { InputFieldset } from '@/components/builder/InputFieldset'
import { TitleInput } from '@/components/builder/TitleInput'
Expand All @@ -26,7 +21,8 @@ import {
SVGText,
SVGThumbnail
} from '~/assets/svg'
import { toolState } from '~/stores/toolStore'
import { useUIActions, useUIState } from '~/stores/uiStore'
import { useCurrentConfig } from '~/stores/toolStore'

interface Props {
onRefresh: (section: 'content' | 'appearance') => void
Expand Down Expand Up @@ -61,8 +57,9 @@ export function BannerBuilder({ onRefresh }: Props) {
}

function ContentBuilder({ onRefresh }: Props) {
const { actions: uiActions, state: uiState } = useUI()
const profile = toolState.currentConfig as BannerConfig
const uiState = useUIState()
const uiActions = useUIActions()
const [snap, profile] = useCurrentConfig({ sync: true })

return (
<BuilderAccordion
Expand All @@ -81,7 +78,7 @@ function ContentBuilder({ onRefresh }: Props) {
initialIsOpen={uiState.activeSection === 'content'}
>
<TitleInput
value={profile.bannerTitleText}
value={snap.bannerTitleText}
onChange={(value) => (profile.bannerTitleText = value)}
suggestions={config.suggestedTitles}
maxLength={config.titleMaxLength}
Expand All @@ -92,9 +89,9 @@ function ContentBuilder({ onRefresh }: Props) {

<DescriptionInput
label={config.messageLabel}
value={profile.bannerDescriptionText}
value={snap.bannerDescriptionText}
onChange={(text) => (profile.bannerDescriptionText = text)}
isVisible={profile.bannerDescriptionVisible}
isVisible={snap.bannerDescriptionVisible}
onVisibilityChange={(visible) =>
(profile.bannerDescriptionVisible = visible)
}
Expand All @@ -107,11 +104,12 @@ function ContentBuilder({ onRefresh }: Props) {
}

function AppearanceBuilder({ onRefresh }: Props) {
const { actions: uiActions, state: uiState } = useUI()
const profile = toolState.currentConfig as BannerConfig
const uiState = useUIState()
const uiActions = useUIActions()
const [snap, profile] = useCurrentConfig()

const defaultFontIndex = FONT_FAMILY_OPTIONS.findIndex(
(option) => option === profile.bannerFontName
(option) => option === snap.bannerFontName
)

return (
Expand Down Expand Up @@ -145,7 +143,7 @@ function AppearanceBuilder({ onRefresh }: Props) {
/>

<FontSizeInput
value={profile.bannerFontSize}
value={snap.bannerFontSize}
onChange={(value) => (profile.bannerFontSize = value)}
min={config.fontSizeRange.min}
max={config.fontSizeRange.max}
Expand All @@ -159,8 +157,8 @@ function AppearanceBuilder({ onRefresh }: Props) {
icon={<SVGColorPicker className="w-5 h-5" />}
>
<BannerColorsSelector
backgroundColor={profile.bannerBackgroundColor}
textColor={profile.bannerTextColor}
backgroundColor={snap.bannerBackgroundColor}
textColor={snap.bannerTextColor}
onBackgroundColorChange={(color: string) =>
(profile.bannerBackgroundColor = color)
}
Expand All @@ -177,7 +175,7 @@ function AppearanceBuilder({ onRefresh }: Props) {
icon={<SVGRoundedCorner className="w-5 h-5" />}
>
<CornerRadiusSelector
value={profile.bannerBorder}
value={snap.bannerBorder}
onChange={(value) => (profile.bannerBorder = value)}
/>
</InputFieldset>
Expand All @@ -189,7 +187,7 @@ function AppearanceBuilder({ onRefresh }: Props) {
icon={<SVGHeaderPosition className="w-5 h-5" />}
>
<BannerPositionSelector
value={profile.bannerPosition}
value={snap.bannerPosition}
onChange={(value) => (profile.bannerPosition = value)}
/>
</InputFieldset>
Expand All @@ -201,7 +199,7 @@ function AppearanceBuilder({ onRefresh }: Props) {
icon={<SVGAnimation className="w-5 h-5" />}
>
<BannerAnimationSelector
value={profile.bannerSlideAnimation}
value={snap.bannerSlideAnimation}
onChange={(value) => (profile.bannerSlideAnimation = value)}
/>
</InputFieldset>
Expand All @@ -213,13 +211,8 @@ function AppearanceBuilder({ onRefresh }: Props) {
icon={<SVGThumbnail className="w-5 h-5" />}
>
<BannerThumbnailSelector
isVisible={
typeof profile.bannerThumbnail === 'undefined' ||
!!profile.bannerThumbnail
}
onVisibilityChange={(visible) => {
profile.bannerThumbnail = visible ? 'default' : ''
}}
value={snap.bannerThumbnail}
onChange={(value) => (profile.bannerThumbnail = value)}
/>
</InputFieldset>
</BuilderAccordion>
Expand Down
5 changes: 2 additions & 3 deletions frontend/app/components/banner/BannerPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,23 @@ import React, {
useState
} from 'react'
import type { BannerConfig, Banner as BannerElement } from '@tools/components'
import type { BannerConfig as BannerStoredConfig } from '@shared/types'
import { useCurrentConfig } from '~/stores/toolStore'

export interface BannerHandle {
triggerPreview: () => void
}

interface Props {
profile: BannerStoredConfig
cdnUrl: string
ref?: React.Ref<BannerHandle>
}

export const BannerPreview = ({
profile,
cdnUrl,
ref
}: React.PropsWithChildren<Props>) => {
const [isLoaded, setIsLoaded] = useState(false)
const [profile] = useCurrentConfig()
const bannerContainerRef = useRef<HTMLDivElement>(null)
const bannerElementRef = useRef<BannerElement | null>(null)

Expand Down
11 changes: 6 additions & 5 deletions frontend/app/components/banner/BannerThumbnailSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ import { Checkbox, Thumbnail } from '@/components'
import wmLogo from '~/assets/images/wm_logo_animated.svg?url'

interface BannerThumbnailSelectorProps {
isVisible: boolean
onVisibilityChange: (visible: boolean) => void
value: string
onChange: (newValue: string) => void
}

export function BannerThumbnailSelector({
isVisible,
onVisibilityChange
value,
onChange
}: BannerThumbnailSelectorProps) {
const thumbnails = [wmLogo]
const [selectedThumbnail, setSelectedThumbnail] = useState(0)
const isVisible = Boolean(value)

return (
<div className="flex gap-md xl:flex-row flex-col xl:items-center items-start">
<Checkbox
checked={isVisible}
onChange={onVisibilityChange}
onChange={(visible) => onChange(visible ? 'default' : '')}
label="Visible"
/>
<div className="flex gap-md">
Expand Down
6 changes: 3 additions & 3 deletions frontend/app/components/builder/BuilderTabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import { useSnapshot } from 'valtio'
export function BuilderTabs({ children }: React.PropsWithChildren) {
const snap = useSnapshot(toolState)

const handleTabSelect = (stableKey: StableKey) => {
toolActions.selectVersion(stableKey)
const handleTabSelect = (profileId: StableKey) => {
toolActions.handleTabSelect(profileId)
}

const handleTabLabelChange = (newLabel: string) => {
toolState.currentConfig.versionName = newLabel
toolActions.handleVersionNameChange(newLabel)
}

// derive tab options consistently from snapshot
Expand Down
14 changes: 3 additions & 11 deletions frontend/app/components/redesign/components/BuilderPresetTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { cx } from 'class-variance-authority'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useCallback, useRef, useState } from 'react'
import { SVGEdit, SVGExclamationCircle } from '~/assets/svg'

type TabOption<T extends string> = { id: T; label: string; isDirty: boolean }
Expand All @@ -22,17 +22,11 @@ export const BuilderPresetTabs = <T extends string>({
}: Props<T>) => {
const tabListRef = useRef<HTMLDivElement>(null)

const [activeTabId, setActiveTabId] = useState(selectedId)
const [activeTabIdx, setActiveTabIdx] = useState(
options.findIndex((option) => option.id === selectedId)
)
const activeTabId = selectedId
const activeTabIdx = options.findIndex((option) => option.id === selectedId)
const [editingId, setEditingId] = useState<T | null>()
const [hasEditingError, setHasEditingError] = useState(false)

useEffect(() => {
setActiveTab(options.findIndex((option) => option.id === selectedId))
}, [selectedId])

const getTabElement = (id: T) => {
return tabListRef.current!.querySelector<HTMLElement>(
`#${idPrefix}-tab-${id}`
Expand All @@ -43,8 +37,6 @@ export const BuilderPresetTabs = <T extends string>({
(tabIndex: number) => {
if (tabIndex < 0) tabIndex += options.length
const tabId = options[tabIndex].id
setActiveTabIdx(tabIndex)
setActiveTabId(tabId)
onChange(tabId)
getTabElement(tabId)?.focus()
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useState, useId, useRef, useEffect } from 'react'
import { useSnapshot } from 'valtio'
import { Tooltip } from './Tooltip'
import { InputField } from './InputField'
import { ToolsSecondaryButton } from './ToolsSecondaryButton'
Expand All @@ -8,7 +7,8 @@ import { SVGRefresh, SVGSpinner } from '~/assets/svg'
import { toolState, toolActions } from '~/stores/toolStore'
import type { ElementErrors } from '~/lib/types'
import { Heading5 } from '../Typography'
import { useUI } from '~/stores/uiStore'
import { useUIActions } from '~/stores/uiStore'
import { useSnapshot } from 'valtio'
import {
checkHrefFormat,
getWalletAddress,
Expand All @@ -17,7 +17,7 @@ import {

export const ToolsWalletAddress = () => {
const snap = useSnapshot(toolState)
const { actions: uiActions } = useUI()
const uiActions = useUIActions()
const [error, setError] = useState<ElementErrors>()
const [isLoading, setIsLoading] = useState(false)
const generatedId = useId()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useEffect, useRef } from 'react'
import Checkbox from '../Checkbox'
import { TextareaField } from '../TextareaField'

Expand All @@ -23,13 +22,6 @@ export function DescriptionInput({
helpText,
placeholder
}: Props) {
const ref = useRef<HTMLTextAreaElement>(null)
useEffect(() => {
if (ref.current) {
ref.current.value = value
}
}, [value])

return (
<fieldset className="space-y-xs">
<legend className="text-base leading-md font-bold text-text-primary">
Expand All @@ -46,9 +38,8 @@ export function DescriptionInput({

<div className="flex-grow w-full">
<TextareaField
defaultValue={value}
value={value}
onChange={(e) => onChange(e.target.value)}
ref={ref}
currentLength={value.length || 0}
maxLength={maxLength}
showCounter={true}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useRef } from 'react'
import { useRef } from 'react'
import Divider from '../Divider'
import { InputField } from '../InputField'
import PillRadioListItem from '../PillRadioListItem'
Expand Down Expand Up @@ -80,19 +80,13 @@ function CustomTitle({
helpText
}: Omit<Props, 'suggestions'> & { placeholder: string }) {
const ref = useRef<HTMLInputElement>(null)
useEffect(() => {
if (ref.current) {
ref.current.value = value
}
}, [value])

return (
<div className="flex flex-col gap-xs">
<h4 className="text-base leading-md font-bold text-text-primary">
Custom title
</h4>
<InputField
defaultValue={value}
value={value}
onChange={(e) => onChange(e.target.value.trim())}
ref={ref}
placeholder={placeholder}
Expand Down
2 changes: 2 additions & 0 deletions frontend/app/components/redesign/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { Checkbox } from './Checkbox'
export { StepsIndicator } from './StepsIndicator'
export { MobileStepsIndicator } from './StepsIndicator'
export { BuilderBackground } from './BuilderBackground'
export { BuilderAccordion } from './BuilderAccordion'
export { HeadingCore } from './HeadingCore'
export { ToolsWalletAddress } from './ToolsWalletAddress'
export { ToolsDropdown } from './ToolsDropdown'
Expand Down Expand Up @@ -39,6 +40,7 @@ export { PillTag } from './landing/PillTag'
export { LinkTagGenerator } from './LinkTagGenerator'
export { CodeBlockLink } from './CodeBlockLink'
export { Card } from './Card'
export { TitleInput } from './builder/TitleInput'
export { ImportTagModal } from './revshare/ImportTagModal'
export { RevShareChart } from './revshare/RevShareChart'
export { ShareInput } from './revshare/ShareInput'
Expand Down
Loading