mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-08 11:19:30 -05:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a37ad0cd66 | |||
| 175775c96e | |||
| 05be68b714 |
+9
-2
@@ -75,7 +75,10 @@ export const ProjectSettings = ({
|
||||
organizationId,
|
||||
data: {
|
||||
...data,
|
||||
styling: fullStyling,
|
||||
styling: {
|
||||
...fullStyling,
|
||||
isPageFontInheritedByDefault: true,
|
||||
},
|
||||
config: { channel, industry },
|
||||
teamIds: data.teamIds,
|
||||
},
|
||||
@@ -112,7 +115,11 @@ export const ProjectSettings = ({
|
||||
const form = useForm<TProjectUpdateInput>({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
styling: { allowStyleOverwrite: true, brandColor: { light: defaultBrandColor } },
|
||||
styling: {
|
||||
allowStyleOverwrite: true,
|
||||
isPageFontInheritedByDefault: true,
|
||||
brandColor: { light: defaultBrandColor },
|
||||
},
|
||||
teamIds: [],
|
||||
},
|
||||
resolver: zodResolver(ZProjectUpdateInput),
|
||||
|
||||
@@ -1711,6 +1711,8 @@ checksums:
|
||||
environments/surveys/edit/upper_label: 1fa48bce3fade6ffc1a52d9fdddf9e17
|
||||
environments/surveys/edit/url_filters: e524879d2eb74463d7fd06a7e0f53421
|
||||
environments/surveys/edit/url_not_supported: af8a753467c617b596aadef1aaaed664
|
||||
environments/surveys/edit/use_page_font: 327c0c42a128a99af13510c24c813cf8
|
||||
environments/surveys/edit/use_page_font_description: ffb511ce099a5ca25832228a85e2b4d8
|
||||
environments/surveys/edit/validate_id_duplicate: f88ec35a9bd4921fb096817b9263b59a
|
||||
environments/surveys/edit/validate_id_empty: 3ee25d429ed5ca9e047f9aee95496323
|
||||
environments/surveys/edit/validate_id_invalid_chars: 50239938a408c04b02d77b8cd096d767
|
||||
@@ -2224,6 +2226,8 @@ checksums:
|
||||
environments/workspace/look/suggested_colors_applied_please_save: a440b8e29a327822a94d9bbf8c52e2ed
|
||||
environments/workspace/look/theme: 21fe00b7a518089576fb83c08631107a
|
||||
environments/workspace/look/theme_settings_description: 9fc45322818c3774ab4a44ea14d7836e
|
||||
environments/workspace/look/use_page_font_for_new_surveys: 327c0c42a128a99af13510c24c813cf8
|
||||
environments/workspace/look/use_page_font_for_new_surveys_description: 010ae8817cc6c9b2aa17ba804e6ff393
|
||||
environments/workspace/tags/add: 87c4a663507f2bcbbf79934af8164e13
|
||||
environments/workspace/tags/add_tag: 2cfa04ceea966149f2b5d40d9c131141
|
||||
environments/workspace/tags/count: 9c5848662eb8024ddf360f7e4001a968
|
||||
|
||||
@@ -93,6 +93,7 @@ const _colors = getSuggestedColors(DEFAULT_BRAND_COLOR);
|
||||
*/
|
||||
export const STYLE_DEFAULTS: TProjectStyling = {
|
||||
allowStyleOverwrite: true,
|
||||
isPageFontInheritedByDefault: false,
|
||||
brandColor: { light: _colors["brandColor.light"] },
|
||||
questionColor: { light: _colors["questionColor.light"] },
|
||||
inputColor: { light: _colors["inputColor.light"] },
|
||||
|
||||
@@ -7,6 +7,7 @@ describe("Styling Utilities", () => {
|
||||
const project: TJsEnvironmentStateProject = {
|
||||
styling: {
|
||||
allowStyleOverwrite: false,
|
||||
isPageFontInheritedByDefault: false,
|
||||
brandColor: "#000000",
|
||||
highlightBorderColor: "#000000",
|
||||
},
|
||||
@@ -20,13 +21,17 @@ describe("Styling Utilities", () => {
|
||||
},
|
||||
} as unknown as TJsEnvironmentStateSurvey;
|
||||
|
||||
expect(getStyling(project, survey)).toBe(project.styling);
|
||||
expect(getStyling(project, survey)).toEqual({
|
||||
...project.styling,
|
||||
isPageFontInherited: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("returns project styling when project allows style overwrite but survey does not overwrite", () => {
|
||||
const project: TJsEnvironmentStateProject = {
|
||||
styling: {
|
||||
allowStyleOverwrite: true,
|
||||
isPageFontInheritedByDefault: false,
|
||||
brandColor: "#000000",
|
||||
highlightBorderColor: "#000000",
|
||||
},
|
||||
@@ -40,13 +45,17 @@ describe("Styling Utilities", () => {
|
||||
},
|
||||
} as unknown as TJsEnvironmentStateSurvey;
|
||||
|
||||
expect(getStyling(project, survey)).toBe(project.styling);
|
||||
expect(getStyling(project, survey)).toEqual({
|
||||
...project.styling,
|
||||
isPageFontInherited: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("returns survey styling when both project and survey allow style overwrite", () => {
|
||||
const project: TJsEnvironmentStateProject = {
|
||||
styling: {
|
||||
allowStyleOverwrite: true,
|
||||
isPageFontInheritedByDefault: false,
|
||||
brandColor: "#000000",
|
||||
highlightBorderColor: "#000000",
|
||||
},
|
||||
@@ -60,13 +69,17 @@ describe("Styling Utilities", () => {
|
||||
},
|
||||
} as unknown as TJsEnvironmentStateSurvey;
|
||||
|
||||
expect(getStyling(project, survey)).toBe(survey.styling);
|
||||
expect(getStyling(project, survey)).toEqual({
|
||||
...survey.styling,
|
||||
isPageFontInherited: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("returns project styling when project allows style overwrite but survey styling is undefined", () => {
|
||||
const project: TJsEnvironmentStateProject = {
|
||||
styling: {
|
||||
allowStyleOverwrite: true,
|
||||
isPageFontInheritedByDefault: false,
|
||||
brandColor: "#000000",
|
||||
highlightBorderColor: "#000000",
|
||||
},
|
||||
@@ -76,13 +89,17 @@ describe("Styling Utilities", () => {
|
||||
styling: undefined,
|
||||
} as unknown as TJsEnvironmentStateSurvey;
|
||||
|
||||
expect(getStyling(project, survey)).toBe(project.styling);
|
||||
expect(getStyling(project, survey)).toEqual({
|
||||
...project.styling,
|
||||
isPageFontInherited: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("returns project styling when project allows style overwrite but survey overwriteThemeStyling is undefined", () => {
|
||||
const project: TJsEnvironmentStateProject = {
|
||||
styling: {
|
||||
allowStyleOverwrite: true,
|
||||
isPageFontInheritedByDefault: false,
|
||||
brandColor: "#000000",
|
||||
highlightBorderColor: "#000000",
|
||||
},
|
||||
@@ -95,6 +112,53 @@ describe("Styling Utilities", () => {
|
||||
},
|
||||
} as unknown as TJsEnvironmentStateSurvey;
|
||||
|
||||
expect(getStyling(project, survey)).toBe(project.styling);
|
||||
expect(getStyling(project, survey)).toEqual({
|
||||
...project.styling,
|
||||
isPageFontInherited: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("keeps survey font preferences even when theme overwrite is disabled", () => {
|
||||
const project: TJsEnvironmentStateProject = {
|
||||
styling: {
|
||||
allowStyleOverwrite: true,
|
||||
brandColor: "#000000",
|
||||
},
|
||||
} as unknown as TJsEnvironmentStateProject;
|
||||
|
||||
const survey: TJsEnvironmentStateSurvey = {
|
||||
styling: {
|
||||
overwriteThemeStyling: false,
|
||||
isPageFontInherited: true,
|
||||
fontFamily: "Inter, Noto Sans Arabic, sans-serif",
|
||||
},
|
||||
} as unknown as TJsEnvironmentStateSurvey;
|
||||
|
||||
expect(getStyling(project, survey)).toEqual({
|
||||
...project.styling,
|
||||
isPageFontInherited: true,
|
||||
fontFamily: "Inter, Noto Sans Arabic, sans-serif",
|
||||
});
|
||||
});
|
||||
|
||||
test("inherits workspace default page-font setting when survey does not specify it", () => {
|
||||
const project: TJsEnvironmentStateProject = {
|
||||
styling: {
|
||||
allowStyleOverwrite: true,
|
||||
isPageFontInheritedByDefault: true,
|
||||
brandColor: "#000000",
|
||||
},
|
||||
} as unknown as TJsEnvironmentStateProject;
|
||||
|
||||
const survey: TJsEnvironmentStateSurvey = {
|
||||
styling: {
|
||||
overwriteThemeStyling: false,
|
||||
},
|
||||
} as unknown as TJsEnvironmentStateSurvey;
|
||||
|
||||
expect(getStyling(project, survey)).toEqual({
|
||||
...project.styling,
|
||||
isPageFontInherited: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,20 +1,36 @@
|
||||
import { TJsEnvironmentStateProject, TJsEnvironmentStateSurvey } from "@formbricks/types/js";
|
||||
|
||||
export const getStyling = (project: TJsEnvironmentStateProject, survey: TJsEnvironmentStateSurvey) => {
|
||||
const resolvedIsPageFontInherited =
|
||||
survey.styling?.isPageFontInherited ?? project.styling.isPageFontInheritedByDefault ?? false;
|
||||
const getFontOverrides = () => ({
|
||||
isPageFontInherited: resolvedIsPageFontInherited,
|
||||
...(survey.styling?.fontFamily !== undefined ? { fontFamily: survey.styling.fontFamily } : {}),
|
||||
});
|
||||
|
||||
// allow style overwrite is disabled from the project
|
||||
if (!project.styling.allowStyleOverwrite) {
|
||||
return project.styling;
|
||||
return {
|
||||
...project.styling,
|
||||
...getFontOverrides(),
|
||||
};
|
||||
}
|
||||
|
||||
// allow style overwrite is enabled from the project
|
||||
if (project.styling.allowStyleOverwrite) {
|
||||
// survey style overwrite is disabled
|
||||
if (!survey.styling?.overwriteThemeStyling) {
|
||||
return project.styling;
|
||||
return {
|
||||
...project.styling,
|
||||
...getFontOverrides(),
|
||||
};
|
||||
}
|
||||
|
||||
// survey style overwrite is enabled
|
||||
return survey.styling;
|
||||
return {
|
||||
...survey.styling,
|
||||
isPageFontInherited: resolvedIsPageFontInherited,
|
||||
};
|
||||
}
|
||||
|
||||
return project.styling;
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Oberes Label",
|
||||
"url_filters": "URL-Filter",
|
||||
"url_not_supported": "URL nicht unterstützt",
|
||||
"use_page_font": "Seitenschriftart verwenden",
|
||||
"use_page_font_description": "Verwende die Schriftart der Host-App oder Website für diese Umfrage.",
|
||||
"validate_id_duplicate": "{type}-ID existiert bereits in Fragen, versteckten Feldern oder Variablen.",
|
||||
"validate_id_empty": "Bitte gib eine {type}-ID ein.",
|
||||
"validate_id_invalid_chars": "{type}-ID ist nicht erlaubt. Bitte verwende nur alphanumerische Zeichen, Bindestriche oder Unterstriche.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Farben vorschlagen",
|
||||
"suggested_colors_applied_please_save": "Vorgeschlagene Farben erfolgreich generiert. Drücke “Speichern”, um die Änderungen zu übernehmen.",
|
||||
"theme": "Theme",
|
||||
"theme_settings_description": "Erstelle ein Style-Theme für alle Umfragen. Du kannst für jede Umfrage individuelles Styling aktivieren."
|
||||
"theme_settings_description": "Erstelle ein Style-Theme für alle Umfragen. Du kannst für jede Umfrage individuelles Styling aktivieren.",
|
||||
"use_page_font_for_new_surveys": "Seitenschriftart verwenden",
|
||||
"use_page_font_for_new_surveys_description": "Wende die Schriftart der Host-App oder Website auf alle Umfragen in diesem Workspace an."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Hinzufügen",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Upper Label",
|
||||
"url_filters": "URL Filters",
|
||||
"url_not_supported": "URL not supported",
|
||||
"use_page_font": "Use page font",
|
||||
"use_page_font_description": "Use the host app or website font for this survey.",
|
||||
"validate_id_duplicate": "{type} ID already exists in questions, hidden fields, or variables.",
|
||||
"validate_id_empty": "Please enter a {type} ID.",
|
||||
"validate_id_invalid_chars": "{type} ID is not allowed. Please use only alphanumeric characters, hyphens, or underscores.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Suggest colors",
|
||||
"suggested_colors_applied_please_save": "Suggested colors generated successfully. Press “Save” to persist the changes.",
|
||||
"theme": "Theme",
|
||||
"theme_settings_description": "Create a style theme for all surveys. You can enable custom styling for each survey."
|
||||
"theme_settings_description": "Create a style theme for all surveys. You can enable custom styling for each survey.",
|
||||
"use_page_font_for_new_surveys": "Use page font",
|
||||
"use_page_font_for_new_surveys_description": "Apply the host app or website font across surveys in this workspace."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Add",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Etiqueta superior",
|
||||
"url_filters": "Filtros de URL",
|
||||
"url_not_supported": "URL no compatible",
|
||||
"use_page_font": "Usar fuente de la página",
|
||||
"use_page_font_description": "Utiliza la fuente de la aplicación o sitio web anfitrión para esta encuesta.",
|
||||
"validate_id_duplicate": "El ID de {type} ya existe en preguntas, campos ocultos o variables.",
|
||||
"validate_id_empty": "Por favor, introduce un ID de {type}.",
|
||||
"validate_id_invalid_chars": "El ID de {type} no está permitido. Por favor, utiliza solo caracteres alfanuméricos, guiones o guiones bajos.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Sugerir colores",
|
||||
"suggested_colors_applied_please_save": "Colores sugeridos generados correctamente. Pulsa “Guardar” para conservar los cambios.",
|
||||
"theme": "Tema",
|
||||
"theme_settings_description": "Crea un tema de estilo para todas las encuestas. Puedes activar el estilo personalizado para cada encuesta."
|
||||
"theme_settings_description": "Crea un tema de estilo para todas las encuestas. Puedes activar el estilo personalizado para cada encuesta.",
|
||||
"use_page_font_for_new_surveys": "Usar fuente de la página",
|
||||
"use_page_font_for_new_surveys_description": "Aplica la fuente de la aplicación o sitio web anfitrión en todas las encuestas de este espacio de trabajo."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Añadir",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Étiquette supérieure",
|
||||
"url_filters": "Filtres d'URL",
|
||||
"url_not_supported": "URL non supportée",
|
||||
"use_page_font": "Utiliser la police de la page",
|
||||
"use_page_font_description": "Utiliser la police de l'application hôte ou du site web pour ce sondage.",
|
||||
"validate_id_duplicate": "L'ID {type} existe déjà dans les questions, champs masqués ou variables.",
|
||||
"validate_id_empty": "Veuillez saisir un ID {type}.",
|
||||
"validate_id_invalid_chars": "L'ID {type} n'est pas autorisé. Veuillez utiliser uniquement des caractères alphanumériques, des traits d'union ou des underscores.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Suggérer des couleurs",
|
||||
"suggested_colors_applied_please_save": "Couleurs suggérées générées avec succès. Appuyez sur “Enregistrer” pour conserver les modifications.",
|
||||
"theme": "Thème",
|
||||
"theme_settings_description": "Créez un thème de style pour toutes les enquêtes. Vous pouvez activer un style personnalisé pour chaque enquête."
|
||||
"theme_settings_description": "Créez un thème de style pour toutes les enquêtes. Vous pouvez activer un style personnalisé pour chaque enquête.",
|
||||
"use_page_font_for_new_surveys": "Utiliser la police de la page",
|
||||
"use_page_font_for_new_surveys_description": "Appliquer la police de l'application hôte ou du site web à tous les sondages de cet espace de travail."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Ajouter",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Felső címke",
|
||||
"url_filters": "URL szűrők",
|
||||
"url_not_supported": "Az URL nem támogatott",
|
||||
"use_page_font": "Oldal betűtípusának használata",
|
||||
"use_page_font_description": "A gazda alkalmazás vagy webhely betűtípusának használata ehhez a felméréshez.",
|
||||
"validate_id_duplicate": "A(z) {type} azonosító már létezik a kérdések, rejtett mezők vagy változók között.",
|
||||
"validate_id_empty": "Kérjük, adjon meg egy {type} azonosítót.",
|
||||
"validate_id_invalid_chars": "A(z) {type} azonosító nem engedélyezett. Kérjük, csak alfanumerikus karaktereket, kötőjeleket vagy aláhúzásjeleket használjon.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Színek ajánlása",
|
||||
"suggested_colors_applied_please_save": "Az ajánlott színek sikeresen előállítva. Nyomja meg a „Mentés” gombot a változtatások mentéséhez.",
|
||||
"theme": "Téma",
|
||||
"theme_settings_description": "Stílustéma létrehozása az összes kérdőívhez. Egyéni stílust engedélyezhet minden egyes kérdőívhez."
|
||||
"theme_settings_description": "Stílustéma létrehozása az összes kérdőívhez. Egyéni stílust engedélyezhet minden egyes kérdőívhez.",
|
||||
"use_page_font_for_new_surveys": "Oldal betűtípusának használata",
|
||||
"use_page_font_for_new_surveys_description": "A gazda alkalmazás vagy webhely betűtípusának alkalmazása a munkaterület felmérésein."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Hozzáadás",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "上限ラベル",
|
||||
"url_filters": "URLフィルター",
|
||||
"url_not_supported": "URLはサポートされていません",
|
||||
"use_page_font": "ページフォントを使用",
|
||||
"use_page_font_description": "このアンケートにホストアプリまたはウェブサイトのフォントを使用します。",
|
||||
"validate_id_duplicate": "{type} IDは質問、非表示フィールド、または変数に既に存在します。",
|
||||
"validate_id_empty": "{type} IDを入力してください。",
|
||||
"validate_id_invalid_chars": "{type} IDは使用できません。英数字、ハイフン、アンダースコアのみを使用してください。",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "カラーを提案",
|
||||
"suggested_colors_applied_please_save": "推奨カラーが正常に生成されました。変更を保存するには“保存”を押してください。",
|
||||
"theme": "テーマ",
|
||||
"theme_settings_description": "すべてのアンケート用のスタイルテーマを作成します。各アンケートでカスタムスタイルを有効にできます。"
|
||||
"theme_settings_description": "すべてのアンケート用のスタイルテーマを作成します。各アンケートでカスタムスタイルを有効にできます。",
|
||||
"use_page_font_for_new_surveys": "ページフォントを使用",
|
||||
"use_page_font_for_new_surveys_description": "このワークスペース内のアンケート全体にホストアプリまたはウェブサイトのフォントを適用します。"
|
||||
},
|
||||
"tags": {
|
||||
"add": "追加",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Bovenste etiket",
|
||||
"url_filters": "URL-filters",
|
||||
"url_not_supported": "URL niet ondersteund",
|
||||
"use_page_font": "Gebruik paginafont",
|
||||
"use_page_font_description": "Gebruik het lettertype van de host-app of website voor deze enquête.",
|
||||
"validate_id_duplicate": "{type}-ID bestaat al in vragen, verborgen velden of variabelen.",
|
||||
"validate_id_empty": "Voer een {type}-ID in.",
|
||||
"validate_id_invalid_chars": "{type}-ID is niet toegestaan. Gebruik alleen alfanumerieke tekens, koppeltekens of underscores.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Kleuren voorstellen",
|
||||
"suggested_colors_applied_please_save": "Voorgestelde kleuren succesvol gegenereerd. Druk op “Opslaan” om de wijzigingen te behouden.",
|
||||
"theme": "Thema",
|
||||
"theme_settings_description": "Maak een stijlthema voor alle enquêtes. Je kunt aangepaste styling inschakelen voor elke enquête."
|
||||
"theme_settings_description": "Maak een stijlthema voor alle enquêtes. Je kunt aangepaste styling inschakelen voor elke enquête.",
|
||||
"use_page_font_for_new_surveys": "Gebruik paginafont",
|
||||
"use_page_font_for_new_surveys_description": "Pas het lettertype van de host-app of website toe op alle enquêtes in deze workspace."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Toevoegen",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Etiqueta Superior",
|
||||
"url_filters": "Filtros de URL",
|
||||
"url_not_supported": "URL não suportada",
|
||||
"use_page_font": "Usar fonte da página",
|
||||
"use_page_font_description": "Use a fonte do aplicativo ou site hospedeiro para esta pesquisa.",
|
||||
"validate_id_duplicate": "O ID de {type} já existe em perguntas, campos ocultos ou variáveis.",
|
||||
"validate_id_empty": "Por favor, insira um ID de {type}.",
|
||||
"validate_id_invalid_chars": "O ID de {type} não é permitido. Por favor, use apenas caracteres alfanuméricos, hífens ou underscores.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Sugerir cores",
|
||||
"suggested_colors_applied_please_save": "Cores sugeridas geradas com sucesso. Pressione “Salvar” para persistir as alterações.",
|
||||
"theme": "Tema",
|
||||
"theme_settings_description": "Crie um tema de estilo para todas as pesquisas. Você pode ativar estilo personalizado para cada pesquisa."
|
||||
"theme_settings_description": "Crie um tema de estilo para todas as pesquisas. Você pode ativar estilo personalizado para cada pesquisa.",
|
||||
"use_page_font_for_new_surveys": "Usar fonte da página",
|
||||
"use_page_font_for_new_surveys_description": "Aplicar a fonte do aplicativo ou site hospedeiro em todas as pesquisas deste espaço de trabalho."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Adicionar",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Etiqueta Superior",
|
||||
"url_filters": "Filtros de URL",
|
||||
"url_not_supported": "URL não suportado",
|
||||
"use_page_font": "Usar tipo de letra da página",
|
||||
"use_page_font_description": "Utilizar o tipo de letra da aplicação ou website anfitrião para este inquérito.",
|
||||
"validate_id_duplicate": "O ID {type} já existe em perguntas, campos ocultos ou variáveis.",
|
||||
"validate_id_empty": "Por favor, introduza um ID {type}.",
|
||||
"validate_id_invalid_chars": "O ID {type} não é permitido. Por favor, utilize apenas caracteres alfanuméricos, hífenes ou underscores.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Sugerir cores",
|
||||
"suggested_colors_applied_please_save": "Cores sugeridas geradas com sucesso. Prima “Guardar” para persistir as alterações.",
|
||||
"theme": "Tema",
|
||||
"theme_settings_description": "Crie um tema de estilo para todos os inquéritos. Pode ativar estilos personalizados para cada inquérito."
|
||||
"theme_settings_description": "Crie um tema de estilo para todos os inquéritos. Pode ativar estilos personalizados para cada inquérito.",
|
||||
"use_page_font_for_new_surveys": "Usar tipo de letra da página",
|
||||
"use_page_font_for_new_surveys_description": "Aplicar o tipo de letra da aplicação ou website anfitrião em todos os inquéritos desta área de trabalho."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Adicionar",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Etichetă superioară",
|
||||
"url_filters": "Filtre URL",
|
||||
"url_not_supported": "URL nesuportat",
|
||||
"use_page_font": "Folosește fontul paginii",
|
||||
"use_page_font_description": "Folosește fontul aplicației sau site-ului gazdă pentru acest chestionar.",
|
||||
"validate_id_duplicate": "ID-ul {type} există deja în întrebări, câmpuri ascunse sau variabile.",
|
||||
"validate_id_empty": "Te rugăm să introduci un ID {type}.",
|
||||
"validate_id_invalid_chars": "ID-ul {type} nu este permis. Te rugăm să folosești doar caractere alfanumerice, cratimă sau liniuță de subliniere.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Sugerează culori",
|
||||
"suggested_colors_applied_please_save": "Culorile sugerate au fost generate cu succes. Apăsați „Save” pentru a salva modificările.",
|
||||
"theme": "Temă",
|
||||
"theme_settings_description": "Creează o temă de stil pentru toate sondajele. Poți activa stilizare personalizată pentru fiecare sondaj."
|
||||
"theme_settings_description": "Creează o temă de stil pentru toate sondajele. Poți activa stilizare personalizată pentru fiecare sondaj.",
|
||||
"use_page_font_for_new_surveys": "Folosește fontul paginii",
|
||||
"use_page_font_for_new_surveys_description": "Aplică fontul aplicației sau site-ului gazdă pentru chestionarele din acest spațiu de lucru."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Adaugă",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Верхняя метка",
|
||||
"url_filters": "Фильтры URL",
|
||||
"url_not_supported": "URL не поддерживается",
|
||||
"use_page_font": "Использовать шрифт страницы",
|
||||
"use_page_font_description": "Использовать шрифт приложения или веб-сайта для этого опроса.",
|
||||
"validate_id_duplicate": "ID {type} уже существует в вопросах, скрытых полях или переменных.",
|
||||
"validate_id_empty": "Пожалуйста, введите ID {type}.",
|
||||
"validate_id_invalid_chars": "ID {type} недопустим. Пожалуйста, используйте только буквенно-цифровые символы, дефисы или подчеркивания.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Предложить цвета",
|
||||
"suggested_colors_applied_please_save": "Рекомендованные цвета успешно сгенерированы. Нажмите «Сохранить», чтобы применить изменения.",
|
||||
"theme": "Тема",
|
||||
"theme_settings_description": "Создайте стиль для всех опросов. Вы можете включить индивидуальное оформление для каждого опроса."
|
||||
"theme_settings_description": "Создайте стиль для всех опросов. Вы можете включить индивидуальное оформление для каждого опроса.",
|
||||
"use_page_font_for_new_surveys": "Использовать шрифт страницы",
|
||||
"use_page_font_for_new_surveys_description": "Применять шрифт приложения или веб-сайта ко всем опросам в этом рабочем пространстве."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Добавить",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "Övre etikett",
|
||||
"url_filters": "URL-filter",
|
||||
"url_not_supported": "URL stöds inte",
|
||||
"use_page_font": "Använd sidans typsnitt",
|
||||
"use_page_font_description": "Använd värdappens eller webbplatsens typsnitt för den här enkäten.",
|
||||
"validate_id_duplicate": "{type}-ID finns redan i frågor, dolda fält eller variabler.",
|
||||
"validate_id_empty": "Vänligen ange ett {type}-ID.",
|
||||
"validate_id_invalid_chars": "{type}-ID är inte tillåtet. Använd endast alfanumeriska tecken, bindestreck eller understreck.",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "Föreslå färger",
|
||||
"suggested_colors_applied_please_save": "Föreslagna färger har genererats. Tryck på ”Spara” för att spara ändringarna.",
|
||||
"theme": "Tema",
|
||||
"theme_settings_description": "Skapa ett stilmall för alla undersökningar. Du kan aktivera anpassad stil för varje undersökning."
|
||||
"theme_settings_description": "Skapa ett stilmall för alla undersökningar. Du kan aktivera anpassad stil för varje undersökning.",
|
||||
"use_page_font_for_new_surveys": "Använd sidans typsnitt",
|
||||
"use_page_font_for_new_surveys_description": "Tillämpa värdappens eller webbplatsens typsnitt för alla enkäter i den här arbetsytan."
|
||||
},
|
||||
"tags": {
|
||||
"add": "Lägg till",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "上限标签",
|
||||
"url_filters": "URL 过滤器",
|
||||
"url_not_supported": "URL 不支持",
|
||||
"use_page_font": "使用页面字体",
|
||||
"use_page_font_description": "为此调查问卷使用宿主应用或网站的字体。",
|
||||
"validate_id_duplicate": "{type} ID 已存在于问题、隐藏字段或变量中。",
|
||||
"validate_id_empty": "请输入 {type} ID。",
|
||||
"validate_id_invalid_chars": "{type} ID 不允许使用。请仅使用字母数字字符、连字符或下划线。",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "推荐颜色",
|
||||
"suggested_colors_applied_please_save": "已成功生成建议颜色。请点击“保存”以保留更改。",
|
||||
"theme": "主题",
|
||||
"theme_settings_description": "为所有问卷创建一个样式主题。你可以为每个问卷启用自定义样式。"
|
||||
"theme_settings_description": "为所有问卷创建一个样式主题。你可以为每个问卷启用自定义样式。",
|
||||
"use_page_font_for_new_surveys": "使用页面字体",
|
||||
"use_page_font_for_new_surveys_description": "在此工作区的所有调查问卷中应用宿主应用或网站的字体。"
|
||||
},
|
||||
"tags": {
|
||||
"add": "添加",
|
||||
|
||||
@@ -1784,6 +1784,8 @@
|
||||
"upper_label": "上標籤",
|
||||
"url_filters": "網址篩選器",
|
||||
"url_not_supported": "不支援網址",
|
||||
"use_page_font": "使用頁面字型",
|
||||
"use_page_font_description": "為此問卷使用主應用程式或網站字型。",
|
||||
"validate_id_duplicate": "{type} ID 已存在於問題、隱藏欄位或變數中。",
|
||||
"validate_id_empty": "請輸入 {type} ID。",
|
||||
"validate_id_invalid_chars": "不允許使用此 {type} ID。請僅使用英數字元、連字號或底線。",
|
||||
@@ -2340,7 +2342,9 @@
|
||||
"suggest_colors": "建議顏色",
|
||||
"suggested_colors_applied_please_save": "已成功產生建議色彩。請按「Save」以儲存變更。",
|
||||
"theme": "主題",
|
||||
"theme_settings_description": "為所有調查建立樣式主題。您可以為每個調查啟用自訂樣式。"
|
||||
"theme_settings_description": "為所有調查建立樣式主題。您可以為每個調查啟用自訂樣式。",
|
||||
"use_page_font_for_new_surveys": "使用頁面字型",
|
||||
"use_page_font_for_new_surveys_description": "在此工作區的所有問卷中套用主應用程式或網站字型。"
|
||||
},
|
||||
"tags": {
|
||||
"add": "新增",
|
||||
|
||||
+5
-8
@@ -98,14 +98,11 @@ describe("Users Lib", () => {
|
||||
|
||||
test("returns conflict error if user with email already exists", async () => {
|
||||
(prisma.user.create as any).mockRejectedValueOnce(
|
||||
new Prisma.PrismaClientKnownRequestError(
|
||||
"Unique constraint failed on the fields: (`email`)",
|
||||
{
|
||||
code: PrismaErrorType.UniqueConstraintViolation,
|
||||
clientVersion: "1.0.0",
|
||||
meta: { target: ["email"] },
|
||||
}
|
||||
)
|
||||
new Prisma.PrismaClientKnownRequestError("Unique constraint failed on the fields: (`email`)", {
|
||||
code: PrismaErrorType.UniqueConstraintViolation,
|
||||
clientVersion: "1.0.0",
|
||||
meta: { target: ["email"] },
|
||||
})
|
||||
);
|
||||
const result = await createUser(
|
||||
{ name: "Duplicate", email: "test@example.com", role: "member" },
|
||||
|
||||
@@ -163,7 +163,7 @@ export const ThemeStyling = ({
|
||||
<div className="relative flex w-1/2 flex-col pr-6">
|
||||
<div className="flex flex-1 flex-col gap-4">
|
||||
<div className="flex flex-col gap-4 rounded-lg bg-slate-50 p-4">
|
||||
<div className="flex items-center gap-6">
|
||||
<div className="flex flex-col gap-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="allowStyleOverwrite"
|
||||
@@ -229,6 +229,11 @@ export const ThemeStyling = ({
|
||||
setOpen={setFormStylingOpen}
|
||||
isSettingsPage
|
||||
form={form as UseFormReturn<TProjectStyling | TSurveyStyling>}
|
||||
usePageFontFieldName="isPageFontInheritedByDefault"
|
||||
usePageFontLabel={t("environments.workspace.look.use_page_font_for_new_surveys")}
|
||||
usePageFontDescription={t(
|
||||
"environments.workspace.look.use_page_font_for_new_surveys_description"
|
||||
)}
|
||||
/>
|
||||
|
||||
<CardStylingSettings
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { TProjectStyling } from "@formbricks/types/project";
|
||||
import { TSurveyStyling } from "@formbricks/types/surveys/types";
|
||||
import { cn } from "@/lib/cn";
|
||||
import { FormControl, FormDescription, FormField, FormItem, FormLabel } from "@/modules/ui/components/form";
|
||||
import {
|
||||
ColorField,
|
||||
DimensionInput,
|
||||
@@ -16,6 +17,7 @@ import {
|
||||
StylingSection,
|
||||
TextField,
|
||||
} from "@/modules/ui/components/styling-fields";
|
||||
import { Switch } from "@/modules/ui/components/switch";
|
||||
|
||||
type FormStylingSettingsProps = {
|
||||
open: boolean;
|
||||
@@ -23,6 +25,9 @@ type FormStylingSettingsProps = {
|
||||
isSettingsPage?: boolean;
|
||||
disabled?: boolean;
|
||||
form: UseFormReturn<TProjectStyling | TSurveyStyling>;
|
||||
usePageFontFieldName?: "isPageFontInherited" | "isPageFontInheritedByDefault";
|
||||
usePageFontLabel?: string;
|
||||
usePageFontDescription?: string;
|
||||
};
|
||||
|
||||
export const FormStylingSettings = ({
|
||||
@@ -31,6 +36,9 @@ export const FormStylingSettings = ({
|
||||
disabled = false,
|
||||
setOpen,
|
||||
form,
|
||||
usePageFontFieldName,
|
||||
usePageFontLabel,
|
||||
usePageFontDescription,
|
||||
}: FormStylingSettingsProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -86,6 +94,27 @@ export const FormStylingSettings = ({
|
||||
open={headlinesOpen}
|
||||
setOpen={setHeadlinesOpen}>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{usePageFontFieldName && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={usePageFontFieldName as never}
|
||||
render={({ field }) => (
|
||||
<FormItem className="col-span-2 flex w-full items-center gap-2 space-y-0 rounded-lg border border-slate-200 p-3">
|
||||
<FormControl>
|
||||
<Switch checked={!!field.value} onCheckedChange={(value) => field.onChange(value)} />
|
||||
</FormControl>
|
||||
<div>
|
||||
<FormLabel>
|
||||
{usePageFontLabel ?? t("environments.surveys.edit.use_page_font")}
|
||||
</FormLabel>
|
||||
<FormDescription>
|
||||
{usePageFontDescription ?? t("environments.surveys.edit.use_page_font_description")}
|
||||
</FormDescription>
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<ColorField
|
||||
form={form}
|
||||
name="elementHeadlineColor.light"
|
||||
|
||||
@@ -64,25 +64,39 @@ export const StylingView = ({
|
||||
const { t } = useTranslation();
|
||||
|
||||
const savedProjectStyling = project.styling as Partial<TProjectStyling> | null;
|
||||
const { isPageFontInheritedByDefault: styleDefaultIsPageFontInheritedByDefault, ...surveyStyleDefaults } =
|
||||
STYLE_DEFAULTS;
|
||||
|
||||
// Strip null/undefined values so they don't override STYLE_DEFAULTS.
|
||||
const cleanProject = savedProjectStyling
|
||||
? Object.fromEntries(Object.entries(savedProjectStyling).filter(([, v]) => v != null))
|
||||
const cleanProject: Partial<TProjectStyling> = savedProjectStyling
|
||||
? (Object.fromEntries(
|
||||
Object.entries(savedProjectStyling).filter(([, v]) => v != null)
|
||||
) as Partial<TProjectStyling>)
|
||||
: {};
|
||||
const cleanSurvey = localSurvey.styling
|
||||
? Object.fromEntries(Object.entries(localSurvey.styling).filter(([, v]) => v != null))
|
||||
const {
|
||||
isPageFontInheritedByDefault: projectIsPageFontInheritedByDefault,
|
||||
...cleanProjectWithoutFontDefault
|
||||
} = cleanProject;
|
||||
const cleanSurvey: Partial<TSurveyStyling> = localSurvey.styling
|
||||
? (Object.fromEntries(
|
||||
Object.entries(localSurvey.styling).filter(([, v]) => v != null)
|
||||
) as Partial<TSurveyStyling>)
|
||||
: {};
|
||||
|
||||
const projectLegacyFills = deriveNewFieldsFromLegacy(cleanProject);
|
||||
const projectLegacyFills = deriveNewFieldsFromLegacy(cleanProjectWithoutFontDefault);
|
||||
const surveyLegacyFills = deriveNewFieldsFromLegacy(cleanSurvey);
|
||||
|
||||
const form = useForm<TSurveyStyling>({
|
||||
defaultValues: {
|
||||
...STYLE_DEFAULTS,
|
||||
...surveyStyleDefaults,
|
||||
...projectLegacyFills,
|
||||
...cleanProject,
|
||||
...cleanProjectWithoutFontDefault,
|
||||
...surveyLegacyFills,
|
||||
...cleanSurvey,
|
||||
isPageFontInherited:
|
||||
cleanSurvey.isPageFontInherited ??
|
||||
projectIsPageFontInheritedByDefault ??
|
||||
styleDefaultIsPageFontInheritedByDefault,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -110,16 +124,19 @@ export const StylingView = ({
|
||||
};
|
||||
|
||||
const onResetThemeStyling = () => {
|
||||
const { allowStyleOverwrite, ...baseStyling } = project.styling ?? {};
|
||||
const { allowStyleOverwrite, isPageFontInheritedByDefault, ...baseStyling } = project.styling ?? {};
|
||||
const isPageFontInherited = form.getValues("isPageFontInherited") ?? false;
|
||||
|
||||
setStyling({
|
||||
...baseStyling,
|
||||
overwriteThemeStyling: true,
|
||||
isPageFontInherited,
|
||||
});
|
||||
|
||||
form.reset({
|
||||
...baseStyling,
|
||||
overwriteThemeStyling: true,
|
||||
isPageFontInherited,
|
||||
});
|
||||
|
||||
setConfirmResetStylingModalOpen(false);
|
||||
@@ -151,7 +168,7 @@ export const StylingView = ({
|
||||
|
||||
const defaultProjectStyling = useMemo(() => {
|
||||
const { styling: projectStyling } = project;
|
||||
const { allowStyleOverwrite, ...baseStyling } = projectStyling ?? {};
|
||||
const { allowStyleOverwrite, isPageFontInheritedByDefault, ...baseStyling } = projectStyling ?? {};
|
||||
|
||||
return baseStyling;
|
||||
}, [project]);
|
||||
@@ -166,9 +183,11 @@ export const StylingView = ({
|
||||
if (value) {
|
||||
if (!styling) {
|
||||
// copy the project styling to the survey styling
|
||||
const isPageFontInherited = form.getValues("isPageFontInherited") ?? false;
|
||||
setStyling({
|
||||
...defaultProjectStyling,
|
||||
overwriteThemeStyling: true,
|
||||
isPageFontInherited,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -179,9 +198,11 @@ export const StylingView = ({
|
||||
}
|
||||
// if there are no local styling changes, we set the styling to the project styling
|
||||
else {
|
||||
const isPageFontInherited = form.getValues("isPageFontInherited") ?? false;
|
||||
setStyling({
|
||||
...defaultProjectStyling,
|
||||
overwriteThemeStyling: true,
|
||||
isPageFontInherited,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -192,9 +213,11 @@ export const StylingView = ({
|
||||
setLocalStylingChanges(styling);
|
||||
|
||||
// copy the project styling to the survey styling
|
||||
const isPageFontInherited = form.getValues("isPageFontInherited") ?? false;
|
||||
setStyling({
|
||||
...defaultProjectStyling,
|
||||
overwriteThemeStyling: false,
|
||||
isPageFontInherited,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -205,30 +228,36 @@ export const StylingView = ({
|
||||
<div className="mt-12 space-y-3 p-5">
|
||||
{!isCxMode && (
|
||||
<div className="flex items-center gap-4 py-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="overwriteThemeStyling"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center gap-2 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
id="overwrite-theme-styling"
|
||||
checked={!!field.value}
|
||||
onCheckedChange={handleOverwriteToggle}
|
||||
/>
|
||||
</FormControl>
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="overwriteThemeStyling"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex items-center gap-2 space-y-0">
|
||||
<FormControl>
|
||||
<Switch
|
||||
id="overwrite-theme-styling"
|
||||
checked={!!field.value}
|
||||
onCheckedChange={handleOverwriteToggle}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<div>
|
||||
<FormLabel htmlFor="overwrite-theme-styling" className="text-base font-semibold text-slate-900">
|
||||
{t("environments.surveys.edit.add_custom_styles")}
|
||||
</FormLabel>
|
||||
<FormDescription className="text-sm text-slate-800">
|
||||
{t("environments.surveys.edit.override_theme_with_individual_styles_for_this_survey")}
|
||||
</FormDescription>
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div>
|
||||
<FormLabel
|
||||
htmlFor="overwrite-theme-styling"
|
||||
className="text-base font-semibold text-slate-900">
|
||||
{t("environments.surveys.edit.add_custom_styles")}
|
||||
</FormLabel>
|
||||
<FormDescription className="text-sm text-slate-800">
|
||||
{t(
|
||||
"environments.surveys.edit.override_theme_with_individual_styles_for_this_survey"
|
||||
)}
|
||||
</FormDescription>
|
||||
</div>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -269,6 +298,9 @@ export const StylingView = ({
|
||||
setOpen={setFormStylingOpen}
|
||||
disabled={!overwriteThemeStyling}
|
||||
form={form as UseFormReturn<TProjectStyling | TSurveyStyling>}
|
||||
usePageFontFieldName="isPageFontInherited"
|
||||
usePageFontLabel={t("environments.surveys.edit.use_page_font")}
|
||||
usePageFontDescription={t("environments.surveys.edit.use_page_font_description")}
|
||||
/>
|
||||
|
||||
<CardStylingSettings
|
||||
|
||||
@@ -189,10 +189,19 @@ function computeStyling(
|
||||
projectStyling: TProjectStyling,
|
||||
surveyStyling?: TSurveyStyling | null
|
||||
): TProjectStyling | TSurveyStyling {
|
||||
const resolvedIsPageFontInherited =
|
||||
surveyStyling?.isPageFontInherited ?? projectStyling.isPageFontInheritedByDefault ?? false;
|
||||
const fontOverrides = {
|
||||
isPageFontInherited: resolvedIsPageFontInherited,
|
||||
...(surveyStyling?.fontFamily !== undefined ? { fontFamily: surveyStyling.fontFamily } : {}),
|
||||
};
|
||||
|
||||
if (!projectStyling.allowStyleOverwrite) {
|
||||
return projectStyling;
|
||||
return { ...projectStyling, ...fontOverrides };
|
||||
}
|
||||
return surveyStyling?.overwriteThemeStyling ? surveyStyling : projectStyling;
|
||||
return surveyStyling?.overwriteThemeStyling
|
||||
? { ...surveyStyling, isPageFontInherited: resolvedIsPageFontInherited }
|
||||
: { ...projectStyling, ...fontOverrides };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { TProjectStyling } from "@formbricks/types/project";
|
||||
import { TSurvey, TSurveyStyling } from "@formbricks/types/surveys/types";
|
||||
import { cn } from "@/lib/cn";
|
||||
import { getStyling as getEffectiveStyling } from "@/lib/utils/styling";
|
||||
import { ClientLogo } from "@/modules/ui/components/client-logo";
|
||||
import { MediaBackground } from "@/modules/ui/components/media-background";
|
||||
import { ResetProgressButton } from "@/modules/ui/components/reset-progress-button";
|
||||
@@ -59,23 +60,7 @@ export const PreviewSurvey = ({
|
||||
const clickOutsideClose = surveyClickOutsideClose ?? project.clickOutsideClose;
|
||||
|
||||
const styling: TSurveyStyling | TProjectStyling = useMemo(() => {
|
||||
// allow style overwrite is disabled from the project
|
||||
if (!project.styling.allowStyleOverwrite) {
|
||||
return project.styling;
|
||||
}
|
||||
|
||||
// allow style overwrite is enabled from the project
|
||||
if (project.styling.allowStyleOverwrite) {
|
||||
// survey style overwrite is disabled
|
||||
if (!survey.styling?.overwriteThemeStyling) {
|
||||
return project.styling;
|
||||
}
|
||||
|
||||
// survey style overwrite is enabled
|
||||
return survey.styling;
|
||||
}
|
||||
|
||||
return project.styling;
|
||||
return getEffectiveStyling(project, survey);
|
||||
}, [project.styling, survey.styling]);
|
||||
|
||||
const updateElementId = useCallback(
|
||||
|
||||
@@ -329,6 +329,19 @@ test.describe("Survey Styling", async () => {
|
||||
// Navigate to Styling tab
|
||||
await page.getByRole("button", { name: "Styling" }).click();
|
||||
|
||||
await openAccordion(page, "Survey styling");
|
||||
await openAccordion(page, "Headlines & Descriptions");
|
||||
const usePageFontToggle = page.getByLabel("Use page font");
|
||||
await expect(usePageFontToggle).toBeVisible();
|
||||
await expect(usePageFontToggle).toBeChecked();
|
||||
let fontCss = await page.evaluate(() => document.getElementById("formbricks__css__custom")?.innerHTML);
|
||||
expect(fontCss).not.toContain("--fb-font-family");
|
||||
|
||||
await usePageFontToggle.click();
|
||||
await page.waitForTimeout(800);
|
||||
fontCss = await page.evaluate(() => document.getElementById("formbricks__css__custom")?.innerHTML);
|
||||
expect(fontCss).toContain("--fb-font-family: Inter, Helvetica, Arial, sans-serif");
|
||||
|
||||
// Toggle "Enable custom styling" (Survey override)
|
||||
// Note: The label text might be "Add custom styles" in survey editor?
|
||||
// Checking previous file: `page.getByLabel("Add custom styles")`
|
||||
|
||||
@@ -28,6 +28,7 @@ Fine-tune how question headlines, descriptions, and upper labels appear:
|
||||
|
||||
| Property | Description |
|
||||
|---|---|
|
||||
| **Use page font** | Applies the host app or website font across surveys in this workspace. This is a workspace-level setting and affects all surveys unless a survey explicitly overrides it in the Survey Editor. |
|
||||
| **Headline Color** | Color of the question headline text |
|
||||
| **Description Color** | Color of the question description text |
|
||||
| **Headline Font Size** | Font size for headlines (in `px` or any CSS unit) |
|
||||
@@ -38,6 +39,11 @@ Fine-tune how question headlines, descriptions, and upper labels appear:
|
||||
| **Upper Label Font Size** | Font size for upper labels |
|
||||
| **Upper Label Font Weight** | Numeric font weight for upper labels |
|
||||
|
||||
<Note>
|
||||
New workspaces have <strong>Use page font</strong> enabled by default. Existing workspaces keep their current
|
||||
default until you change it.
|
||||
</Note>
|
||||
|
||||
### Inputs
|
||||
|
||||
Control the appearance of text inputs, textareas, and other form fields:
|
||||
|
||||
@@ -27,6 +27,12 @@ Overwrite the global styling theme for individual surveys to create unique style
|
||||
|
||||
Just hit the **Save** button to apply your changes. Your survey is now ready to impress with its unique look!
|
||||
|
||||
<Note>
|
||||
The workspace-level <strong>Use page font</strong> setting (in <strong>Look & Feel → Survey styling → Headlines & Descriptions</strong>)
|
||||
applies to all surveys in the workspace by default. In this survey-level styling view, you can enable or disable
|
||||
<strong>Use page font</strong> to override that default for a specific survey.
|
||||
</Note>
|
||||
|
||||
## Overwrite CSS Styles for App & Website Surveys
|
||||
|
||||
You can overwrite the default CSS styles for app and website surveys by adding the following CSS to your global CSS file (e.g., `globals.css`):
|
||||
|
||||
@@ -311,7 +311,11 @@ describe("utils.ts", () => {
|
||||
test("returns project styling if allowStyleOverwrite=false", () => {
|
||||
const project = {
|
||||
id: "p1",
|
||||
styling: { allowStyleOverwrite: false, brandColor: { light: "#fff" } },
|
||||
styling: {
|
||||
allowStyleOverwrite: false,
|
||||
isPageFontInheritedByDefault: false,
|
||||
brandColor: { light: "#fff" },
|
||||
},
|
||||
} as TEnvironmentStateProject;
|
||||
const survey = {
|
||||
styling: {
|
||||
@@ -322,13 +326,20 @@ describe("utils.ts", () => {
|
||||
|
||||
const result = getStyling(project, survey);
|
||||
// should get project styling
|
||||
expect(result).toEqual(project.styling);
|
||||
expect(result).toEqual({
|
||||
...project.styling,
|
||||
isPageFontInherited: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("returns project styling if allowStyleOverwrite=true but survey overwriteThemeStyling=false", () => {
|
||||
const project = {
|
||||
id: "p1",
|
||||
styling: { allowStyleOverwrite: true, brandColor: { light: "#fff" } },
|
||||
styling: {
|
||||
allowStyleOverwrite: true,
|
||||
isPageFontInheritedByDefault: false,
|
||||
brandColor: { light: "#fff" },
|
||||
},
|
||||
} as TEnvironmentStateProject;
|
||||
const survey = {
|
||||
styling: {
|
||||
@@ -339,13 +350,20 @@ describe("utils.ts", () => {
|
||||
|
||||
const result = getStyling(project, survey);
|
||||
// should get project styling still
|
||||
expect(result).toEqual(project.styling);
|
||||
expect(result).toEqual({
|
||||
...project.styling,
|
||||
isPageFontInherited: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("returns survey styling if allowStyleOverwrite=true and survey overwriteThemeStyling=true", () => {
|
||||
const project = {
|
||||
id: "p1",
|
||||
styling: { allowStyleOverwrite: true, brandColor: { light: "#fff" } },
|
||||
styling: {
|
||||
allowStyleOverwrite: true,
|
||||
isPageFontInheritedByDefault: false,
|
||||
brandColor: { light: "#fff" },
|
||||
},
|
||||
} as TEnvironmentStateProject;
|
||||
const survey = {
|
||||
styling: {
|
||||
@@ -355,7 +373,53 @@ describe("utils.ts", () => {
|
||||
} as TEnvironmentStateSurvey;
|
||||
|
||||
const result = getStyling(project, survey);
|
||||
expect(result).toEqual(survey.styling);
|
||||
expect(result).toEqual({
|
||||
...survey.styling,
|
||||
isPageFontInherited: false,
|
||||
});
|
||||
});
|
||||
|
||||
test("keeps survey font preferences when using project theme", () => {
|
||||
const project = {
|
||||
id: "p1",
|
||||
styling: { allowStyleOverwrite: true, brandColor: { light: "#fff" } },
|
||||
} as TEnvironmentStateProject;
|
||||
const survey = {
|
||||
styling: {
|
||||
overwriteThemeStyling: false,
|
||||
isPageFontInherited: true,
|
||||
fontFamily: "Inter, Noto Sans Arabic, sans-serif",
|
||||
} as TSurveyStyling,
|
||||
} as TEnvironmentStateSurvey;
|
||||
|
||||
const result = getStyling(project, survey);
|
||||
expect(result).toEqual({
|
||||
...project.styling,
|
||||
isPageFontInherited: true,
|
||||
fontFamily: "Inter, Noto Sans Arabic, sans-serif",
|
||||
});
|
||||
});
|
||||
|
||||
test("inherits workspace default page-font setting when survey does not specify it", () => {
|
||||
const project = {
|
||||
id: "p1",
|
||||
styling: {
|
||||
allowStyleOverwrite: true,
|
||||
isPageFontInheritedByDefault: true,
|
||||
brandColor: { light: "#fff" },
|
||||
},
|
||||
} as TEnvironmentStateProject;
|
||||
const survey = {
|
||||
styling: {
|
||||
overwriteThemeStyling: false,
|
||||
} as TSurveyStyling,
|
||||
} as TEnvironmentStateSurvey;
|
||||
|
||||
const result = getStyling(project, survey);
|
||||
expect(result).toEqual({
|
||||
...project.styling,
|
||||
isPageFontInherited: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -142,19 +142,35 @@ export const getStyling = (
|
||||
project: TEnvironmentStateProject,
|
||||
survey: TEnvironmentStateSurvey
|
||||
): TProjectStyling | TSurveyStyling => {
|
||||
const resolvedIsPageFontInherited =
|
||||
survey.styling?.isPageFontInherited ?? project.styling.isPageFontInheritedByDefault ?? false;
|
||||
const getFontOverrides = () => ({
|
||||
isPageFontInherited: resolvedIsPageFontInherited,
|
||||
...(survey.styling?.fontFamily !== undefined ? { fontFamily: survey.styling.fontFamily } : {}),
|
||||
});
|
||||
|
||||
// allow style overwrite is enabled from the project
|
||||
if (project.styling.allowStyleOverwrite) {
|
||||
// survey style overwrite is disabled
|
||||
if (!survey.styling?.overwriteThemeStyling) {
|
||||
return project.styling;
|
||||
return {
|
||||
...project.styling,
|
||||
...getFontOverrides(),
|
||||
};
|
||||
}
|
||||
|
||||
// survey style overwrite is enabled
|
||||
return survey.styling;
|
||||
return {
|
||||
...survey.styling,
|
||||
isPageFontInherited: resolvedIsPageFontInherited,
|
||||
};
|
||||
}
|
||||
|
||||
// allow style overwrite is disabled from the project
|
||||
return project.styling;
|
||||
return {
|
||||
...project.styling,
|
||||
...getFontOverrides(),
|
||||
};
|
||||
};
|
||||
|
||||
export const getDefaultLanguageCode = (survey: TEnvironmentStateSurvey): string | undefined => {
|
||||
|
||||
@@ -91,11 +91,12 @@ export interface TConfigInput {
|
||||
|
||||
export interface TStylingColor {
|
||||
light: string;
|
||||
dark?: string | null | undefined;
|
||||
dark?: string | null;
|
||||
}
|
||||
|
||||
export interface TBaseStyling {
|
||||
brandColor?: TStylingColor | null;
|
||||
fontFamily?: string | null;
|
||||
questionColor?: TStylingColor | null;
|
||||
inputColor?: TStylingColor | null;
|
||||
inputBorderColor?: TStylingColor | null;
|
||||
@@ -119,10 +120,12 @@ export interface TBaseStyling {
|
||||
|
||||
export interface TProjectStyling extends TBaseStyling {
|
||||
allowStyleOverwrite: boolean;
|
||||
isPageFontInheritedByDefault?: boolean | null;
|
||||
}
|
||||
|
||||
export interface TSurveyStyling extends TBaseStyling {
|
||||
overwriteThemeStyling?: boolean | null;
|
||||
isPageFontInherited?: boolean | null;
|
||||
}
|
||||
|
||||
export interface TUpdates {
|
||||
|
||||
@@ -278,6 +278,43 @@ describe("addCustomThemeToDom", () => {
|
||||
expect(variables["--fb-border-radius"]).toBe("8px"); // Default roundness
|
||||
});
|
||||
|
||||
test("uses the legacy font stack when page-font inheritance is disabled", () => {
|
||||
const styling = getBaseProjectStyling({});
|
||||
addCustomThemeToDom({ styling });
|
||||
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
|
||||
const variables = getCssVariables(styleElement);
|
||||
|
||||
expect(variables["--fb-font-family"]).toBe("Inter, Helvetica, Arial, sans-serif");
|
||||
expect(styleElement.innerHTML).toContain("font-family: var(--fb-font-family) !important;");
|
||||
});
|
||||
|
||||
test("inherits host font when page-font inheritance is enabled", () => {
|
||||
const styling: TSurveyStyling = {
|
||||
isPageFontInherited: true,
|
||||
};
|
||||
|
||||
addCustomThemeToDom({ styling });
|
||||
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
|
||||
const variables = getCssVariables(styleElement);
|
||||
|
||||
expect(variables["--fb-font-family"]).toBeUndefined();
|
||||
expect(styleElement.innerHTML).not.toContain("font-family: var(--fb-font-family) !important;");
|
||||
});
|
||||
|
||||
test("prefers explicit fontFamily over page-font inheritance", () => {
|
||||
const styling: TSurveyStyling = {
|
||||
isPageFontInherited: true,
|
||||
fontFamily: "Inter, Noto Sans Arabic, sans-serif",
|
||||
};
|
||||
|
||||
addCustomThemeToDom({ styling });
|
||||
const styleElement = document.getElementById("formbricks__css__custom") as HTMLStyleElement;
|
||||
const variables = getCssVariables(styleElement);
|
||||
|
||||
expect(variables["--fb-font-family"]).toBe("Inter, Noto Sans Arabic, sans-serif");
|
||||
expect(styleElement.innerHTML).toContain("font-family: var(--fb-font-family) !important;");
|
||||
});
|
||||
|
||||
test("should apply brand-text-color as black for light brandColor", () => {
|
||||
const styling = getBaseProjectStyling({ brandColor: { light: "#FFFF00" } }); // A light color
|
||||
addCustomThemeToDom({ styling });
|
||||
|
||||
@@ -7,6 +7,8 @@ import global from "@/styles/global.css?inline";
|
||||
import preflight from "@/styles/preflight.css?inline";
|
||||
import editorCss from "../../../../apps/web/modules/ui/components/editor/styles-editor-frontend.css?inline";
|
||||
|
||||
const LEGACY_FONT_FAMILY_STACK = "Inter, Helvetica, Arial, sans-serif";
|
||||
|
||||
// Store the nonce globally for style elements
|
||||
let styleNonce: string | undefined;
|
||||
|
||||
@@ -81,6 +83,14 @@ export const addCustomThemeToDom = ({ styling }: { styling: TProjectStyling | TS
|
||||
// Start the innerHTML string with #fbjs
|
||||
let cssVariables = "#fbjs {\n";
|
||||
|
||||
const explicitFontFamily = styling.fontFamily?.trim();
|
||||
const isPageFontInherited =
|
||||
(styling as TSurveyStyling).isPageFontInherited ??
|
||||
(styling as TProjectStyling).isPageFontInheritedByDefault ??
|
||||
false;
|
||||
const resolvedFontFamily =
|
||||
explicitFontFamily || (isPageFontInherited ? undefined : LEGACY_FONT_FAMILY_STACK);
|
||||
|
||||
// Helper function to append the variable if it's not undefined
|
||||
const appendCssVariable = (variableName: string, value?: string | null) => {
|
||||
if (value !== undefined && value !== null) {
|
||||
@@ -299,6 +309,7 @@ export const addCustomThemeToDom = ({ styling }: { styling: TProjectStyling | TS
|
||||
"progress-indicator-bg-color",
|
||||
styling.progressIndicatorBgColor?.light ?? styling.brandColor?.light
|
||||
);
|
||||
appendCssVariable("font-family", resolvedFontFamily);
|
||||
|
||||
// Close the #fbjs variable block
|
||||
cssVariables += "}\n";
|
||||
@@ -319,6 +330,10 @@ export const addCustomThemeToDom = ({ styling }: { styling: TProjectStyling | TS
|
||||
};
|
||||
|
||||
// --- Headlines ---
|
||||
if (resolvedFontFamily) {
|
||||
addRule("#fbjs", " font-family: var(--fb-font-family) !important;\n");
|
||||
}
|
||||
|
||||
let headlineDecls = "";
|
||||
if (styling.elementHeadlineFontSize !== undefined)
|
||||
headlineDecls += " font-size: var(--fb-element-headline-font-size) !important;\n";
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
border-color: theme("borderColor.DEFAULT", currentColor);
|
||||
/* 2 */
|
||||
|
||||
font-family: Inter, Helvetica, Arial, sans-serif;
|
||||
font-family: inherit;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ZBaseStyling, ZLogo } from "./styling";
|
||||
|
||||
export const ZProjectStyling = ZBaseStyling.extend({
|
||||
allowStyleOverwrite: z.boolean(),
|
||||
isPageFontInheritedByDefault: z.boolean().nullish(),
|
||||
});
|
||||
|
||||
export type TProjectStyling = z.infer<typeof ZProjectStyling>;
|
||||
|
||||
@@ -239,6 +239,7 @@ export type TSurveyBackgroundBgType = z.infer<typeof ZSurveyBackgroundBgType>;
|
||||
|
||||
export const ZSurveyStyling = ZBaseStyling.extend({
|
||||
overwriteThemeStyling: z.boolean().nullish(),
|
||||
isPageFontInherited: z.boolean().nullish(),
|
||||
});
|
||||
|
||||
export type TSurveyStyling = z.infer<typeof ZSurveyStyling>;
|
||||
|
||||
Reference in New Issue
Block a user