subtitle configuration

This commit is contained in:
Anton Tranelis 2025-10-12 08:26:57 +02:00
parent 6408941844
commit a4822ffc28
13 changed files with 167 additions and 42 deletions

View File

@ -60,6 +60,8 @@
"public_registration_role": null,
"public_registration_email_filter": null,
"visual_editor_urls": null,
"accepted_terms": true,
"project_id": "0199aa52-4dd7-7293-984a-f2af93b5f8fd",
"_syncId": "55f04445-0c26-4201-ab9c-d6e0fbadf6bf"
}
]

View File

@ -24,14 +24,14 @@
"display": null,
"display_options": null,
"field": "cta_button_label",
"group": "Header",
"group": "header_elements",
"hidden": false,
"interface": "input",
"note": null,
"options": null,
"readonly": false,
"required": false,
"sort": 6,
"sort": 5,
"special": null,
"translations": null,
"validation": null,

View File

@ -0,0 +1,29 @@
{
"collection": "types",
"field": "header_elements",
"type": "alias",
"meta": {
"collection": "types",
"conditions": null,
"display": null,
"display_options": null,
"field": "header_elements",
"group": "Header",
"hidden": false,
"interface": "group-raw",
"note": null,
"options": null,
"readonly": false,
"required": false,
"sort": 3,
"special": [
"alias",
"no-data",
"group"
],
"translations": null,
"validation": null,
"validation_message": null,
"width": "full"
}
}

View File

@ -8,14 +8,14 @@
"display": null,
"display_options": null,
"field": "show_cta_button",
"group": "Header",
"group": "header_elements",
"hidden": false,
"interface": "boolean",
"note": null,
"options": null,
"readonly": false,
"required": false,
"sort": 5,
"sort": 4,
"special": [
"cast-boolean"
],

View File

@ -8,14 +8,14 @@
"display": null,
"display_options": null,
"field": "show_navigation_button",
"group": "Header",
"group": "header_elements",
"hidden": false,
"interface": "boolean",
"note": null,
"options": null,
"readonly": false,
"required": false,
"sort": 4,
"sort": 2,
"special": [
"cast-boolean"
],

View File

@ -8,14 +8,14 @@
"display": null,
"display_options": null,
"field": "show_qr_button",
"group": "Header",
"group": "header_elements",
"hidden": false,
"interface": "boolean",
"note": null,
"options": null,
"readonly": false,
"required": false,
"sort": 2,
"sort": 1,
"special": [
"cast-boolean"
],

View File

@ -8,7 +8,7 @@
"display": null,
"display_options": null,
"field": "show_share_button",
"group": "Header",
"group": "header_elements",
"hidden": false,
"interface": "boolean",
"note": null,

View File

@ -0,0 +1,74 @@
{
"collection": "types",
"field": "subtitle_label",
"type": "string",
"meta": {
"collection": "types",
"conditions": [
{
"hidden": false,
"name": "subtitle=custom",
"readonly": false,
"required": true,
"rule": {
"_and": [
{
"subtitle_mode": {
"_eq": "custom"
}
}
]
}
},
{
"hidden": true,
"name": "subtitle != custom",
"readonly": true,
"required": false,
"rule": {
"_and": [
{
"subtitle_mode": {
"_neq": "custom"
}
}
]
}
}
],
"display": null,
"display_options": null,
"field": "subtitle_label",
"group": "Header",
"hidden": false,
"interface": "input",
"note": null,
"options": null,
"readonly": false,
"required": false,
"sort": 2,
"special": null,
"translations": null,
"validation": null,
"validation_message": null,
"width": "half"
},
"schema": {
"name": "subtitle_label",
"table": "types",
"data_type": "character varying",
"default_value": "Subname",
"max_length": 255,
"numeric_precision": null,
"numeric_scale": null,
"is_nullable": true,
"is_unique": false,
"is_indexed": false,
"is_primary_key": false,
"is_generated": false,
"generation_expression": null,
"has_auto_increment": false,
"foreign_key_table": null,
"foreign_key_column": null
}
}

View File

