diff --git a/public/index.html b/index.html
similarity index 100%
rename from public/index.html
rename to index.html
diff --git a/src/components/Auth/Subscription.tsx b/src/components/Auth/Subscription.tsx
index 628b540fd..796b3ff3f 100644
--- a/src/components/Auth/Subscription.tsx
+++ b/src/components/Auth/Subscription.tsx
@@ -4,6 +4,7 @@ import { useClient } from '@vocdoni/react-providers'
import { dotobject, ensure0x } from '@vocdoni/sdk'
import { ReactNode, useMemo } from 'react'
import { useAuth } from '~components/Auth/useAuth'
+import type { Plan } from '~components/Pricing/Plans'
import { ApiEndpoints } from './api'
type PermissionsContextType = {
@@ -27,27 +28,7 @@ type SubscriptionType = {
subOrgs: number
members: number
}
- plan: {
- id: number
- name: string
- stripeID: string
- default: boolean
- organization: {
- memberships: number
- subOrgs: number
- censusSize: number
- }
- votingTypes: {
- approval: boolean
- ranked: boolean
- weighted: boolean
- }
- features: {
- personalization: boolean
- emailReminder: boolean
- smsNotification: boolean
- }
- }
+ plan: Plan
}
const [SubscriptionProvider, useSubscription] = createContext({
diff --git a/src/components/Layout/Form/DetailedCheckbox.tsx b/src/components/Layout/Form/DetailedCheckbox.tsx
new file mode 100644
index 000000000..482d47508
--- /dev/null
+++ b/src/components/Layout/Form/DetailedCheckbox.tsx
@@ -0,0 +1,28 @@
+import { Checkbox, CheckboxProps, Text, useMultiStyleConfig } from '@chakra-ui/react'
+import { cloneElement, ReactElement } from 'react'
+import { useFormContext } from 'react-hook-form'
+
+export type DetailedBoxProps = CheckboxProps & {
+ badge?: ReactElement
+ description?: string
+ icon?: ReactElement
+ name: string
+ title: string
+}
+
+export const DetailedBox = ({ icon, badge, title, description, name, ...props }: DetailedBoxProps) => {
+ const styles = useMultiStyleConfig('DetailedBox', props)
+ const { register } = useFormContext()
+
+ return (
+
+
+ {icon && cloneElement(icon, { sx: styles.icon })}
+ {title}
+
+ {description}
+
+ {badge && cloneElement(badge, { sx: styles.badge })}
+
+ )
+}
diff --git a/src/components/Pricing/Features.tsx b/src/components/Pricing/Features.tsx
index 4181b777c..5dd325d6e 100644
--- a/src/components/Pricing/Features.tsx
+++ b/src/components/Pricing/Features.tsx
@@ -2,15 +2,7 @@ import { dotobject } from '@vocdoni/sdk'
import { useTranslation } from 'react-i18next'
import type { Plan } from './Plans'
-export type FeaturesKeys =
- | 'anonymous'
- | 'secretUntilTheEnd'
- | 'overwrite'
- | 'personalization'
- | 'emailReminder'
- | 'smsNotification'
- | 'whiteLabel'
- | 'liveStreaming'
+export type FeaturesKeys = 'personalization' | 'emailReminder' | 'smsNotification' | 'whiteLabel' | 'liveStreaming'
// Translation keys for the subscription features
export const PlanFeaturesTranslationKeys = {
@@ -24,6 +16,15 @@ export const PlanFeaturesTranslationKeys = {
'features.smsNotification': 'features.sms_notification',
}
+/**
+ * Checks if the specified feature exists in the plan.
+ *
+ * @param plan - The plan object to check.
+ * @param featurePath - Dot notation path to the feature (e.g., 'organization.memberships').
+ * @returns boolean - `true` if the feature exists, `false` otherwise.
+ */
+export const hasFeature = (plan: Plan, featurePath: string) => dotobject(plan, featurePath) !== 'undefined'
+
/**
* Checks if a given feature exists and meets the required condition in a plan.
*
diff --git a/src/components/Pricing/utils.ts b/src/components/Pricing/utils.ts
index ceca5afcf..19f4f8e6f 100644
--- a/src/components/Pricing/utils.ts
+++ b/src/components/Pricing/utils.ts
@@ -16,15 +16,12 @@ export const isFeatureAvailable = (
featurePath: string,
expectedValue?: number | { operator: '===' | '>' | '>=' | '<' | '<='; value: number }
): boolean => {
- const featureValue = dotobject(plan, featurePath) // Get the feature value using dot notation
+ // Get the feature value using dot notation
+ const featureValue = dotobject(plan, featurePath)
+ // If the feature doesn't exist, return false
if (typeof featureValue === 'undefined') {
- return false // If the feature doesn't exist, return false
- }
-
- // If no expected value is provided, return true if the feature exists
- if (typeof expectedValue === 'undefined') {
- return true
+ return false
}
// Handle exact match or comparison
@@ -32,6 +29,11 @@ export const isFeatureAvailable = (
return featureValue >= expectedValue // Default to "greater than or equal to" for numbers
}
+ // Booleans are treated as exact matches
+ if (typeof featureValue === 'boolean') {
+ return featureValue
+ }
+
if (typeof expectedValue === 'object' && expectedValue.operator && expectedValue.value !== undefined) {
const { operator, value } = expectedValue
diff --git a/src/components/ProcessCreate/Questions/useVotingType.ts b/src/components/ProcessCreate/Questions/useVotingType.ts
index cb72942f2..834f35263 100644
--- a/src/components/ProcessCreate/Questions/useVotingType.ts
+++ b/src/components/ProcessCreate/Questions/useVotingType.ts
@@ -5,13 +5,13 @@ import SingleChoice from '~components/ProcessCreate/Questions/SingleChoice'
import { GenericFeatureObject } from '~components/ProcessCreate/Steps/TabsPage'
export const VotingTypeSingle = 'single'
-export const UnimplementedVotingTypeApproval = 'approval'
+export const VotingTypeApproval = 'approval'
export const MultiQuestionTypes = [VotingTypeSingle]
-export type VotingType = typeof VotingTypeSingle | typeof UnimplementedVotingTypeApproval
+export type VotingType = typeof VotingTypeSingle | typeof VotingTypeApproval
-export const VotingTypes = [VotingTypeSingle as VotingType, UnimplementedVotingTypeApproval as VotingType]
+export const VotingTypes = [VotingTypeSingle as VotingType, VotingTypeApproval as VotingType]
export const useVotingType = (): GenericFeatureObject => {
const { t } = useTranslation()
@@ -24,7 +24,7 @@ export const useVotingType = (): GenericFeatureObject => {
icon: GiChoice,
component: SingleChoice,
},
- [UnimplementedVotingTypeApproval]: {
+ [VotingTypeApproval]: {
title: t('process_create.question.approval_voting.title'),
description: t('process_create.question.approval_voting.description'),
icon: GiChoice,
diff --git a/src/components/ProcessCreate/Settings/SaasFeatures.tsx b/src/components/ProcessCreate/Settings/Features.tsx
similarity index 58%
rename from src/components/ProcessCreate/Settings/SaasFeatures.tsx
rename to src/components/ProcessCreate/Settings/Features.tsx
index 46f31f1ac..c78257e13 100644
--- a/src/components/ProcessCreate/Settings/SaasFeatures.tsx
+++ b/src/components/ProcessCreate/Settings/Features.tsx
@@ -1,10 +1,11 @@
-import { Box, Checkbox, CheckboxProps, Flex, Icon, Text } from '@chakra-ui/react'
+import { Badge, Flex, Icon } from '@chakra-ui/react'
import { useMemo } from 'react'
import { useFormContext } from 'react-hook-form'
import { useTranslation } from 'react-i18next'
-import { IconType } from 'react-icons'
import { BiCheckDouble } from 'react-icons/bi'
import { useSubscription } from '~components/Auth/Subscription'
+import { DetailedBox } from '~components/Layout/Form/DetailedCheckbox'
+import { usePricingModal } from '~components/Pricing/Modals'
const useProcessFeatures = () => {
const { t } = useTranslation()
@@ -13,86 +14,93 @@ const useProcessFeatures = () => {
anonymous: {
title: t('anonymous.title', { defaultValue: 'Anonymous' }),
description: t('anonymous.description', { defaultValue: 'Voters will remain anonymous' }),
- boxIcon: BiCheckDouble,
- formKey: 'electionType.anonymous',
+ icon: BiCheckDouble,
+ name: 'electionType.anonymous',
+ permission: 'features.anonymous',
},
secretUntilTheEnd: {
title: t('secret_until_the_end.title', { defaultValue: 'Secret until the end' }),
description: t('secret_until_the_end.description', {
defaultValue: 'Vote contents will be encrypted till the end of the voting',
}),
- boxIcon: BiCheckDouble,
- formKey: 'electionType.secretUntilTheEnd',
+ icon: BiCheckDouble,
+ name: 'electionType.secretUntilTheEnd',
},
overwrite: {
title: t('overwrite.title', { defaultValue: 'Vote overwrite' }),
description: t('overwrite.description', { defaultValue: 'Voters will be able to overwrite their vote once' }),
- formKey: 'maxVoteOverwrites',
- boxIcon: BiCheckDouble,
+ name: 'maxVoteOverwrites',
+ icon: BiCheckDouble,
+ permission: 'features.voteOverwrite',
},
// non implemented features...
// personalization: {
// title: t('personalization.title', { defaultValue: 'personalization' }),
// description: t('personalization.description', { defaultValue: 'personalization' }),
- // boxIcon: BiCheckDouble,
+ // icon: BiCheckDouble,
// },
// emailReminder: {
// title: t('email_reminder.title', { defaultValue: 'Email reminder' }),
// description: t('email_reminder.description', { defaultValue: 'Remind by email' }),
- // boxIcon: BiCheckDouble,
+ // icon: BiCheckDouble,
// },
// smsNotification: {
// title: t('sms_notification.title', { defaultValue: 'SMS Notification' }),
// description: t('sms_notification.description', { defaultValue: 'Notify users somehow (?)' }),
- // boxIcon: BiCheckDouble,
+ // icon: BiCheckDouble,
// },
// whiteLabel: {
// title: t('white_label.title', { defaultValue: 'White label' }),
// description: t('white_label.description', { defaultValue: 'Customize the process layout entirely adding your own logos and color palette' }),
- // boxIcon: BiCheckDouble,
+ // icon: BiCheckDouble,
// },
// liveStreaming: {
// title: t('live_streaming.title', { defaultValue: 'Live Streaming' }),
// description: t('live_streaming.description', { defaultValue: 'IDK what\'s this about' }),
- // boxIcon: BiCheckDouble,
+ // icon: BiCheckDouble,
// },
}),
[t]
)
}
+
export const Features = () => {
- const { subscription } = useSubscription()
+ const { t } = useTranslation()
const translations = useProcessFeatures()
+ const { permission } = useSubscription()
+ const { openModal } = usePricingModal()
+ const { setValue, getValues } = useFormContext()
return (
- {Object.entries(translations).map(([feature, card], i) => (
-
- ))}
-
- )
-}
+ {Object.entries(translations).map(([feature, card], i) => {
+ const needsUpgrade = 'permission' in card && !permission(card.permission)
-interface CheckBoxCardProps {
- title: string
- description: string
- boxIcon: IconType
- isPro?: boolean
- formKey?: string
-}
-
-const CheckBoxCard = ({ title, description, boxIcon, isPro, formKey, ...rest }: CheckBoxCardProps & CheckboxProps) => {
- const { register, watch } = useFormContext()
+ return (
+ {t('upgrade')}}
+ icon={card.icon && }
+ isChecked={getValues(card.name)}
+ onChange={(e) => {
+ if (!needsUpgrade) {
+ setValue(card.name, e.target.checked)
+ return
+ }
- return (
-
- {isPro && Pro}
-
-
- {title}
-
-
- {description}
-
+ openModal('planUpgrade', {
+ feature: 'permission' in card && card.permission,
+ text: translations[feature].title,
+ })
+ // reset the value to false
+ setValue(card.name, false)
+ return false
+ }}
+ />
+ )
+ })}
+
)
}
diff --git a/src/components/ProcessCreate/StepForm/SaasFeatures.tsx b/src/components/ProcessCreate/StepForm/Features.tsx
similarity index 85%
rename from src/components/ProcessCreate/StepForm/SaasFeatures.tsx
rename to src/components/ProcessCreate/StepForm/Features.tsx
index de24caa9b..af8676ba9 100644
--- a/src/components/ProcessCreate/StepForm/SaasFeatures.tsx
+++ b/src/components/ProcessCreate/StepForm/Features.tsx
@@ -1,14 +1,14 @@
import { Flex } from '@chakra-ui/react'
import { FormProvider, SubmitHandler, useForm } from 'react-hook-form'
import { FeaturesKeys } from '~components/Pricing/Features'
-import { Features as SaasFeaturesComponent } from '~components/ProcessCreate/Settings/SaasFeatures'
+import { Features as SaasFeaturesComponent } from '~components/ProcessCreate/Settings/Features'
import { ConfigurationValues } from '~components/ProcessCreate/StepForm/Info'
import { StepsNavigation } from '~components/ProcessCreate/Steps/Navigation'
import Wrapper from '~components/ProcessCreate/Steps/Wrapper'
import { useProcessCreationSteps } from '../Steps/use-steps'
-export type SaasFeaturesValues = { saasFeatures: Record }
-interface FeaturesForm extends SaasFeaturesValues, ConfigurationValues {}
+export type FeaturesValues = { features: Record }
+interface FeaturesForm extends FeaturesValues, ConfigurationValues {}
export const SaasFeatures = () => {
const { form, setForm, next } = useProcessCreationSteps()
diff --git a/src/components/ProcessCreate/StepForm/Questions.tsx b/src/components/ProcessCreate/StepForm/Questions.tsx
index b2e570f46..bbc7ea0c3 100644
--- a/src/components/ProcessCreate/StepForm/Questions.tsx
+++ b/src/components/ProcessCreate/StepForm/Questions.tsx
@@ -41,6 +41,7 @@ const QuestionsTabs = () => {
{
const newQuestionType = definedVotingTypes.defined[index]
// If the question type not accepts multiquestion and there are multiple questions selcted store only the first
diff --git a/src/components/ProcessCreate/Steps/Form.tsx b/src/components/ProcessCreate/Steps/Form.tsx
index 1cc91d71e..f6cb50649 100644
--- a/src/components/ProcessCreate/Steps/Form.tsx
+++ b/src/components/ProcessCreate/Steps/Form.tsx
@@ -37,13 +37,11 @@ export const StepsForm = ({ steps, activeStep, next, prev, setActiveStep }: Step
weightedVote: false,
questions: [{ options: [{}, {}] }],
addresses: [],
+ // these do not end up in the election process object, but are required for other purposes
gpsWeighted: false,
passportScore: 20,
stampsUnionType: 'OR',
- saasFeatures: {
- anonymous: false,
- secretUntilTheEnd: true,
- overwrite: false,
+ features: {
personalization: false,
emailReminder: false,
smsNotification: false,
diff --git a/src/components/ProcessCreate/Steps/TabsPage.tsx b/src/components/ProcessCreate/Steps/TabsPage.tsx
index 503a9d052..5d0d68a3b 100644
--- a/src/components/ProcessCreate/Steps/TabsPage.tsx
+++ b/src/components/ProcessCreate/Steps/TabsPage.tsx
@@ -1,8 +1,24 @@
-import { Box, Flex, Icon, Tab, TabList, TabPanel, TabPanels, Tabs, Text, useDisclosure } from '@chakra-ui/react'
+import {
+ Badge,
+ Box,
+ Flex,
+ Icon,
+ Tab,
+ TabList,
+ TabPanel,
+ TabPanels,
+ Tabs,
+ Text,
+ useDisclosure,
+ useMultiStyleConfig,
+} from '@chakra-ui/react'
import { TabProps } from '@chakra-ui/tabs/dist/tab'
-import { useState } from 'react'
-import { useTranslation } from 'react-i18next'
+import { useMemo, useState } from 'react'
+import { Trans, useTranslation } from 'react-i18next'
import { CgMoreO } from 'react-icons/cg'
+import { useSubscription } from '~components/Auth/Subscription'
+import { hasFeature } from '~components/Pricing/Features'
+import { usePricingModal } from '~components/Pricing/Modals'
import ModalPro from '~components/ProcessCreate/ModalPro'
import { StepsNavigation } from '~components/ProcessCreate/Steps/Navigation'
import Wrapper from '~components/ProcessCreate/Steps/Wrapper'
@@ -25,6 +41,7 @@ export interface ITabsPageProps
unimplementedList: GenericFeatureObject
}
@@ -36,18 +53,32 @@ export const TabsPage = ) => {
const { t } = useTranslation()
const { isOpen, onOpen, onClose } = useDisclosure()
-
+ const { permission, subscription } = useSubscription()
+ const { openModal } = usePricingModal()
const { defined, details } = definedList
const { defined: definedUnim, details: detailsUnim } = unimplementedList
-
+ const [tab, setTab] = useState(defined.findIndex((val) => val === selected))
const [reason, setReason] = useState('')
const [showProCards, setShowProCards] = useState(false)
if (!defined || !definedUnim) return null
+ // Store upgrade requirements per feature for later use
+ const requireUpgrade = useMemo(
+ () =>
+ defined.map((ct: Implemented) => {
+ if (permissionsPath) {
+ return (hasFeature(subscription.plan, permissionsPath) && permission(`${permissionsPath}.${ct}`)) === false
+ }
+ return false
+ }),
+ [subscription]
+ )
+
return (
@@ -56,19 +87,48 @@ export const TabsPage = {title}
{description}
- val === selected)} onChange={onTabChange} variant='card' isLazy>
+ val === selected)}
+ index={tab}
+ onChange={(index: number) => {
+ // Check if the feature requires an account upgrade
+ if (permissionsPath) {
+ const requiresUpgrade = requireUpgrade[index] || false
+ const key = defined[index]
+
+ if (requiresUpgrade) {
+ openModal('planUpgrade', {
+ feature: `${permissionsPath}.${key}`,
+ text: details[key].title,
+ })
+ return false
+ }
+ }
+
+ setTab(index)
+ onTabChange(index)
+ }}
+ variant='card'
+ isLazy
+ >
<>
- {defined.map((ct: Implemented, index: number) => (
- setShowProCards(false)}
- icon={details[ct].icon}
- title={details[ct].title}
- description={details[ct].description}
- check
- />
- ))}
+ {defined.map((ct: Implemented, index: number) => {
+ const needsUpgrade = requireUpgrade[index] || false
+ return (
+ {
+ setShowProCards(false)
+ }}
+ icon={details[ct].icon}
+ title={details[ct].title}
+ description={details[ct].description}
+ check
+ needsUpgrade={needsUpgrade}
+ />
+ )
+ })}
{!!definedUnim.length && (
setShowProCards((prev) => !prev)}
@@ -93,7 +153,7 @@ export const TabsPage =
))}
>
@@ -120,7 +180,7 @@ interface ITabsCardSkeletonProps {
title: string
description: string
check?: boolean
- pro?: boolean
+ needsUpgrade?: boolean
}
const TabCardSkeleton = ({
@@ -129,25 +189,43 @@ const TabCardSkeleton = ({
title,
description,
check = false,
- pro = false,
+ needsUpgrade = false,
...props
-}: ITabsCardSkeletonProps & TabProps) => (
-
- {check && (
- <>
-
-
- >
- )}
- {pro && (
-
- Pro
+}: ITabsCardSkeletonProps & TabProps) => {
+ const styles = useMultiStyleConfig('DetailedBox', props)
+
+ return (
+
+ {check && (
+ <>
+
+
+ >
+ )}
+
+
+
+ {convertParagraphs(title)}
- )}
-
-
- {convertParagraphs(title)}
-
- {description}
-
-)
+ {description}
+ {needsUpgrade && (
+
+ Upgrade
+
+ )}
+
+ )
+}
diff --git a/src/components/ProcessCreate/Steps/use-steps.tsx b/src/components/ProcessCreate/Steps/use-steps.tsx
index e5f9e7f5e..ad0c4b5c7 100644
--- a/src/components/ProcessCreate/Steps/use-steps.tsx
+++ b/src/components/ProcessCreate/Steps/use-steps.tsx
@@ -1,7 +1,7 @@
import { createContext, Dispatch, SetStateAction, useContext } from 'react'
import { useTranslation } from 'react-i18next'
import { CensusGitcoinValues } from '~components/ProcessCreate/StepForm/CensusGitcoin'
-import { SaasFeatures, SaasFeaturesValues } from '~components/ProcessCreate/StepForm/SaasFeatures'
+import { FeaturesValues, SaasFeatures } from '~components/ProcessCreate/StepForm/Features'
import { CensusCspValues } from '../StepForm/CensusCsp'
import { CensusSpreadsheetValues } from '../StepForm/CensusSpreadsheet'
import { CensusTokenValues } from '../StepForm/CensusToken'
@@ -21,7 +21,7 @@ export interface StepsFormValues
CensusCspValues,
CensusGitcoinValues,
CensusSpreadsheetValues,
- SaasFeaturesValues {}
+ FeaturesValues {}
export interface StepsState {
title: string
diff --git a/src/elements/dashboard/processes/create.tsx b/src/elements/dashboard/processes/create.tsx
index 78ebe7924..4a38474ad 100644
--- a/src/elements/dashboard/processes/create.tsx
+++ b/src/elements/dashboard/processes/create.tsx
@@ -1,5 +1,10 @@
+import { PricingModalProvider } from '~components/Pricing/Modals'
import Steps from '~components/ProcessCreate/Steps'
-const ProcessCreate = () =>
+const ProcessCreate = () => (
+
+
+
+)
export default ProcessCreate
diff --git a/src/importmeta.d.ts b/src/importmeta.d.ts
index 8867b5590..01951439c 100644
--- a/src/importmeta.d.ts
+++ b/src/importmeta.d.ts
@@ -1,6 +1,7 @@
interface ImportMeta {
env: {
NODE_ENV: string
+ DEV: boolean
BASE_URL: string
VOCDONI_ENVIRONMENT: string
CUSTOM_FAUCET_URL: string
diff --git a/src/theme/components/Tabs.ts b/src/theme/components/Tabs.ts
index d3d01f511..5b274efdf 100644
--- a/src/theme/components/Tabs.ts
+++ b/src/theme/components/Tabs.ts
@@ -31,59 +31,13 @@ const card = definePartsStyle({
borderRadius: 'xl',
w: 'full',
- '& > #description': {
- color: 'tab.variant.card.description.light',
- textAlign: 'start',
- fontSize: 'xs',
- _dark: {
- color: 'tab.variant.card.description.dark',
- },
- },
-
- '& #pro-badge': {
- bgColor: 'tab.variant.card.badge_bg',
- borderRadius: '10px',
- position: 'absolute',
- top: '3px',
- right: '3px',
- px: 4,
- color: 'badge.pro_color',
- pt: '2px',
- fontSize: '12px',
- },
-
- '& > #title': {
- display: 'flex',
- alignItems: 'center',
- w: 'full',
- gap: 3,
- fontSize: 'sm',
-
- '& p': {
- fontWeight: 'bold',
- textAlign: 'start',
- },
- },
-
- // Empty checkbox
- '& #empty-check': {
- position: 'absolute',
- top: 2.5,
- right: 2.5,
- w: 4,
- h: 4,
- borderRadius: 'full',
- border: `1px solid`,
- borderColor: 'tab.variant.card.border',
- },
-
'& > svg': {
w: 5,
h: 5,
color: 'tab.variant.card.svg',
position: 'absolute',
- top: 2,
- right: 2,
+ top: '1rem',
+ right: '1rem',
display: 'none',
},
@@ -93,7 +47,7 @@ const card = definePartsStyle({
display: 'block',
},
- '& > #empty-check': {
+ '& > .empty': {
display: 'none',
},
diff --git a/src/theme/components/checkbox.ts b/src/theme/components/checkbox.ts
index 92c5b872d..8b1094692 100644
--- a/src/theme/components/checkbox.ts
+++ b/src/theme/components/checkbox.ts
@@ -2,30 +2,36 @@ import { checkboxAnatomy } from '@chakra-ui/anatomy'
import { createMultiStyleConfigHelpers, defineStyle } from '@chakra-ui/react'
const { definePartsStyle, defineMultiStyleConfig } = createMultiStyleConfigHelpers(checkboxAnatomy.keys)
+const { definePartsStyle: defineDetailedPartsStyle, defineMultiStyleConfig: defineDetailedMultiStyleConfig } =
+ createMultiStyleConfigHelpers(['icon', 'title', 'badge', 'description', 'checkbox'])
-export const Checkbox = defineMultiStyleConfig({
- baseStyle: {
- control: {
- borderRadius: 'full',
- _checked: {
- borderColor: 'checkbox.checked.border',
- bgColor: 'checkbox.checked.bg',
-
- _hover: {
- borderColor: 'checkbox.checked.border',
- bgColor: 'checkbox.checked.bg',
- },
- },
- _focus: {
- boxShadow: 'none',
- },
+export const DetailedBox = defineDetailedMultiStyleConfig({
+ baseStyle: defineDetailedPartsStyle((props) => ({
+ title: {
+ display: 'flex',
+ alignItems: 'center',
+ gap: 2,
+ fontWeight: 'bold',
+ fontSize: 'sm',
+ },
+ badge: {
+ position: 'absolute',
+ top: '.9rem',
+ right: '.9rem',
},
- icon: {
- color: 'checkbox.icon',
+ description: {
+ textAlign: 'start',
+ fontSize: 'sm',
},
+ })),
+})
+
+export const Checkbox = defineMultiStyleConfig({
+ defaultProps: {
+ colorScheme: 'brand',
},
variants: {
- radiobox: definePartsStyle({
+ detailed: definePartsStyle({
container: defineStyle({
position: 'relative',
display: 'flex',
@@ -47,53 +53,13 @@ export const Checkbox = defineMultiStyleConfig({
}),
control: defineStyle({
position: 'absolute',
- right: 1,
- top: 1,
+ right: '1rem',
+ top: '1rem',
rounded: 'full',
- ml: 'auto',
- display: 'flex',
- justifyContent: 'center',
- alignItems: 'center',
-
- _checked: {
- border: 'none',
- },
}),
label: defineStyle({
fontSize: 'sm',
alignSelf: 'start',
-
- '& > div:first-of-type': {
- display: 'flex',
- alignItems: 'center',
- gap: 2,
- fontWeight: 'bold',
- mb: 2,
- },
-
- '& > p': {
- fontSize: 'sm',
- textAlign: 'start',
- },
-
- //pro plan, it allows opening the modal
- '& > span': {
- borderRadius: 'xl',
- position: 'absolute',
- top: 1,
- right: 1,
- px: 2,
- bgColor: 'checkbox.bg',
- fontSize: 'sm',
- color: 'white',
- },
- '& div:nth-of-type(2)': {
- position: 'absolute',
- h: '100%',
- w: '100%',
- top: 0,
- left: 0,
- },
}),
}),
},
diff --git a/src/theme/index.ts b/src/theme/index.ts
index e90b045a5..13198f5ab 100644
--- a/src/theme/index.ts
+++ b/src/theme/index.ts
@@ -7,7 +7,7 @@ import { Accordion } from './components/accordion'
import { Badge } from './components/badge'
import { Button } from './components/button'
import { Card } from './components/card'
-import { Checkbox } from './components/checkbox'
+import { Checkbox, DetailedBox } from './components/checkbox'
import { Form } from './components/Form'
import { ElectionTitle, Heading } from './components/heading'
import { Input } from './components/input'
@@ -83,6 +83,7 @@ export const theme = extendTheme(vtheme, {
Button,
Card,
Checkbox,
+ DetailedBox,
ElectionTitle,
ElectionQuestions,
ElectionResults,
diff --git a/vite.config.ts b/vite.config.ts
index 4bfa96557..ed798ff71 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -56,7 +56,7 @@ const viteconfig = ({ mode }) => {
react(),
svgr(),
createHtmlPlugin({
- template: `public/index.html`,
+ template: `index.html`,
minify: {
removeComments: false,
collapseWhitespace: true,