---
title: "Diseño personalizado en CalendarWeek"
slug: "individuelles-design-in-der-calendarweek"
category: "Ejemplos"
hosts: "ninox"
locale: "es"
reactExampleKind: "recipe"
reactExample: "recipe-calendar.tsx"
---

# Diseño personalizado en CalendarWeek

# Diseño personalizado en CalendarWeek

![](https://framerusercontent.com/images/8GpUlcwkZdOmzYEMBkbiw4Fy2Y.png)

En este artículo os mostramos paso a paso cómo construir, con ayuda de **Layouts** y widgets complementarios, una **Card** con diseño personalizado para `customCalendarWeek`.

💡 No solo aprenderéis cómo **anidar widgets** de forma elegante, sino que también obtendréis directamente los **códigos de ejemplo** correspondientes de nuestro setup.

Tanto como **plantilla directa** (los nombres de tabla, campos e IDs los tenéis que adaptar, claro, a vuestro sistema) como **inspiración para vuestros propios diseños** en el estilo típico de arcRiderWidget: esta guía os ayuda a llevar vuestro calendario al siguiente nivel, tanto visual como funcionalmente.

## Widgets necesarios

- **Widget: **[*customCalendarWeek*](/documentation/custom-calendar-week)
- **Mini Widgets integrados: **[*Layout*](/documentation/custom-layout)*, *[*Button*](https://www.arc-rider.de/documentation/buttons)*, *[*Select*](https://www.arc-rider.de/documentation/select)*, *[*Icon*](https://www.arc-rider.de/documentation/custom-icon)*, *[*Image*](/documentation/images)* y *[*Text*](/documentation/text)*.*

## Let's build together 🚀

Antes de empezar, asegurad que vuestra **base de datos de Ninox** contiene las tablas y campos necesarios; podéis usar estructuras existentes o crearlas de nuevo.

Para el layout de la card en este caso de uso usamos las siguientes tablas:

<figure><table><tbody><tr><th>


</th><th>Tablas

</th></tr><tr><td>![](https://framerusercontent.com/images/lP1viIyLdkCNeoESjqzUBAzWc.png)

</td><td>- Clientes
- Empleados</p><ul><li data-preset-tag="p"><p>Citas
- Participantes de la cita

</li>- Custom Calendar</p><li data-preset-tag="p"><p>Status_Termine
- Typ_Termin

</li></ul></td></tr></tbody></table></figure>***Consejo:*** Para la selección dinámica se pueden crear tablas auxiliares/de ajustes, donde se guardan los valores de color e icono para luego llamarlos en los widgets correspondientes.

Así los valores están centralizados y no hay que introducirlos manualmente cada vez que se quieren usar también en otras superficies con distintos widgets.

![](https://framerusercontent.com/images/eK0VYGXu2VKBnER4WlJUYOL0tM.png)

## Diseño personalizado de la card

### Integrar los widgets de forma clara

El layout de la calenderCard y los distintos widgets a integrar se crean en la tabla *Citas*, cuyos registros finalmente se llaman dentro de customCalendarWeek.

![](https://framerusercontent.com/images/BRqVTA1AaUt8cqAWVWANW49wc.png)

Aquí creamos para cada fila de la card un campo fx con un layout cada uno, y campos fx para elementos como layouts adicionales, Select, Button. Esto ofrece buena claridad al programar los layouts, y además los distintos diseños se pueden intercambiar/sustituir/probar más rápido.

###  Línea 1

![](https://framerusercontent.com/images/44pvIfDknaVhBorSTm8eGTIrGl4.png)

**Paso 1:** Empezamos con los elementos externalizados para la primera línea.

#### select_status

![](https://framerusercontent.com/images/AL1lKCPYqxa2RpoLdIEnRi2cZkU.png)

*Widgets usados: customSelect + customLayout*

Código:


```javascript
let current := this;
arcCustomSelect({
        uniqueId: "Status Termin" + nr,
        recordId: nr,
        field: "Y",
        embedded: true,
        width: "100%",
        height: "25px",
        alignX: "",
        fontColor: "",
        backgroundColor: text(record(Status_Termin,number(Status)).Farbcode),
        borderColor: "none",
        borderWidth: "0px",
        borderRadius: "5px",
        itemsSettings: {
            width: "100%",
            height: "auto",
            borderRadius: "5px"
        },
        clickPosition: "",
        placeholder: "",
        disabled: false,
        reset: {
            title: "reset",
            value: "",
            hide: true
        },
        currentValue: arcCustomLayout({
                uniqueId: "status-bezeichnung-current " + nr,
                embedded: true,
                direction: "horizontal",
                alignX: "left",
                alignY: "center",
                width: "100%",
                height: "auto",
                gap: "10px",
                backgroundColor: text(record(Status_Termin,number(Status)).Farbcode),
                paddingY: "1px",
                paddingX: "1px",
                styles: "border-radius: 5px;",
                scrollSettings: {
                    scrollY: false,
                    scrollX: false
                },
                blocks: [{
                        width: "100%",
                        height: "auto",
                        lineHeight: "",
                        alignX: "left",
                        color: "",
                        styles: "",
                        value: text(record(Status_Termin,number(Status)).Bezeichnung)
                    }]
            }),
        items: let id := nr;
        (select Status_Termin).[{
                title: arcCustomLayout({
                        uniqueId: "status-bezeichnung " + Nr,
                        embedded: true,
                        direction: "horizontal",
                        alignX: "left",
                        alignY: "center",
                        width: "100%",
                        height: "",
                        gap: "0px",
                        backgroundColor: Farbcode,
                        paddingY: "3px",
                        paddingX: "5px",
                        styles: "border-radius: 5px;",
                        scrollSettings: {
                            scrollY: false,
                            scrollX: false
                        },
                        blocks: [{
                                width: "100%",
                                height: "auto",
                                lineHeight: "",
                                alignX: "left",
                                color: "",
                                styles: "",
                                value: Bezeichnung
                            }]
                    }),
                active: number(id.Status) = number(Nr),
                value: number(Nr)
            }]
    })
```

#### layout_line1_left

![](https://framerusercontent.com/images/PVJ8DYdrEqoq42ocr4Z7TVR674.png)

*Widgets usados: customLayout + customIcon + customText*

Código:


```javascript
let current := this;
arcCustomLayout({
        uniqueId: "calenderCard line1 left" + nr,
        embedded: true,
        direction: "horizontal",
        alignX: "center",
        alignY: "center",
        width: "100%",
        height: "100%",
        gap: "3px",
        backgroundColor: "",
        paddingY: "0px",
        paddingX: "0px",
        styles: "",
        scrollSettings: {
            scrollY: false,
            scrollX: false
        },
        blocks: [{
                width: "auto",
                height: "auto",
                alignX: "center",
                color: "",
                styles: "",
                clickAction: {
                    recordId: nr,
                    type: "popup"
                },
                value: arcCustomIcon({
                        iconSet: "phosphor",
                        name: text(record(Typ_Termin,number(Typ)).iconName),
                        containerSize: "20px",
                        iconSize: "20px",
                        color: text(record(Typ_Termin,number(current.Typ)).colorDark)
                    })
            }, {
                width: "100%",
                height: "100%",
                alignX: "left",
                color: "",
                clickAction: {
                    recordId: nr,
                    type: "popup"
                },
                value: arcCustomText({
                        uniqueId: "appointment-title" + nr,
                        embedded: true,
                        fontSize: "12px",
                        fontWeight: "700",
                        fontColor: text(record(Typ_Termin,number(current.Typ)).colorDark),
                        lineHeight: "1.2",
                        textDirection: "horizontal",
                        value: text(Bezeichnung)
                    })
            }]
    })
```

**Paso 2: **Después ambos elementos se colocan en el layout de la primera línea.

#### calendarCard_line1

![](https://framerusercontent.com/images/v6TEsRutvjB6BG1c5Ow8ZCfvLI.png)

*Widgets usados: customLayout*

Código:


```javascript
let current := this;
arcCustomLayout({
        uniqueId: "calenderCard line1 " + nr,
        embedded: true,
        direction: "horizontal",
        alignX: "center",
        alignY: "top",
        width: "100%",
        height: "100%",
        gap: "10px",
        backgroundColor: "",
        paddingY: "0px",
        paddingX: "0px",
        styles: "",
        scrollSettings: {
            scrollY: false,
            scrollX: false
        },
        blocks: [{
                width: "fraction",
                height: "auto",
                alignX: "center",
                color: "",
                value: layout_line1_left
            }, {
                width: "35%",
                height: "auto",
                alignX: "right",
                color: "",
                value: select_status
            }]
    })
```

### Línea 2

![](https://framerusercontent.com/images/yx2JRb0qA1pCBGY8bOldxpBJ9BE.png)

**Paso 1:** Empezamos de nuevo con el elemento externalizado para la segunda línea.

#### button_customer

![](https://framerusercontent.com/images/BdZ0RuNR87kw7lkQHglNBX3YU4w.png)

*Widgets usados: customButton + customIcon*

Código:


```javascript
let current := this;
let lilaDark := "#35339E";
let lilaMiddle := "#D2D2F7";
arcCustomButton({
        uniqueId: "Button-kunde " + nr,
        title: text(Kunde.Name),
        embedded: true,
        width: "auto",
        height: "25px",
        alignY: "",
        alignX: "",
        paddingX: "",
        paddingY: "",
        gap: "5px",
        icon: arcCustomIcon({
                name: "link",
                color: lilaDark,
                containerSize: "20px",
                borderSize: "",
                borderColor: "",
                borderRadius: "",
                iconSize: "20px"
            }),
        iconPosition: "left",
        fontSize: "12px",
        fontColor: lilaDark,
        backgroundColor: lilaMiddle,
        borderColor: lilaMiddle,
        borderRadius: "5px",
        showBadge: false,
    })
```

**Paso 2:** Después el elemento se inserta en el layout de la segunda línea.

#### calendarCard_line2

![](https://framerusercontent.com/images/Y3WqsaZ1F91rdQrGG5rQi1P3Q.png)

*Widgets usados: customLayout + customText*

Código:


```javascript
let current := this;
arcCustomLayout({
        uniqueId: "calenderCard line2 " + nr,
        embedded: true,
        direction: "horizontal",
        alignX: "center",
        alignY: "top",
        width: "100%",
        height: "100%",
        gap: "10px",
        backgroundColor: "",
        paddingY: "",
        paddingX: "",
        styles: "",
        scrollSettings: {
            scrollY: false,
            scrollX: false
        },
        blocks: [{
                width: "50%",
                height: "auto",
                lineHeight: "",
                alignX: "left",
                color: "",
                styles: "",
                value: arcCustomText({
                        uniqueId: "appointment-time" + nr,
                        embedded: true,
                        fontSize: "15px",
                        fontWeight: "500",
                        fontColor: text(record(Typ_Termin,number(current.Typ)).colorDark),
                        lineHeight: "1.2",
                        textDirection: "",
                        value: text(Von) + " - " + text(Bis) + " Uhr"
                    })
            }, {
                width: "50%",
                height: "auto",
                lineHeight: "",
                alignX: "right",
                color: "",
                value: if Kunde != null then button_customer end,
                clickAction: {
                    type: "popup",
                    recordId: current.Kunde.Nr
                }
            }]
    })
```

### Línea 3

![](https://framerusercontent.com/images/O4s594gvSjPVo8E0fIqyLh6fb8.png)

**Paso 1:** La tercera línea se divide en dos layouts; además necesitamos un campo fx para calcular la vista limitada a 3 participantes.

#### paginatedList_teilnehmer

Código:


```javascript
let maxEntries := 3;
let currentPage := 1;
let list := Terminteilnehmer;
let paginatedList := unique(record(Terminteilnehmer,0).Mitarbeiter)[!= 0];
for listItem in slice(list.Nr, maxEntries * (currentPage - 1), maxEntries * currentPage) do
    paginatedList := unique(paginatedList, record(Terminteilnehmer,listItem).Mitarbeiter)
end;
paginatedList
```

#### layout_buttons

![](https://framerusercontent.com/images/DWYLtB9xfkSKjIkIo0V9mLkPWtw.png)

*Widgets usados: customLayout + customButton + customIcon*

Código:


```javascript
let current := this;
arcCustomLayout({
        uniqueId: "layout-buttons " + nr,
        embedded: true,
        direction: "horizontal",
        alignX: "right",
        alignY: "center",
        width: "100%",
        height: "auto",
        gap: "5px",
        backgroundColor: "",
        paddingY: "0px",
        paddingX: "0px",
        styles: "",
        scrollSettings: {
            scrollY: false,
            scrollX: false
        },
        blocks: [{
                width: "auto",
                height: "auto",
                lineHeight: "",
                alignX: "left",
                color: "",
                styles: "",
                value: arcCustomButton({
                        uniqueId: "Button-paperclip " + nr,
                        title: "",
                        width: "25px",
                        height: "25px",
                        alignY: "",
                        alignX: "",
                        paddingX: "",
                        paddingY: "",
                        gap: "5px",
                        icon: arcCustomIcon({
                                name: "paperclip-fill",
                                color: text(record(Typ_Termin,number(current.Typ)).colorDark),
                                containerSize: "25px",
                                borderSize: "",
                                borderColor: "",
                                borderRadius: "",
                                iconSize: "20px"
                            }),
                        iconPosition: "left",
                        fontSize: "12px",
                        fontColor: "",
                        backgroundColor: "none",
                        borderColor: "none",
                        borderRadius: "5px",
                        showBadge: false,
                        actions: [{
                                type: "create",
                                tableId: "",
                                popup: true,
                                changeFieldValues: [{
                                        fieldId: "",
                                        value: ""
                                    }, {
                                        fieldId: "",
                                        value: ""
                                    }]
                            }]
                    })
            }, {
                width: "auto",
                height: "auto",
                lineHeight: "",
                alignX: "left",
                color: "",
                styles: "",
                value: arcCustomButton({
                        uniqueId: "Button-message " + nr,
                        title: "",
                        width: "25px",
                        height: "25px",
                        alignY: "",
                        alignX: "",
                        paddingX: "",
                        paddingY: "",
                        gap: "5px",
                        icon: arcCustomIcon({
                                name: "chat-circle-dots-fill",
                                color: text(record(Typ_Termin,number(current.Typ)).colorDark),
                                containerSize: "25px",
                                borderSize: "",
                                borderColor: "",
                                borderRadius: "",
                                iconSize: "20px"
                            }),
                        iconPosition: "left",
                        fontSize: "12px",
                        fontColor: "",
                        backgroundColor: "none",
                        borderColor: "none",
                        borderRadius: "5px",
                        showBadge: false,
                        actions: [{
                                type: "",
                                tableId: "",
                                popup: true,
                                changeFieldValues: [{
                                        fieldId: "",
                                        value: ""
                                    }, {
                                        fieldId: "",
                                        value: ""
                                    }]
                            }]
                    })
            }, {
                width: "auto",
                height: "",
                lineHeight: "",
                alignX: "left",
                color: "",
                styles: "",
                value: arcCustomButton({
                        uniqueId: "Button-list " + nr,
                        title: "",
                        width: "25px",
                        height: "25px",
                        alignY: "",
                        alignX: "",
                        paddingX: "",
                        paddingY: "",
                        gap: "5px",
                        icon: arcCustomIcon({
                                name: "list-checks-fill",
                                color: text(record(Typ_Termin,number(current.Typ)).colorDark),
                                containerSize: "25px",
                                borderSize: "",
                                borderColor: "",
                                borderRadius: "",
                                iconSize: "20px"
                            }),
                        iconPosition: "left",
                        fontSize: "12px",
                        fontColor: "",
                        backgroundColor: "none",
                        borderColor: "none",
                        borderRadius: "5px",
                        showBadge: false,
                        actions: [{
                                type: "",
                                tableId: "",
                                popup: true,
                                changeFieldValues: [{
                                        fieldId: "",
                                        value: ""
                                    }, {
                                        fieldId: "",
                                        value: ""
                                    }]
                            }]
                    })
            }]
    })
```

#### layout_teilnehmer

![](https://framerusercontent.com/images/uC5bZCbfPqD1bXCXINIPqdHsI.png)

*Widgets usados: customLayout + customImage*

Código:


```javascript
let current := this;
let colorDark := text(record(Typ_Termin,number(current.Typ)).colorDark);
let colorLight := text(record(Typ_Termin,number(current.Typ)).color);
arcCustomLayout({
        uniqueId: "layout-teilnehmer " + nr,
        embedded: true,
        direction: "horizontal",
        alignX: "left",
        alignY: "center",
        width: "100%",
        height: "",
        gap: "0px",
        backgroundColor: "",
        paddingY: "0px",
        paddingX: "0px",
        styles: "",
        scrollSettings: {
            scrollY: false,
            scrollX: false
        },
        blocks: let imageList := paginatedList_teilnehmer.[{
                    width: "auto",
                    height: "auto",
                    lineHeight: "",
                    alignX: "left",
                    color: "",
                    styles: "margin-right: -10px; border: 2px solid; border-radius: 50px; border-color: " +
                    colorLight +
                    ";",
                    value: arcCustomImage({
                            uniqueId: "Mitarbeier-image" + Nr,
                            title: "Logo",
                            width: "30px",
                            height: "30px",
                            backgroundSize: "cover",
                            class: "",
                            style: "",
                            radius: "50px",
                            borderColor: "",
                            link: shareURL
                        }),
                    clickAction: {
                        type: "popup",
                        recordId: Nr
                    }
                }];
        let plusBubble := [if cnt(Terminteilnehmer) > 3 then
                    {
                        width: "30px",
                        height: "30px",
                        lineHeight: "",
                        alignX: "center",
                        color: colorDark,
                        styles: "margin-left: 20px; border: 1px solid; border-radius: 50px; border-color: " +
                        colorDark +
                        "; font-size: 12px;",
                        value: "+" + if cnt(Terminteilnehmer) > 3 then
                            text(cnt(Terminteilnehmer) - 3)
                        end
                    }
                end];
        array(imageList, plusBubble)
    })
```

**Paso 2:** A continuación, ambos customLayouts se insertan en el layout de la tercera línea.

#### calendarCard_line3

![](https://framerusercontent.com/images/grCqFlAt3BK6jGFhfciridlacU.png)

*Widgets usados: customLayout*

Código:


```javascript
let current := this;
arcCustomLayout({
        uniqueId: "calenderCard Line3 " + nr,
        embedded: true,
        direction: "horizontal",
        alignX: "center",
        alignY: "center",
        width: "",
        height: "auto",
        gap: "10px",
        backgroundColor: "",
        paddingY: "",
        paddingX: "",
        styles: "",
        scrollSettings: {
            scrollY: false,
            scrollX: false
        },
        blocks: [{
                width: "100%",
                height: "auto",
                lineHeight: "",
                alignX: "left",
                color: "",
                styles: "",
                value: layout_teilnehmer
            }, {
                width: "100%",
                height: "auto",
                lineHeight: "",
                alignX: "right",
                color: "",
                value: layout_buttons
            }]
    })
```

#### Ensamblar el diseño de la card

**Finalmente **se pueden ensamblar las líneas en el último layout de la calendarCard. Para que la card se pueda ver completa en citas más cortas, recordad poner scrollY: true en scrollSettings.

![](https://framerusercontent.com/images/RgWIpNKTTKCXdAjbZ10gAJuV4iI.png)

*Widgets usados: customLayout*

Código:


```javascript
let current := this;
arcCustomLayout({
        uniqueId: "calenderCard " + nr,
        embedded: true,
        direction: "vertical",
        alignX: "center",
        alignY: "top",
        width: "100%",
        height: "100%",
        gap: "10px",
        backgroundColor: record(Typ_Termin,number(current.Typ)).color,
        paddingY: "8px",
        paddingX: "8px",
        styles: "border-radius: 14px;",
        scrollSettings: {
            scrollY: true,
            scrollX: false
        },
        blocks: [{
                width: "100%",
                height: "auto",
                lineHeight: "",
                alignX: "center",
                color: "",
                styles: "",
                value: calendarCard_line1
            }, {
                width: "100%",
                height: "100%",
                lineHeight: "",
                alignX: "center",
                color: "",
                value: calendarCard_line2
            }, {
                width: "100%",
                height: "auto",
                lineHeight: "",
                alignX: "center",
                color: "",
                value: calendarCard_line3
            }]
    })
```

***Consejo: **Al externalizar los distintos elementos, podéis crear otros diseños y otras vistas mucho más rápido. Por ejemplo, intercambiando las líneas:*

![](https://framerusercontent.com/images/lc1yOCv4jLEwkW4vMezjGhX3k.png)

Código:


```javascript
let current := this;
arcCustomLayout({
        uniqueId: "calenderCard version 2" + nr,
        embedded: true,
        direction: "vertical",
        alignX: "center",
        alignY: "top",
        width: "100%",
        height: "100%",
        gap: "10px",
        backgroundColor: record(Typ_Termin,number(current.Typ)).color,
        paddingY: "8px",
        paddingX: "8px",
        styles: "border-radius: 14px;",
        scrollSettings: {
            scrollY: true,
            scrollX: false
        },
        blocks: [{
                width: "100%",
                height: "auto",
                lineHeight: "",
                alignX: "center",
                color: "",
                styles: "",
                value: calendarCard_line2
            }, {
                width: "100%",
                height: "100%",
                lineHeight: "",
                alignX: "center",
                color: "",
                value: calendarCard_line1
            }, {
                width: "100%",
                height: "auto",
                lineHeight: "",
                alignX: "center",
                color: "",
                value: calendarCard_line3
            }]
    })
```

## Finalizar el diseño

La card terminada se puede insertar **finalmente** en el widget customCalendarWeek. El layout de nuestra calendarCard se llama en timeEntries dentro del parámetro **customLayout**.


```javascript
...		timeEntries: (select Termine where forCalendarWeek = true).[{
                subtitle: "",
                title: "",
                value: "",
                customLayout: calendarCard,
                                                                ...
```

***¡Importante!*** Si definís el color de fondo y un borderRadius en el layout de la card, recordad poner backgroundColor en "transparent" y padding en "0px" en el parámetro styles de timeEntries.


```javascript
...		styles: {
            backgroundColor: "transparent",
            padding: "0px"
                },
                                                                ...
```

### Código completo de la aplicación de customCalendarWeek:


```javascript
let current := this;
arcCustomCalendarWeek({
        uniqueId: "customCalendar" + Nr,
        embedded: false,
        height: "800px",
        weekdaySettings: {
            week: week(today()),
            year: year(today())
        },
        weekStart: 1,
        timeZoneBalance: -1,
        timeSettings: {
            timeStart: time(6, 30),
            duration: time(15, 30)
        },
        currentTime: "#f95757",
        dayHighlights: [{
                date: date(2024, 10, 31),
                color: ""
            }, {
                weekday: 6,
                color: "#f9f9f9"
            }, {
                weekday: 7,
                color: "#f9f9f9"
            }],
        lang: clientLang(),
        timeSlotWidth: "372px",
        timeSlotHeight: "120px",
        styles: {
            backgroundColor: "#cccccc11"
        },
        timeEntries: (select Termine where forCalendarWeek = true).[{
                subtitle: "",
                title: "",
                value: "",
                customLayout: calendarCard,
                dateFrom: 'Datum von',
                dateTo: 'Datum bis',
                timeFrom: Von,
                timeTo: Bis,
                styles: {
                    backgroundColor: "transparent",
                    padding: "0px"
                },
                dragAction: {
                    recordId: nr,
                    dateFrom: fieldId(nr, "Datum von"),
                    timeFrom: fieldId(nr, "Von"),
                    dateTo: fieldId(nr, "Datum bis"),
                    timeTo: fieldId(nr, "Bis")
                }
            }]
    })
```

** **