@ -1,35 +1,48 @@
{
"collection": "types",
"field": "show_address",
"type": "boolean",
"field": "subtitle_mode",
"type": "string",
"meta": {
"collection": "types",
"conditions": null,
"display": null,
"display_options": null,
"field": "show_address",
"field": "subtitle_mode",
"group": "Header",
"hidden": false,
"interface": "boolean",
"interface": "select-dropdown",
"note": null,
"options": null,
"options": {
"choices": [
{
"text": "address",
"value": "address"
},
{
"text": "custom",
"value": "custom"
},
{
"text": "none",
"value": "none"
}
]
},
"readonly": false,
"required": false,
"sort": 1,
"special": [
"cast-boolean"
],
"special": null,
"translations": null,
"validation": null,
"validation_message": null,
"width": "half"
},
"schema": {
"name": "show_address",
"name": "subtitle_mode",
"table": "types",
"data_type": "boolean",
"default_value": true,
"max_length": null,
"data_type": "character varying",
"default_value": "address",
"max_length": 255,
"numeric_precision": null,
"numeric_scale": null,
"is_nullable": true,

View File

@ -12,7 +12,7 @@ interface ItemTitleProps {
item: Item
big?: boolean
truncateSubname?: boolean
showAddress?: boolean
subtitleMode?: 'address' | 'custom' | 'none'
hasAvatar?: boolean
}
@ -20,7 +20,7 @@ export function ItemTitle({
item,
big = false,
truncateSubname = true,
showAddress = true,
subtitleMode = 'address',
hasAvatar = false,
}: ItemTitleProps) {
const { distance } = useGeoDistance(item.position ?? undefined)
@ -31,12 +31,13 @@ export function ItemTitle({
const { address } = useReverseGeocode(
item.position?.coordinates as [number, number] | undefined,
showAddress,
subtitleMode === 'address',
'municipality',
)
const title = item.name ?? item.layer?.item_default_name
const subtitle = item.subname
const subtitleLabel = item.layer?.itemType.subtitle_label
useEffect(() => {
if (!containerRef.current || !title) {
@ -111,7 +112,7 @@ export function ItemTitle({
>
{title}
</div>
{showAddress && address && (
{subtitleMode === 'address' && address && (
<div className='tw:text-sm tw:flex tw:items-center tw:text-gray-500 tw:w-full'>
<MapPinIcon className='tw:w-4 tw:mr-1 tw:flex-shrink-0' />
<span title={address} className='tw:truncate'>
@ -120,7 +121,7 @@ export function ItemTitle({
</span>
</div>
)}
{subtitle && !showAddress && (
{subtitleMode === 'custom' && subtitle && (
<div
className={`tw:text-sm tw:opacity-50 tw:items-center ${truncateSubname ? 'tw:truncate' : ''}`}
>

View File

@ -33,6 +33,7 @@ export function HeaderView({
const hasAvatar = !!(item.image ?? item.image_external)
const isMyProfile = myProfile.myProfile?.id === item.id
const showQrButton = big && isMyProfile && (item.layer?.itemType.show_qr_button ?? true)
const subtitleMode = item.layer?.itemType.subtitle_mode ?? (showAddress ? 'address' : 'none')
return (
<>
@ -49,7 +50,7 @@ export function HeaderView({
item={item}
big={big}
truncateSubname={truncateSubname}
showAddress={showAddress}
subtitleMode={subtitleMode}
hasAvatar={hasAvatar}
/>
</div>

View File

@ -38,7 +38,9 @@ export const FormHeader = ({ item, state, setState }: Props) => {
}
className={'tw:-left-6 tw:top-14 tw:-mr-6'}
/>
<div className='tw:grow tw:mr-4 tw:pt-1'>
<div
className={`tw:grow tw:mr-4 ${item.layer?.itemType.subtitle_mode === 'custom' ? 'tw:pt-1' : 'tw:flex tw:items-center'}`}
>
<TextInput
placeholder='Name'
defaultValue={item.name ? item.name : ''}
@ -51,19 +53,21 @@ export const FormHeader = ({ item, state, setState }: Props) => {
containerStyle='tw:grow tw:px-4'
inputStyle='tw:input-md'
/>
<TextInput
placeholder='Subtitle'
required={false}
defaultValue={item.subname ? item.subname : ''}
updateFormValue={(v) =>
setState((prevState) => ({
...prevState,
subname: v,
}))
}
containerStyle='tw:grow tw:px-4 tw:mt-1'
inputStyle='tw:input-sm'
/>
{item.layer?.itemType.subtitle_mode === 'custom' && (
<TextInput
placeholder={item.layer.itemType.subtitle_label}
required={false}
defaultValue={item.subname ? item.subname : ''}
updateFormValue={(v) =>
setState((prevState) => ({
...prevState,
subname: v,
}))
}
containerStyle='tw:grow tw:px-4 tw:mt-1'
inputStyle='tw:input-sm'
/>
)}
</div>
</div>
</div>

View File

@ -22,7 +22,8 @@ export interface ItemType {
text_input_label?: string
show_header_view_in_form?: boolean
cta_button_label?: string
show_address?: boolean
subtitle_mode?: 'address' | 'custom' | 'none'
subtitle_label?: string
cta_relation?: string
show_cta_button?: boolean
show_qr_button?: boolean