Public Designer için style ve css
This commit is contained in:
parent
900f2815f9
commit
ffa3ff2d63
18 changed files with 1124 additions and 286 deletions
|
|
@ -66,6 +66,7 @@ public class HomeSlideDto
|
||||||
{
|
{
|
||||||
public string TitleKey { get; set; }
|
public string TitleKey { get; set; }
|
||||||
public string SubtitleKey { get; set; }
|
public string SubtitleKey { get; set; }
|
||||||
|
public string StyleClass { get; set; }
|
||||||
public List<HomeSlideServiceDto> Services { get; set; } = [];
|
public List<HomeSlideServiceDto> Services { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,6 +75,7 @@ public class HomeSlideServiceDto
|
||||||
public string Icon { get; set; }
|
public string Icon { get; set; }
|
||||||
public string TitleKey { get; set; }
|
public string TitleKey { get; set; }
|
||||||
public string DescriptionKey { get; set; }
|
public string DescriptionKey { get; set; }
|
||||||
|
public string StyleClass { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HomeFeatureDto
|
public class HomeFeatureDto
|
||||||
|
|
@ -81,6 +83,7 @@ public class HomeFeatureDto
|
||||||
public string Icon { get; set; }
|
public string Icon { get; set; }
|
||||||
public string TitleKey { get; set; }
|
public string TitleKey { get; set; }
|
||||||
public string DescriptionKey { get; set; }
|
public string DescriptionKey { get; set; }
|
||||||
|
public string StyleClass { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HomeSolutionDto
|
public class HomeSolutionDto
|
||||||
|
|
@ -89,4 +92,5 @@ public class HomeSolutionDto
|
||||||
public string ColorClass { get; set; }
|
public string ColorClass { get; set; }
|
||||||
public string TitleKey { get; set; }
|
public string TitleKey { get; set; }
|
||||||
public string DescriptionKey { get; set; }
|
public string DescriptionKey { get; set; }
|
||||||
|
public string StyleClass { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ public class SaveAboutPageInput
|
||||||
public List<SaveAboutStatInput> Stats { get; set; } = [];
|
public List<SaveAboutStatInput> Stats { get; set; } = [];
|
||||||
public List<SaveLocalizedTextInput> Descriptions { get; set; } = [];
|
public List<SaveLocalizedTextInput> Descriptions { get; set; } = [];
|
||||||
public List<SaveAboutSectionInput> Sections { get; set; } = [];
|
public List<SaveAboutSectionInput> Sections { get; set; } = [];
|
||||||
|
public List<SaveLocalizedTextInput> StyleTexts { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SaveAboutStatInput
|
public class SaveAboutStatInput
|
||||||
|
|
@ -58,6 +59,7 @@ public class SaveServicesPageInput
|
||||||
public string CtaButtonLabelValue { get; set; }
|
public string CtaButtonLabelValue { get; set; }
|
||||||
public List<SaveServiceItemInput> ServiceItems { get; set; } = [];
|
public List<SaveServiceItemInput> ServiceItems { get; set; } = [];
|
||||||
public List<SaveServiceItemInput> SupportItems { get; set; } = [];
|
public List<SaveServiceItemInput> SupportItems { get; set; } = [];
|
||||||
|
public List<SaveLocalizedTextInput> StyleTexts { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SaveServiceItemInput
|
public class SaveServiceItemInput
|
||||||
|
|
@ -84,22 +86,40 @@ public class SaveHomePageInput
|
||||||
public string HeroBackgroundImageValue { get; set; }
|
public string HeroBackgroundImageValue { get; set; }
|
||||||
public string HeroPrimaryCtaKey { get; set; }
|
public string HeroPrimaryCtaKey { get; set; }
|
||||||
public string HeroPrimaryCtaValue { get; set; }
|
public string HeroPrimaryCtaValue { get; set; }
|
||||||
|
public string HeroPrimaryCtaStyleKey { get; set; }
|
||||||
|
public string HeroPrimaryCtaStyleValue { get; set; }
|
||||||
public string HeroSecondaryCtaKey { get; set; }
|
public string HeroSecondaryCtaKey { get; set; }
|
||||||
public string HeroSecondaryCtaValue { get; set; }
|
public string HeroSecondaryCtaValue { get; set; }
|
||||||
|
public string HeroSecondaryCtaStyleKey { get; set; }
|
||||||
|
public string HeroSecondaryCtaStyleValue { get; set; }
|
||||||
public string FeaturesTitleKey { get; set; }
|
public string FeaturesTitleKey { get; set; }
|
||||||
public string FeaturesTitleValue { get; set; }
|
public string FeaturesTitleValue { get; set; }
|
||||||
|
public string FeaturesTitleStyleKey { get; set; }
|
||||||
|
public string FeaturesTitleStyleValue { get; set; }
|
||||||
public string FeaturesSubtitleKey { get; set; }
|
public string FeaturesSubtitleKey { get; set; }
|
||||||
public string FeaturesSubtitleValue { get; set; }
|
public string FeaturesSubtitleValue { get; set; }
|
||||||
|
public string FeaturesSubtitleStyleKey { get; set; }
|
||||||
|
public string FeaturesSubtitleStyleValue { get; set; }
|
||||||
public string SolutionsTitleKey { get; set; }
|
public string SolutionsTitleKey { get; set; }
|
||||||
public string SolutionsTitleValue { get; set; }
|
public string SolutionsTitleValue { get; set; }
|
||||||
|
public string SolutionsTitleStyleKey { get; set; }
|
||||||
|
public string SolutionsTitleStyleValue { get; set; }
|
||||||
public string SolutionsSubtitleKey { get; set; }
|
public string SolutionsSubtitleKey { get; set; }
|
||||||
public string SolutionsSubtitleValue { get; set; }
|
public string SolutionsSubtitleValue { get; set; }
|
||||||
|
public string SolutionsSubtitleStyleKey { get; set; }
|
||||||
|
public string SolutionsSubtitleStyleValue { get; set; }
|
||||||
public string CtaTitleKey { get; set; }
|
public string CtaTitleKey { get; set; }
|
||||||
public string CtaTitleValue { get; set; }
|
public string CtaTitleValue { get; set; }
|
||||||
|
public string CtaTitleStyleKey { get; set; }
|
||||||
|
public string CtaTitleStyleValue { get; set; }
|
||||||
public string CtaSubtitleKey { get; set; }
|
public string CtaSubtitleKey { get; set; }
|
||||||
public string CtaSubtitleValue { get; set; }
|
public string CtaSubtitleValue { get; set; }
|
||||||
|
public string CtaSubtitleStyleKey { get; set; }
|
||||||
|
public string CtaSubtitleStyleValue { get; set; }
|
||||||
public string CtaButtonLabelKey { get; set; }
|
public string CtaButtonLabelKey { get; set; }
|
||||||
public string CtaButtonLabelValue { get; set; }
|
public string CtaButtonLabelValue { get; set; }
|
||||||
|
public string CtaButtonStyleKey { get; set; }
|
||||||
|
public string CtaButtonStyleValue { get; set; }
|
||||||
public List<SaveHomeSlideInput> Slides { get; set; } = [];
|
public List<SaveHomeSlideInput> Slides { get; set; } = [];
|
||||||
public List<SaveHomeFeatureInput> Features { get; set; } = [];
|
public List<SaveHomeFeatureInput> Features { get; set; } = [];
|
||||||
public List<SaveHomeSolutionInput> Solutions { get; set; } = [];
|
public List<SaveHomeSolutionInput> Solutions { get; set; } = [];
|
||||||
|
|
@ -111,6 +131,7 @@ public class SaveHomeSlideInput
|
||||||
public string TitleValue { get; set; }
|
public string TitleValue { get; set; }
|
||||||
public string SubtitleKey { get; set; }
|
public string SubtitleKey { get; set; }
|
||||||
public string SubtitleValue { get; set; }
|
public string SubtitleValue { get; set; }
|
||||||
|
public string StyleClass { get; set; }
|
||||||
public List<SaveHomeSlideServiceInput> Services { get; set; } = [];
|
public List<SaveHomeSlideServiceInput> Services { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,6 +142,7 @@ public class SaveHomeSlideServiceInput
|
||||||
public string TitleValue { get; set; }
|
public string TitleValue { get; set; }
|
||||||
public string DescriptionKey { get; set; }
|
public string DescriptionKey { get; set; }
|
||||||
public string DescriptionValue { get; set; }
|
public string DescriptionValue { get; set; }
|
||||||
|
public string StyleClass { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SaveHomeFeatureInput
|
public class SaveHomeFeatureInput
|
||||||
|
|
@ -130,6 +152,7 @@ public class SaveHomeFeatureInput
|
||||||
public string TitleValue { get; set; }
|
public string TitleValue { get; set; }
|
||||||
public string DescriptionKey { get; set; }
|
public string DescriptionKey { get; set; }
|
||||||
public string DescriptionValue { get; set; }
|
public string DescriptionValue { get; set; }
|
||||||
|
public string StyleClass { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SaveHomeSolutionInput
|
public class SaveHomeSolutionInput
|
||||||
|
|
@ -140,6 +163,7 @@ public class SaveHomeSolutionInput
|
||||||
public string TitleValue { get; set; }
|
public string TitleValue { get; set; }
|
||||||
public string DescriptionKey { get; set; }
|
public string DescriptionKey { get; set; }
|
||||||
public string DescriptionValue { get; set; }
|
public string DescriptionValue { get; set; }
|
||||||
|
public string StyleClass { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SaveContactPageInput
|
public class SaveContactPageInput
|
||||||
|
|
@ -168,6 +192,7 @@ public class SaveContactPageInput
|
||||||
public string BankBranch { get; set; }
|
public string BankBranch { get; set; }
|
||||||
public string BankAccountNumber { get; set; }
|
public string BankAccountNumber { get; set; }
|
||||||
public string BankIban { get; set; }
|
public string BankIban { get; set; }
|
||||||
|
public string BankStyleClass { get; set; }
|
||||||
|
|
||||||
public string WorkHoursTitleKey { get; set; }
|
public string WorkHoursTitleKey { get; set; }
|
||||||
public string WorkHoursTitleValue { get; set; }
|
public string WorkHoursTitleValue { get; set; }
|
||||||
|
|
@ -177,6 +202,7 @@ public class SaveContactPageInput
|
||||||
public string WorkWeekendValue { get; set; }
|
public string WorkWeekendValue { get; set; }
|
||||||
public string WorkWhatsappKey { get; set; }
|
public string WorkWhatsappKey { get; set; }
|
||||||
public string WorkWhatsappValue { get; set; }
|
public string WorkWhatsappValue { get; set; }
|
||||||
|
public string WorkHoursStyleClass { get; set; }
|
||||||
|
|
||||||
public string MapTitleKey { get; set; }
|
public string MapTitleKey { get; set; }
|
||||||
public string MapTitleValue { get; set; }
|
public string MapTitleValue { get; set; }
|
||||||
|
|
@ -186,4 +212,7 @@ public class SaveContactPageInput
|
||||||
public bool MapAllowFullScreen { get; set; }
|
public bool MapAllowFullScreen { get; set; }
|
||||||
public string MapLoading { get; set; }
|
public string MapLoading { get; set; }
|
||||||
public string MapReferrerPolicy { get; set; }
|
public string MapReferrerPolicy { get; set; }
|
||||||
|
public string MapContainerStyleClass { get; set; }
|
||||||
|
public string MapFrameStyleClass { get; set; }
|
||||||
|
public List<SaveLocalizedTextInput> StyleTexts { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
@ -128,6 +128,11 @@ public class PublicAppService : PlatformAppService
|
||||||
await UpsertLanguageTextAsync(input.CultureName, section.DescriptionKey, section.DescriptionValue);
|
await UpsertLanguageTextAsync(input.CultureName, section.DescriptionKey, section.DescriptionValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var styleText in input.StyleTexts)
|
||||||
|
{
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, styleText.Key, styleText.Value);
|
||||||
|
}
|
||||||
|
|
||||||
await _aboutRepository.UpdateAsync(entity, autoSave: true);
|
await _aboutRepository.UpdateAsync(entity, autoSave: true);
|
||||||
await _languageTextAppService.ClearRedisCacheAsync();
|
await _languageTextAppService.ClearRedisCacheAsync();
|
||||||
}
|
}
|
||||||
|
|
@ -176,6 +181,11 @@ public class PublicAppService : PlatformAppService
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.CtaDescriptionKey, input.CtaDescriptionValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.CtaDescriptionKey, input.CtaDescriptionValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.CtaButtonLabelKey, input.CtaButtonLabelValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.CtaButtonLabelKey, input.CtaButtonLabelValue);
|
||||||
|
|
||||||
|
foreach (var styleText in input.StyleTexts)
|
||||||
|
{
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, styleText.Key, styleText.Value);
|
||||||
|
}
|
||||||
|
|
||||||
await CurrentUnitOfWork!.SaveChangesAsync();
|
await CurrentUnitOfWork!.SaveChangesAsync();
|
||||||
await _languageTextAppService.ClearRedisCacheAsync();
|
await _languageTextAppService.ClearRedisCacheAsync();
|
||||||
}
|
}
|
||||||
|
|
@ -212,11 +222,13 @@ public class PublicAppService : PlatformAppService
|
||||||
{
|
{
|
||||||
TitleKey = slide.TitleKey,
|
TitleKey = slide.TitleKey,
|
||||||
SubtitleKey = slide.SubtitleKey,
|
SubtitleKey = slide.SubtitleKey,
|
||||||
|
StyleClass = slide.StyleClass,
|
||||||
Services = slide.Services.Select(service => new HomeSlideServiceDto
|
Services = slide.Services.Select(service => new HomeSlideServiceDto
|
||||||
{
|
{
|
||||||
Icon = service.Icon,
|
Icon = service.Icon,
|
||||||
TitleKey = service.TitleKey,
|
TitleKey = service.TitleKey,
|
||||||
DescriptionKey = service.DescriptionKey,
|
DescriptionKey = service.DescriptionKey,
|
||||||
|
StyleClass = service.StyleClass,
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
}).ToList());
|
}).ToList());
|
||||||
|
|
||||||
|
|
@ -225,6 +237,7 @@ public class PublicAppService : PlatformAppService
|
||||||
Icon = feature.Icon,
|
Icon = feature.Icon,
|
||||||
TitleKey = feature.TitleKey,
|
TitleKey = feature.TitleKey,
|
||||||
DescriptionKey = feature.DescriptionKey,
|
DescriptionKey = feature.DescriptionKey,
|
||||||
|
StyleClass = feature.StyleClass,
|
||||||
}).ToList());
|
}).ToList());
|
||||||
|
|
||||||
entity.SolutionsJson = JsonSerializer.Serialize(input.Solutions.Select(solution => new HomeSolutionDto
|
entity.SolutionsJson = JsonSerializer.Serialize(input.Solutions.Select(solution => new HomeSolutionDto
|
||||||
|
|
@ -233,6 +246,7 @@ public class PublicAppService : PlatformAppService
|
||||||
ColorClass = solution.ColorClass,
|
ColorClass = solution.ColorClass,
|
||||||
TitleKey = solution.TitleKey,
|
TitleKey = solution.TitleKey,
|
||||||
DescriptionKey = solution.DescriptionKey,
|
DescriptionKey = solution.DescriptionKey,
|
||||||
|
StyleClass = solution.StyleClass,
|
||||||
}).ToList());
|
}).ToList());
|
||||||
|
|
||||||
if (isNewEntity)
|
if (isNewEntity)
|
||||||
|
|
@ -246,14 +260,23 @@ public class PublicAppService : PlatformAppService
|
||||||
|
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.HeroBackgroundImageKey, input.HeroBackgroundImageValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.HeroBackgroundImageKey, input.HeroBackgroundImageValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.HeroPrimaryCtaKey, input.HeroPrimaryCtaValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.HeroPrimaryCtaKey, input.HeroPrimaryCtaValue);
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, input.HeroPrimaryCtaStyleKey, input.HeroPrimaryCtaStyleValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.HeroSecondaryCtaKey, input.HeroSecondaryCtaValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.HeroSecondaryCtaKey, input.HeroSecondaryCtaValue);
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, input.HeroSecondaryCtaStyleKey, input.HeroSecondaryCtaStyleValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.FeaturesTitleKey, input.FeaturesTitleValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.FeaturesTitleKey, input.FeaturesTitleValue);
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, input.FeaturesTitleStyleKey, input.FeaturesTitleStyleValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.FeaturesSubtitleKey, input.FeaturesSubtitleValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.FeaturesSubtitleKey, input.FeaturesSubtitleValue);
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, input.FeaturesSubtitleStyleKey, input.FeaturesSubtitleStyleValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.SolutionsTitleKey, input.SolutionsTitleValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.SolutionsTitleKey, input.SolutionsTitleValue);
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, input.SolutionsTitleStyleKey, input.SolutionsTitleStyleValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.SolutionsSubtitleKey, input.SolutionsSubtitleValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.SolutionsSubtitleKey, input.SolutionsSubtitleValue);
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, input.SolutionsSubtitleStyleKey, input.SolutionsSubtitleStyleValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.CtaTitleKey, input.CtaTitleValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.CtaTitleKey, input.CtaTitleValue);
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, input.CtaTitleStyleKey, input.CtaTitleStyleValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.CtaSubtitleKey, input.CtaSubtitleValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.CtaSubtitleKey, input.CtaSubtitleValue);
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, input.CtaSubtitleStyleKey, input.CtaSubtitleStyleValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.CtaButtonLabelKey, input.CtaButtonLabelValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.CtaButtonLabelKey, input.CtaButtonLabelValue);
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, input.CtaButtonStyleKey, input.CtaButtonStyleValue);
|
||||||
|
|
||||||
foreach (var slide in input.Slides)
|
foreach (var slide in input.Slides)
|
||||||
{
|
{
|
||||||
|
|
@ -528,6 +551,7 @@ public class PublicAppService : PlatformAppService
|
||||||
Branch = input.BankBranch,
|
Branch = input.BankBranch,
|
||||||
AccountNumber = input.BankAccountNumber,
|
AccountNumber = input.BankAccountNumber,
|
||||||
Iban = input.BankIban,
|
Iban = input.BankIban,
|
||||||
|
StyleClass = input.BankStyleClass,
|
||||||
});
|
});
|
||||||
|
|
||||||
entity.WorkHoursJson = JsonSerializer.Serialize(new WorkHoursDto
|
entity.WorkHoursJson = JsonSerializer.Serialize(new WorkHoursDto
|
||||||
|
|
@ -535,6 +559,7 @@ public class PublicAppService : PlatformAppService
|
||||||
Weekday = input.WorkWeekdayKey,
|
Weekday = input.WorkWeekdayKey,
|
||||||
Weekend = input.WorkWeekendKey,
|
Weekend = input.WorkWeekendKey,
|
||||||
Whatsapp = input.WorkWhatsappKey,
|
Whatsapp = input.WorkWhatsappKey,
|
||||||
|
StyleClass = input.WorkHoursStyleClass,
|
||||||
});
|
});
|
||||||
|
|
||||||
entity.MapJson = JsonSerializer.Serialize(new MapDto
|
entity.MapJson = JsonSerializer.Serialize(new MapDto
|
||||||
|
|
@ -546,6 +571,8 @@ public class PublicAppService : PlatformAppService
|
||||||
AllowFullScreen = input.MapAllowFullScreen,
|
AllowFullScreen = input.MapAllowFullScreen,
|
||||||
Loading = input.MapLoading,
|
Loading = input.MapLoading,
|
||||||
ReferrerPolicy = input.MapReferrerPolicy,
|
ReferrerPolicy = input.MapReferrerPolicy,
|
||||||
|
ContainerStyleClass = input.MapContainerStyleClass,
|
||||||
|
FrameStyleClass = input.MapFrameStyleClass,
|
||||||
});
|
});
|
||||||
|
|
||||||
await _contactRepository.UpdateAsync(entity, autoSave: false);
|
await _contactRepository.UpdateAsync(entity, autoSave: false);
|
||||||
|
|
@ -562,6 +589,11 @@ public class PublicAppService : PlatformAppService
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.WorkWhatsappKey, input.WorkWhatsappValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.WorkWhatsappKey, input.WorkWhatsappValue);
|
||||||
await UpsertLanguageTextAsync(input.CultureName, input.MapTitleKey, input.MapTitleValue);
|
await UpsertLanguageTextAsync(input.CultureName, input.MapTitleKey, input.MapTitleValue);
|
||||||
|
|
||||||
|
foreach (var styleText in input.StyleTexts)
|
||||||
|
{
|
||||||
|
await UpsertLanguageTextAsync(input.CultureName, styleText.Key, styleText.Value);
|
||||||
|
}
|
||||||
|
|
||||||
await CurrentUnitOfWork!.SaveChangesAsync();
|
await CurrentUnitOfWork!.SaveChangesAsync();
|
||||||
await _languageTextAppService.ClearRedisCacheAsync();
|
await _languageTextAppService.ClearRedisCacheAsync();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,5 @@ public class BankDto
|
||||||
public string Branch { get; set; }
|
public string Branch { get; set; }
|
||||||
public string AccountNumber { get; set; }
|
public string AccountNumber { get; set; }
|
||||||
public string Iban { get; set; }
|
public string Iban { get; set; }
|
||||||
|
public string StyleClass { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ public class MapDto
|
||||||
public string Width { get; set; }
|
public string Width { get; set; }
|
||||||
public string Height { get; set; }
|
public string Height { get; set; }
|
||||||
public string Style { get; set; }
|
public string Style { get; set; }
|
||||||
|
public string ContainerStyleClass { get; set; }
|
||||||
|
public string FrameStyleClass { get; set; }
|
||||||
public bool? AllowFullScreen { get; set; }
|
public bool? AllowFullScreen { get; set; }
|
||||||
public string Loading { get; set; }
|
public string Loading { get; set; }
|
||||||
public string ReferrerPolicy { get; set; }
|
public string ReferrerPolicy { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,5 @@ public class WorkHoursDto
|
||||||
public string Weekday { get; set; }
|
public string Weekday { get; set; }
|
||||||
public string Weekend { get; set; }
|
public string Weekend { get; set; }
|
||||||
public string Whatsapp { get; set; }
|
public string Whatsapp { get; set; }
|
||||||
|
public string StyleClass { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
|
||||||
namespace Sozsoft.Platform.Migrations
|
namespace Sozsoft.Platform.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(PlatformDbContext))]
|
[DbContext(typeof(PlatformDbContext))]
|
||||||
[Migration("20260317104139_Initial")]
|
[Migration("20260317120000_Initial")]
|
||||||
partial class Initial
|
partial class Initial
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -15,12 +15,14 @@ export interface BankDto {
|
||||||
branch: string
|
branch: string
|
||||||
accountNumber: string
|
accountNumber: string
|
||||||
iban: string
|
iban: string
|
||||||
|
styleClass?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WorkHoursDto {
|
export interface WorkHoursDto {
|
||||||
weekday: string
|
weekday: string
|
||||||
weekend: string
|
weekend: string
|
||||||
whatsapp: string
|
whatsapp: string
|
||||||
|
styleClass?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MapDto {
|
export interface MapDto {
|
||||||
|
|
@ -28,6 +30,9 @@ export interface MapDto {
|
||||||
src: string
|
src: string
|
||||||
width: string
|
width: string
|
||||||
height: string
|
height: string
|
||||||
|
style?: string
|
||||||
|
containerStyleClass?: string
|
||||||
|
frameStyleClass?: string
|
||||||
allowFullScreen?: boolean
|
allowFullScreen?: boolean
|
||||||
loading: string
|
loading: string
|
||||||
referrerPolicy: string
|
referrerPolicy: string
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ export interface SaveAboutPageInput {
|
||||||
stats: SaveAboutStatInput[]
|
stats: SaveAboutStatInput[]
|
||||||
descriptions: SaveLocalizedTextInput[]
|
descriptions: SaveLocalizedTextInput[]
|
||||||
sections: SaveAboutSectionInput[]
|
sections: SaveAboutSectionInput[]
|
||||||
|
styleTexts: SaveLocalizedTextInput[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAbout() {
|
export function getAbout() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import apiService from './api.service'
|
import apiService from './api.service'
|
||||||
import { ContactDto } from '@/proxy/contact/models'
|
import { ContactDto } from '@/proxy/contact/models'
|
||||||
|
|
||||||
|
export interface SaveLocalizedTextInput {
|
||||||
|
key: string
|
||||||
|
value: string
|
||||||
|
}
|
||||||
|
|
||||||
export function getContact() {
|
export function getContact() {
|
||||||
return apiService.fetchData<ContactDto>(
|
return apiService.fetchData<ContactDto>(
|
||||||
{
|
{
|
||||||
|
|
@ -33,6 +38,7 @@ export interface SaveContactPageInput extends Record<string, unknown> {
|
||||||
bankBranch: string
|
bankBranch: string
|
||||||
bankAccountNumber: string
|
bankAccountNumber: string
|
||||||
bankIban: string
|
bankIban: string
|
||||||
|
bankStyleClass: string
|
||||||
workHoursTitleKey: string
|
workHoursTitleKey: string
|
||||||
workHoursTitleValue: string
|
workHoursTitleValue: string
|
||||||
workWeekdayKey: string
|
workWeekdayKey: string
|
||||||
|
|
@ -41,6 +47,7 @@ export interface SaveContactPageInput extends Record<string, unknown> {
|
||||||
workWeekendValue: string
|
workWeekendValue: string
|
||||||
workWhatsappKey: string
|
workWhatsappKey: string
|
||||||
workWhatsappValue: string
|
workWhatsappValue: string
|
||||||
|
workHoursStyleClass: string
|
||||||
mapTitleKey: string
|
mapTitleKey: string
|
||||||
mapTitleValue: string
|
mapTitleValue: string
|
||||||
mapSrc: string
|
mapSrc: string
|
||||||
|
|
@ -49,6 +56,9 @@ export interface SaveContactPageInput extends Record<string, unknown> {
|
||||||
mapAllowFullScreen: boolean
|
mapAllowFullScreen: boolean
|
||||||
mapLoading: string
|
mapLoading: string
|
||||||
mapReferrerPolicy: string
|
mapReferrerPolicy: string
|
||||||
|
mapContainerStyleClass: string
|
||||||
|
mapFrameStyleClass: string
|
||||||
|
styleTexts: SaveLocalizedTextInput[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveContactPage(input: SaveContactPageInput) {
|
export function saveContactPage(input: SaveContactPageInput) {
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,13 @@ export interface HomeSlideServiceDto {
|
||||||
icon: string
|
icon: string
|
||||||
titleKey: string
|
titleKey: string
|
||||||
descriptionKey: string
|
descriptionKey: string
|
||||||
|
styleClass?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HomeSlideDto {
|
export interface HomeSlideDto {
|
||||||
titleKey: string
|
titleKey: string
|
||||||
subtitleKey: string
|
subtitleKey: string
|
||||||
|
styleClass?: string
|
||||||
services: HomeSlideServiceDto[]
|
services: HomeSlideServiceDto[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -16,6 +18,7 @@ export interface HomeFeatureDto {
|
||||||
icon: string
|
icon: string
|
||||||
titleKey: string
|
titleKey: string
|
||||||
descriptionKey: string
|
descriptionKey: string
|
||||||
|
styleClass?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HomeSolutionDto {
|
export interface HomeSolutionDto {
|
||||||
|
|
@ -23,6 +26,7 @@ export interface HomeSolutionDto {
|
||||||
colorClass: string
|
colorClass: string
|
||||||
titleKey: string
|
titleKey: string
|
||||||
descriptionKey: string
|
descriptionKey: string
|
||||||
|
styleClass?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HomeDto {
|
export interface HomeDto {
|
||||||
|
|
@ -48,6 +52,7 @@ export interface SaveHomeSlideServiceInput {
|
||||||
titleValue: string
|
titleValue: string
|
||||||
descriptionKey: string
|
descriptionKey: string
|
||||||
descriptionValue: string
|
descriptionValue: string
|
||||||
|
styleClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SaveHomeSlideInput {
|
export interface SaveHomeSlideInput {
|
||||||
|
|
@ -55,6 +60,7 @@ export interface SaveHomeSlideInput {
|
||||||
titleValue: string
|
titleValue: string
|
||||||
subtitleKey: string
|
subtitleKey: string
|
||||||
subtitleValue: string
|
subtitleValue: string
|
||||||
|
styleClass: string
|
||||||
services: SaveHomeSlideServiceInput[]
|
services: SaveHomeSlideServiceInput[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,6 +70,7 @@ export interface SaveHomeFeatureInput {
|
||||||
titleValue: string
|
titleValue: string
|
||||||
descriptionKey: string
|
descriptionKey: string
|
||||||
descriptionValue: string
|
descriptionValue: string
|
||||||
|
styleClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SaveHomeSolutionInput {
|
export interface SaveHomeSolutionInput {
|
||||||
|
|
@ -73,6 +80,7 @@ export interface SaveHomeSolutionInput {
|
||||||
titleValue: string
|
titleValue: string
|
||||||
descriptionKey: string
|
descriptionKey: string
|
||||||
descriptionValue: string
|
descriptionValue: string
|
||||||
|
styleClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SaveHomePageInput {
|
export interface SaveHomePageInput {
|
||||||
|
|
@ -81,22 +89,40 @@ export interface SaveHomePageInput {
|
||||||
heroBackgroundImageValue: string
|
heroBackgroundImageValue: string
|
||||||
heroPrimaryCtaKey: string
|
heroPrimaryCtaKey: string
|
||||||
heroPrimaryCtaValue: string
|
heroPrimaryCtaValue: string
|
||||||
|
heroPrimaryCtaStyleKey: string
|
||||||
|
heroPrimaryCtaStyleValue: string
|
||||||
heroSecondaryCtaKey: string
|
heroSecondaryCtaKey: string
|
||||||
heroSecondaryCtaValue: string
|
heroSecondaryCtaValue: string
|
||||||
|
heroSecondaryCtaStyleKey: string
|
||||||
|
heroSecondaryCtaStyleValue: string
|
||||||
featuresTitleKey: string
|
featuresTitleKey: string
|
||||||
featuresTitleValue: string
|
featuresTitleValue: string
|
||||||
|
featuresTitleStyleKey: string
|
||||||
|
featuresTitleStyleValue: string
|
||||||
featuresSubtitleKey: string
|
featuresSubtitleKey: string
|
||||||
featuresSubtitleValue: string
|
featuresSubtitleValue: string
|
||||||
|
featuresSubtitleStyleKey: string
|
||||||
|
featuresSubtitleStyleValue: string
|
||||||
solutionsTitleKey: string
|
solutionsTitleKey: string
|
||||||
solutionsTitleValue: string
|
solutionsTitleValue: string
|
||||||
|
solutionsTitleStyleKey: string
|
||||||
|
solutionsTitleStyleValue: string
|
||||||
solutionsSubtitleKey: string
|
solutionsSubtitleKey: string
|
||||||
solutionsSubtitleValue: string
|
solutionsSubtitleValue: string
|
||||||
|
solutionsSubtitleStyleKey: string
|
||||||
|
solutionsSubtitleStyleValue: string
|
||||||
ctaTitleKey: string
|
ctaTitleKey: string
|
||||||
ctaTitleValue: string
|
ctaTitleValue: string
|
||||||
|
ctaTitleStyleKey: string
|
||||||
|
ctaTitleStyleValue: string
|
||||||
ctaSubtitleKey: string
|
ctaSubtitleKey: string
|
||||||
ctaSubtitleValue: string
|
ctaSubtitleValue: string
|
||||||
|
ctaSubtitleStyleKey: string
|
||||||
|
ctaSubtitleStyleValue: string
|
||||||
ctaButtonLabelKey: string
|
ctaButtonLabelKey: string
|
||||||
ctaButtonLabelValue: string
|
ctaButtonLabelValue: string
|
||||||
|
ctaButtonStyleKey: string
|
||||||
|
ctaButtonStyleValue: string
|
||||||
slides: SaveHomeSlideInput[]
|
slides: SaveHomeSlideInput[]
|
||||||
features: SaveHomeFeatureInput[]
|
features: SaveHomeFeatureInput[]
|
||||||
solutions: SaveHomeSolutionInput[]
|
solutions: SaveHomeSolutionInput[]
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ export interface SaveServicesPageInput {
|
||||||
ctaButtonLabelValue: string
|
ctaButtonLabelValue: string
|
||||||
serviceItems: SaveServiceItemInput[]
|
serviceItems: SaveServiceItemInput[]
|
||||||
supportItems: SaveServiceItemInput[]
|
supportItems: SaveServiceItemInput[]
|
||||||
|
styleTexts: SaveLocalizedTextInput[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getServices() {
|
export function getServices() {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import { APP_NAME } from '@/constants/app.constant'
|
||||||
import { Notification, toast } from '@/components/ui'
|
import { Notification, toast } from '@/components/ui'
|
||||||
import { useStoreState } from '@/store'
|
import { useStoreState } from '@/store'
|
||||||
import { useStoreActions } from '@/store'
|
import { useStoreActions } from '@/store'
|
||||||
import { useNavigate } from 'react-router-dom'
|
|
||||||
import DesignerDrawer from './designer/DesignerDrawer'
|
import DesignerDrawer from './designer/DesignerDrawer'
|
||||||
import SelectableBlock from './designer/SelectableBlock'
|
import SelectableBlock from './designer/SelectableBlock'
|
||||||
import { DesignerSelection } from './designer/types'
|
import { DesignerSelection } from './designer/types'
|
||||||
|
|
@ -20,6 +19,12 @@ interface AboutStatContent {
|
||||||
value: string
|
value: string
|
||||||
label: string
|
label: string
|
||||||
labelKey: string
|
labelKey: string
|
||||||
|
styleClassKey: string
|
||||||
|
styleClass: string
|
||||||
|
valueStyleClassKey: string
|
||||||
|
valueStyleClass: string
|
||||||
|
labelStyleClassKey: string
|
||||||
|
labelStyleClass: string
|
||||||
useCounter?: boolean
|
useCounter?: boolean
|
||||||
counterEnd?: string
|
counterEnd?: string
|
||||||
counterSuffix?: string
|
counterSuffix?: string
|
||||||
|
|
@ -29,6 +34,8 @@ interface AboutStatContent {
|
||||||
interface AboutDescriptionContent {
|
interface AboutDescriptionContent {
|
||||||
key: string
|
key: string
|
||||||
text: string
|
text: string
|
||||||
|
styleClassKey: string
|
||||||
|
styleClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AboutSectionContent {
|
interface AboutSectionContent {
|
||||||
|
|
@ -36,15 +43,29 @@ interface AboutSectionContent {
|
||||||
description: string
|
description: string
|
||||||
titleKey: string
|
titleKey: string
|
||||||
descriptionKey: string
|
descriptionKey: string
|
||||||
|
cardStyleClassKey: string
|
||||||
|
cardStyleClass: string
|
||||||
|
titleStyleClassKey: string
|
||||||
|
titleStyleClass: string
|
||||||
|
descriptionStyleClassKey: string
|
||||||
|
descriptionStyleClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AboutContent {
|
interface AboutContent {
|
||||||
heroTitle: string
|
heroTitle: string
|
||||||
heroTitleKey: string
|
heroTitleKey: string
|
||||||
|
heroTitleStyleClassKey: string
|
||||||
|
heroTitleStyleClass: string
|
||||||
heroSubtitle: string
|
heroSubtitle: string
|
||||||
heroSubtitleKey: string
|
heroSubtitleKey: string
|
||||||
|
heroSubtitleStyleClassKey: string
|
||||||
|
heroSubtitleStyleClass: string
|
||||||
heroImage: string
|
heroImage: string
|
||||||
heroImageKey: string
|
heroImageKey: string
|
||||||
|
heroSectionStyleClassKey: string
|
||||||
|
heroSectionStyleClass: string
|
||||||
|
descriptionsContainerStyleClassKey: string
|
||||||
|
descriptionsContainerStyleClass: string
|
||||||
stats: AboutStatContent[]
|
stats: AboutStatContent[]
|
||||||
descriptions: AboutDescriptionContent[]
|
descriptions: AboutDescriptionContent[]
|
||||||
sections: AboutSectionContent[]
|
sections: AboutSectionContent[]
|
||||||
|
|
@ -55,6 +76,10 @@ const ABOUT_HERO_IMAGE =
|
||||||
const ABOUT_HERO_TITLE_KEY = 'App.About'
|
const ABOUT_HERO_TITLE_KEY = 'App.About'
|
||||||
const ABOUT_HERO_SUBTITLE_KEY = 'Public.about.subtitle'
|
const ABOUT_HERO_SUBTITLE_KEY = 'Public.about.subtitle'
|
||||||
const ABOUT_HERO_IMAGE_KEY = 'Public.about.heroImage'
|
const ABOUT_HERO_IMAGE_KEY = 'Public.about.heroImage'
|
||||||
|
const ABOUT_HERO_SECTION_STYLE_KEY = 'Public.about.hero.sectionStyleClass'
|
||||||
|
const ABOUT_HERO_TITLE_STYLE_KEY = 'Public.about.hero.titleStyleClass'
|
||||||
|
const ABOUT_HERO_SUBTITLE_STYLE_KEY = 'Public.about.hero.subtitleStyleClass'
|
||||||
|
const ABOUT_DESCRIPTIONS_CONTAINER_STYLE_KEY = 'Public.about.descriptions.containerStyleClass'
|
||||||
|
|
||||||
function isLikelyLocalizationKey(value?: string) {
|
function isLikelyLocalizationKey(value?: string) {
|
||||||
return Boolean(value && /^[A-Za-z0-9_.-]+$/.test(value) && value.includes('.'))
|
return Boolean(value && /^[A-Za-z0-9_.-]+$/.test(value) && value.includes('.'))
|
||||||
|
|
@ -84,18 +109,60 @@ function buildAboutContent(
|
||||||
return {
|
return {
|
||||||
heroTitle: resolveLocalizedValue(translate, ABOUT_HERO_TITLE_KEY, 'About'),
|
heroTitle: resolveLocalizedValue(translate, ABOUT_HERO_TITLE_KEY, 'About'),
|
||||||
heroTitleKey: ABOUT_HERO_TITLE_KEY,
|
heroTitleKey: ABOUT_HERO_TITLE_KEY,
|
||||||
|
heroTitleStyleClassKey: ABOUT_HERO_TITLE_STYLE_KEY,
|
||||||
|
heroTitleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
ABOUT_HERO_TITLE_STYLE_KEY,
|
||||||
|
'text-5xl font-bold ml-4 mt-3 mb-2 text-white',
|
||||||
|
),
|
||||||
heroSubtitle: resolveLocalizedValue(translate, ABOUT_HERO_SUBTITLE_KEY),
|
heroSubtitle: resolveLocalizedValue(translate, ABOUT_HERO_SUBTITLE_KEY),
|
||||||
heroSubtitleKey: ABOUT_HERO_SUBTITLE_KEY,
|
heroSubtitleKey: ABOUT_HERO_SUBTITLE_KEY,
|
||||||
|
heroSubtitleStyleClassKey: ABOUT_HERO_SUBTITLE_STYLE_KEY,
|
||||||
|
heroSubtitleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
ABOUT_HERO_SUBTITLE_STYLE_KEY,
|
||||||
|
'text-xl max-w-3xl ml-4',
|
||||||
|
),
|
||||||
heroImage: resolveLocalizedValue(translate, ABOUT_HERO_IMAGE_KEY, ABOUT_HERO_IMAGE),
|
heroImage: resolveLocalizedValue(translate, ABOUT_HERO_IMAGE_KEY, ABOUT_HERO_IMAGE),
|
||||||
heroImageKey: ABOUT_HERO_IMAGE_KEY,
|
heroImageKey: ABOUT_HERO_IMAGE_KEY,
|
||||||
|
heroSectionStyleClassKey: ABOUT_HERO_SECTION_STYLE_KEY,
|
||||||
|
heroSectionStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
ABOUT_HERO_SECTION_STYLE_KEY,
|
||||||
|
'relative bg-blue-900 text-white py-12',
|
||||||
|
),
|
||||||
|
descriptionsContainerStyleClassKey: ABOUT_DESCRIPTIONS_CONTAINER_STYLE_KEY,
|
||||||
|
descriptionsContainerStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
ABOUT_DESCRIPTIONS_CONTAINER_STYLE_KEY,
|
||||||
|
'p-5 mx-auto text-gray-800 text-lg leading-relaxed shadow-md bg-white border-l-4 border-blue-600',
|
||||||
|
),
|
||||||
stats:
|
stats:
|
||||||
about?.statsDto.map((stat) => ({
|
about?.statsDto.map((stat, index) => ({
|
||||||
|
styleClassKey: `Public.about.dynamic.stat.${index + 1}.styleClass`,
|
||||||
|
styleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.about.dynamic.stat.${index + 1}.styleClass`,
|
||||||
|
'text-center rounded-xl px-4 py-6',
|
||||||
|
),
|
||||||
|
valueStyleClassKey: `Public.about.dynamic.stat.${index + 1}.valueStyleClass`,
|
||||||
|
valueStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.about.dynamic.stat.${index + 1}.valueStyleClass`,
|
||||||
|
'text-4xl font-bold text-gray-900 mb-2',
|
||||||
|
),
|
||||||
|
labelStyleClassKey: `Public.about.dynamic.stat.${index + 1}.labelStyleClass`,
|
||||||
|
labelStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.about.dynamic.stat.${index + 1}.labelStyleClass`,
|
||||||
|
'text-gray-600',
|
||||||
|
),
|
||||||
icon: stat.icon || '',
|
icon: stat.icon || '',
|
||||||
value: stat.value,
|
value: stat.value,
|
||||||
label: resolveLocalizedValue(translate, stat.labelKey, stat.labelKey),
|
label: resolveLocalizedValue(translate, stat.labelKey, stat.labelKey),
|
||||||
labelKey:
|
labelKey:
|
||||||
(isLikelyLocalizationKey(stat.labelKey) ? stat.labelKey : undefined) ||
|
(isLikelyLocalizationKey(stat.labelKey) ? stat.labelKey : undefined) ||
|
||||||
`Public.about.dynamic.stat.${stat.value}.label`,
|
`Public.about.dynamic.stat.${index + 1}.label`,
|
||||||
useCounter: stat.useCounter,
|
useCounter: stat.useCounter,
|
||||||
counterEnd: stat.counterEnd,
|
counterEnd: stat.counterEnd,
|
||||||
counterSuffix: stat.counterSuffix,
|
counterSuffix: stat.counterSuffix,
|
||||||
|
|
@ -107,6 +174,12 @@ function buildAboutContent(
|
||||||
(isLikelyLocalizationKey(item) ? item : undefined) ||
|
(isLikelyLocalizationKey(item) ? item : undefined) ||
|
||||||
`Public.about.dynamic.description.${index + 1}`,
|
`Public.about.dynamic.description.${index + 1}`,
|
||||||
text: resolveLocalizedValue(translate, item, item),
|
text: resolveLocalizedValue(translate, item, item),
|
||||||
|
styleClassKey: `Public.about.dynamic.description.${index + 1}.styleClass`,
|
||||||
|
styleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.about.dynamic.description.${index + 1}.styleClass`,
|
||||||
|
index % 2 === 0 ? '' : 'text-center p-5 text-blue-800',
|
||||||
|
),
|
||||||
})) ?? [],
|
})) ?? [],
|
||||||
sections:
|
sections:
|
||||||
about?.sectionsDto.map((section) => ({
|
about?.sectionsDto.map((section) => ({
|
||||||
|
|
@ -118,13 +191,30 @@ function buildAboutContent(
|
||||||
descriptionKey:
|
descriptionKey:
|
||||||
(isLikelyLocalizationKey(section.descKey) ? section.descKey : undefined) ||
|
(isLikelyLocalizationKey(section.descKey) ? section.descKey : undefined) ||
|
||||||
`Public.about.dynamic.section.${section.key}.description`,
|
`Public.about.dynamic.section.${section.key}.description`,
|
||||||
|
cardStyleClassKey: `Public.about.dynamic.section.${section.key}.cardStyleClass`,
|
||||||
|
cardStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.about.dynamic.section.${section.key}.cardStyleClass`,
|
||||||
|
'bg-white p-8 rounded-xl shadow-lg',
|
||||||
|
),
|
||||||
|
titleStyleClassKey: `Public.about.dynamic.section.${section.key}.titleStyleClass`,
|
||||||
|
titleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.about.dynamic.section.${section.key}.titleStyleClass`,
|
||||||
|
'text-2xl font-bold text-gray-900 mb-4',
|
||||||
|
),
|
||||||
|
descriptionStyleClassKey: `Public.about.dynamic.section.${section.key}.descriptionStyleClass`,
|
||||||
|
descriptionStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.about.dynamic.section.${section.key}.descriptionStyleClass`,
|
||||||
|
'text-gray-700',
|
||||||
|
),
|
||||||
})) ?? [],
|
})) ?? [],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const About: React.FC = () => {
|
const About: React.FC = () => {
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
const navigate = useNavigate()
|
|
||||||
const { setLang } = useStoreActions((actions) => actions.locale)
|
const { setLang } = useStoreActions((actions) => actions.locale)
|
||||||
const { getConfig } = useStoreActions((actions) => actions.abpConfig)
|
const { getConfig } = useStoreActions((actions) => actions.abpConfig)
|
||||||
const configCultureName = useStoreState(
|
const configCultureName = useStoreState(
|
||||||
|
|
@ -207,7 +297,15 @@ const About: React.FC = () => {
|
||||||
|
|
||||||
const handleFieldChange = (fieldKey: string, value: string | string[]) => {
|
const handleFieldChange = (fieldKey: string, value: string | string[]) => {
|
||||||
updateContent((current) => {
|
updateContent((current) => {
|
||||||
if (fieldKey === 'heroTitle' || fieldKey === 'heroSubtitle' || fieldKey === 'heroImage') {
|
if (
|
||||||
|
fieldKey === 'heroTitle' ||
|
||||||
|
fieldKey === 'heroSubtitle' ||
|
||||||
|
fieldKey === 'heroImage' ||
|
||||||
|
fieldKey === 'heroSectionStyleClass' ||
|
||||||
|
fieldKey === 'heroTitleStyleClass' ||
|
||||||
|
fieldKey === 'heroSubtitleStyleClass' ||
|
||||||
|
fieldKey === 'descriptionsContainerStyleClass'
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
...current,
|
...current,
|
||||||
[fieldKey]: value as string,
|
[fieldKey]: value as string,
|
||||||
|
|
@ -228,6 +326,20 @@ const About: React.FC = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fieldKey.startsWith('descriptionStyle-')) {
|
||||||
|
const index = Number(fieldKey.replace('descriptionStyle-', ''))
|
||||||
|
const descriptions = [...current.descriptions]
|
||||||
|
descriptions[index] = {
|
||||||
|
...descriptions[index],
|
||||||
|
styleClass: value as string,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...current,
|
||||||
|
descriptions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedBlockId?.startsWith('stat-')) {
|
if (selectedBlockId?.startsWith('stat-')) {
|
||||||
const index = Number(selectedBlockId.replace('stat-', ''))
|
const index = Number(selectedBlockId.replace('stat-', ''))
|
||||||
const stats = [...current.stats]
|
const stats = [...current.stats]
|
||||||
|
|
@ -277,18 +389,36 @@ const About: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.heroTitle,
|
value: content.heroTitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroTitleStyleClass',
|
||||||
|
label: content.heroTitleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroTitleStyleClass,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'heroSubtitle',
|
key: 'heroSubtitle',
|
||||||
label: content.heroSubtitleKey,
|
label: content.heroSubtitleKey,
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: content.heroSubtitle,
|
value: content.heroSubtitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroSubtitleStyleClass',
|
||||||
|
label: content.heroSubtitleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroSubtitleStyleClass,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'heroImage',
|
key: 'heroImage',
|
||||||
label: content.heroImageKey,
|
label: content.heroImageKey,
|
||||||
type: 'image',
|
type: 'image',
|
||||||
value: content.heroImage,
|
value: content.heroImage,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroSectionStyleClass',
|
||||||
|
label: content.heroSectionStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroSectionStyleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -298,13 +428,29 @@ const About: React.FC = () => {
|
||||||
id: 'descriptions',
|
id: 'descriptions',
|
||||||
title: 'Public.about.description.*',
|
title: 'Public.about.description.*',
|
||||||
description: 'Orta bolumdeki aciklama metinlerini duzenleyin.',
|
description: 'Orta bolumdeki aciklama metinlerini duzenleyin.',
|
||||||
fields: content.descriptions.map((item, index) => ({
|
fields: [
|
||||||
|
{
|
||||||
|
key: 'descriptionsContainerStyleClass',
|
||||||
|
label: content.descriptionsContainerStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.descriptionsContainerStyleClass,
|
||||||
|
},
|
||||||
|
...content.descriptions.flatMap((item, index) => [
|
||||||
|
{
|
||||||
key: `description-${index}`,
|
key: `description-${index}`,
|
||||||
label: item.key || `Public.about.dynamic.description.${index + 1}`,
|
label: item.key || `Public.about.dynamic.description.${index + 1}`,
|
||||||
type: 'textarea',
|
type: 'textarea' as const,
|
||||||
value: item.text,
|
value: item.text,
|
||||||
rows: index % 2 === 0 ? 4 : 3,
|
rows: index % 2 === 0 ? 4 : 3,
|
||||||
})),
|
},
|
||||||
|
{
|
||||||
|
key: `descriptionStyle-${index}`,
|
||||||
|
label: item.styleClassKey,
|
||||||
|
type: 'text' as const,
|
||||||
|
value: item.styleClass,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -340,6 +486,24 @@ const About: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: stat.label,
|
value: stat.label,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'styleClass',
|
||||||
|
label: stat.styleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: stat.styleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'valueStyleClass',
|
||||||
|
label: stat.valueStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: stat.valueStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'labelStyleClass',
|
||||||
|
label: stat.labelStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: stat.labelStyleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -369,6 +533,24 @@ const About: React.FC = () => {
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: section.description,
|
value: section.description,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'cardStyleClass',
|
||||||
|
label: section.cardStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: section.cardStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'titleStyleClass',
|
||||||
|
label: section.titleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: section.titleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'descriptionStyleClass',
|
||||||
|
label: section.descriptionStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: section.descriptionStyleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -413,6 +595,56 @@ const About: React.FC = () => {
|
||||||
section.descriptionKey || `Public.about.dynamic.section.${index + 1}.description`,
|
section.descriptionKey || `Public.about.dynamic.section.${index + 1}.description`,
|
||||||
descriptionValue: section.description,
|
descriptionValue: section.description,
|
||||||
})),
|
})),
|
||||||
|
styleTexts: [
|
||||||
|
{
|
||||||
|
key: content.heroSectionStyleClassKey,
|
||||||
|
value: content.heroSectionStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.heroTitleStyleClassKey,
|
||||||
|
value: content.heroTitleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.heroSubtitleStyleClassKey,
|
||||||
|
value: content.heroSubtitleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.descriptionsContainerStyleClassKey,
|
||||||
|
value: content.descriptionsContainerStyleClass,
|
||||||
|
},
|
||||||
|
...content.stats.flatMap((stat) => [
|
||||||
|
{
|
||||||
|
key: stat.styleClassKey,
|
||||||
|
value: stat.styleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: stat.valueStyleClassKey,
|
||||||
|
value: stat.valueStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: stat.labelStyleClassKey,
|
||||||
|
value: stat.labelStyleClass,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
...content.descriptions.map((item) => ({
|
||||||
|
key: item.styleClassKey,
|
||||||
|
value: item.styleClass,
|
||||||
|
})),
|
||||||
|
...content.sections.flatMap((section) => [
|
||||||
|
{
|
||||||
|
key: section.cardStyleClassKey,
|
||||||
|
value: section.cardStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: section.titleStyleClassKey,
|
||||||
|
value: section.titleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: section.descriptionStyleClassKey,
|
||||||
|
value: section.descriptionStyleClass,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
await getConfig(false)
|
await getConfig(false)
|
||||||
|
|
@ -483,7 +715,7 @@ const About: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="relative bg-blue-900 text-white py-12">
|
<div className={content?.heroSectionStyleClass || 'relative bg-blue-900 text-white py-12'}>
|
||||||
<div
|
<div
|
||||||
className="absolute inset-0 opacity-20"
|
className="absolute inset-0 opacity-20"
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -493,10 +725,10 @@ const About: React.FC = () => {
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
<div className="container mx-auto pt-20 relative">
|
<div className="container mx-auto pt-20 relative">
|
||||||
<h1 className="text-5xl font-bold ml-4 mt-3 mb-2 text-white">
|
<h1 className={content?.heroTitleStyleClass || 'text-5xl font-bold ml-4 mt-3 mb-2 text-white'}>
|
||||||
{content?.heroTitle}
|
{content?.heroTitle}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-xl max-w-3xl ml-4">{content?.heroSubtitle}</p>
|
<p className={content?.heroSubtitleStyleClass || 'text-xl max-w-3xl ml-4'}>{content?.heroSubtitle}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SelectableBlock>
|
</SelectableBlock>
|
||||||
|
|
@ -516,14 +748,14 @@ const About: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="text-center rounded-xl px-4 py-6">
|
<div className={stat.styleClass || 'text-center rounded-xl px-4 py-6'}>
|
||||||
{IconComponent && (
|
{IconComponent && (
|
||||||
<IconComponent
|
<IconComponent
|
||||||
className={`w-12 h-12 mx-auto mb-4 ${getIconColor(index)}`}
|
className={`w-12 h-12 mx-auto mb-4 ${getIconColor(index)}`}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="text-4xl font-bold text-gray-900 mb-2">{stat.value}</div>
|
<div className={stat.valueStyleClass || 'text-4xl font-bold text-gray-900 mb-2'}>{stat.value}</div>
|
||||||
<div className="text-gray-600">{stat.label}</div>
|
<div className={stat.labelStyleClass || 'text-gray-600'}>{stat.label}</div>
|
||||||
</div>
|
</div>
|
||||||
</SelectableBlock>
|
</SelectableBlock>
|
||||||
)
|
)
|
||||||
|
|
@ -542,11 +774,12 @@ const About: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="p-5 mx-auto mx-auto text-gray-800 text-lg leading-relaxed shadow-md bg-white border-l-4 border-blue-600">
|
<div className={content?.descriptionsContainerStyleClass || 'p-5 mx-auto text-gray-800 text-lg leading-relaxed shadow-md bg-white border-l-4 border-blue-600'}>
|
||||||
<p>{content?.descriptions[0]?.text}</p>
|
{content?.descriptions.map((item, index) => (
|
||||||
<p className="text-center p-5 text-blue-800">{content?.descriptions[1]?.text}</p>
|
<p key={item.key || `description-${index}`} className={item.styleClass || ''}>
|
||||||
<p>{content?.descriptions[2]?.text}</p>
|
{item.text}
|
||||||
<p className="text-center p-5 text-blue-800">{content?.descriptions[3]?.text}</p>
|
</p>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</SelectableBlock>
|
</SelectableBlock>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -560,9 +793,9 @@ const About: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="bg-white p-8 rounded-xl shadow-lg">
|
<div className={section.cardStyleClass || 'bg-white p-8 rounded-xl shadow-lg'}>
|
||||||
<h3 className="text-2xl font-bold text-gray-900 mb-4">{section.title}</h3>
|
<h3 className={section.titleStyleClass || 'text-2xl font-bold text-gray-900 mb-4'}>{section.title}</h3>
|
||||||
<p className="text-gray-700">{section.description}</p>
|
<p className={section.descriptionStyleClass || 'text-gray-700'}>{section.description}</p>
|
||||||
</div>
|
</div>
|
||||||
</SelectableBlock>
|
</SelectableBlock>
|
||||||
))}
|
))}
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,22 @@ import { Notification, toast } from '@/components/ui'
|
||||||
interface ContactContent {
|
interface ContactContent {
|
||||||
heroTitle: string
|
heroTitle: string
|
||||||
heroTitleKey: string
|
heroTitleKey: string
|
||||||
|
heroSectionStyleClass: string
|
||||||
|
heroSectionStyleClassKey: string
|
||||||
|
heroTitleStyleClass: string
|
||||||
|
heroTitleStyleClassKey: string
|
||||||
heroSubtitle: string
|
heroSubtitle: string
|
||||||
heroSubtitleKey: string
|
heroSubtitleKey: string
|
||||||
|
heroSubtitleStyleClass: string
|
||||||
|
heroSubtitleStyleClassKey: string
|
||||||
heroImage: string
|
heroImage: string
|
||||||
heroImageKey: string
|
heroImageKey: string
|
||||||
contactInfoTitle: string
|
contactInfoTitle: string
|
||||||
contactInfoTitleKey: string
|
contactInfoTitleKey: string
|
||||||
|
contactInfoCardStyleClass: string
|
||||||
|
contactInfoCardStyleClassKey: string
|
||||||
|
contactInfoTitleStyleClass: string
|
||||||
|
contactInfoTitleStyleClassKey: string
|
||||||
address: string
|
address: string
|
||||||
addressKey: string
|
addressKey: string
|
||||||
phoneNumber: string
|
phoneNumber: string
|
||||||
|
|
@ -43,6 +53,7 @@ interface ContactContent {
|
||||||
bankBranch: string
|
bankBranch: string
|
||||||
bankAccountNumber: string
|
bankAccountNumber: string
|
||||||
bankIban: string
|
bankIban: string
|
||||||
|
bankStyleClass: string
|
||||||
workHoursTitle: string
|
workHoursTitle: string
|
||||||
workHoursTitleKey: string
|
workHoursTitleKey: string
|
||||||
workWeekday: string
|
workWeekday: string
|
||||||
|
|
@ -51,6 +62,7 @@ interface ContactContent {
|
||||||
workWeekendKey: string
|
workWeekendKey: string
|
||||||
workWhatsapp: string
|
workWhatsapp: string
|
||||||
workWhatsappKey: string
|
workWhatsappKey: string
|
||||||
|
workHoursStyleClass: string
|
||||||
mapTitle: string
|
mapTitle: string
|
||||||
mapTitleKey: string
|
mapTitleKey: string
|
||||||
mapSrc: string
|
mapSrc: string
|
||||||
|
|
@ -59,6 +71,8 @@ interface ContactContent {
|
||||||
mapAllowFullScreen: string
|
mapAllowFullScreen: string
|
||||||
mapLoading: string
|
mapLoading: string
|
||||||
mapReferrerPolicy: string
|
mapReferrerPolicy: string
|
||||||
|
mapContainerStyleClass: string
|
||||||
|
mapFrameStyleClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONTACT_HERO_TITLE_KEY = 'App.Contact'
|
const CONTACT_HERO_TITLE_KEY = 'App.Contact'
|
||||||
|
|
@ -67,13 +81,13 @@ const CONTACT_HERO_IMAGE_KEY = 'Public.contact.heroImage'
|
||||||
const CONTACT_HERO_IMAGE_DEFAULT =
|
const CONTACT_HERO_IMAGE_DEFAULT =
|
||||||
'https://images.pexels.com/photos/3183171/pexels-photo-3183171.jpeg?auto=compress&cs=tinysrgb&w=1920'
|
'https://images.pexels.com/photos/3183171/pexels-photo-3183171.jpeg?auto=compress&cs=tinysrgb&w=1920'
|
||||||
const CONTACT_INFO_TITLE_KEY = 'Abp.Identity.User.UserInformation.ContactInformation'
|
const CONTACT_INFO_TITLE_KEY = 'Abp.Identity.User.UserInformation.ContactInformation'
|
||||||
const CONTACT_ADDRESS_KEY = 'Public.contact.address.full'
|
|
||||||
const CONTACT_BANK_TITLE_KEY = 'Public.contact.bank.title'
|
const CONTACT_BANK_TITLE_KEY = 'Public.contact.bank.title'
|
||||||
const CONTACT_WORK_HOURS_TITLE_KEY = 'App.Definitions.WorkHour'
|
const CONTACT_WORK_HOURS_TITLE_KEY = 'App.Definitions.WorkHour'
|
||||||
const CONTACT_WORK_WEEKDAY_KEY = 'Public.contact.workHours.weekday'
|
const CONTACT_HERO_SECTION_STYLE_KEY = 'Public.contact.hero.sectionStyleClass'
|
||||||
const CONTACT_WORK_WEEKEND_KEY = 'Public.contact.workHours.weekend'
|
const CONTACT_HERO_TITLE_STYLE_KEY = 'Public.contact.hero.titleStyleClass'
|
||||||
const CONTACT_WORK_WHATSAPP_KEY = 'Public.contact.workHours.whatsapp'
|
const CONTACT_HERO_SUBTITLE_STYLE_KEY = 'Public.contact.hero.subtitleStyleClass'
|
||||||
const CONTACT_MAP_TITLE_KEY = 'Public.contact.location'
|
const CONTACT_INFO_CARD_STYLE_KEY = 'Public.contact.info.cardStyleClass'
|
||||||
|
const CONTACT_INFO_TITLE_STYLE_KEY = 'Public.contact.info.titleStyleClass'
|
||||||
|
|
||||||
function isLikelyLocalizationKey(value?: string) {
|
function isLikelyLocalizationKey(value?: string) {
|
||||||
return Boolean(value && /^[A-Za-z0-9_.-]+$/.test(value) && value.includes('.'))
|
return Boolean(value && /^[A-Za-z0-9_.-]+$/.test(value) && value.includes('.'))
|
||||||
|
|
@ -103,14 +117,44 @@ function buildContactContent(
|
||||||
return {
|
return {
|
||||||
heroTitle: resolveLocalizedValue(translate, CONTACT_HERO_TITLE_KEY, 'Contact'),
|
heroTitle: resolveLocalizedValue(translate, CONTACT_HERO_TITLE_KEY, 'Contact'),
|
||||||
heroTitleKey: CONTACT_HERO_TITLE_KEY,
|
heroTitleKey: CONTACT_HERO_TITLE_KEY,
|
||||||
|
heroSectionStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
CONTACT_HERO_SECTION_STYLE_KEY,
|
||||||
|
'relative bg-blue-900 py-12 text-white',
|
||||||
|
),
|
||||||
|
heroSectionStyleClassKey: CONTACT_HERO_SECTION_STYLE_KEY,
|
||||||
|
heroTitleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
CONTACT_HERO_TITLE_STYLE_KEY,
|
||||||
|
'ml-4 mb-2 mt-3 text-5xl font-bold text-white',
|
||||||
|
),
|
||||||
|
heroTitleStyleClassKey: CONTACT_HERO_TITLE_STYLE_KEY,
|
||||||
heroSubtitle: resolveLocalizedValue(translate, CONTACT_HERO_SUBTITLE_KEY),
|
heroSubtitle: resolveLocalizedValue(translate, CONTACT_HERO_SUBTITLE_KEY),
|
||||||
heroSubtitleKey: CONTACT_HERO_SUBTITLE_KEY,
|
heroSubtitleKey: CONTACT_HERO_SUBTITLE_KEY,
|
||||||
|
heroSubtitleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
CONTACT_HERO_SUBTITLE_STYLE_KEY,
|
||||||
|
'ml-4 max-w-3xl text-xl',
|
||||||
|
),
|
||||||
|
heroSubtitleStyleClassKey: CONTACT_HERO_SUBTITLE_STYLE_KEY,
|
||||||
heroImage: resolveLocalizedValue(translate, CONTACT_HERO_IMAGE_KEY, CONTACT_HERO_IMAGE_DEFAULT),
|
heroImage: resolveLocalizedValue(translate, CONTACT_HERO_IMAGE_KEY, CONTACT_HERO_IMAGE_DEFAULT),
|
||||||
heroImageKey: CONTACT_HERO_IMAGE_KEY,
|
heroImageKey: CONTACT_HERO_IMAGE_KEY,
|
||||||
contactInfoTitle: resolveLocalizedValue(translate, CONTACT_INFO_TITLE_KEY),
|
contactInfoTitle: resolveLocalizedValue(translate, CONTACT_INFO_TITLE_KEY),
|
||||||
contactInfoTitleKey: CONTACT_INFO_TITLE_KEY,
|
contactInfoTitleKey: CONTACT_INFO_TITLE_KEY,
|
||||||
address: resolveLocalizedValue(translate, contact?.address || CONTACT_ADDRESS_KEY),
|
contactInfoCardStyleClass: resolveLocalizedValue(
|
||||||
addressKey: contact?.address || CONTACT_ADDRESS_KEY,
|
translate,
|
||||||
|
CONTACT_INFO_CARD_STYLE_KEY,
|
||||||
|
'rounded-xl bg-white p-8 shadow-lg',
|
||||||
|
),
|
||||||
|
contactInfoCardStyleClassKey: CONTACT_INFO_CARD_STYLE_KEY,
|
||||||
|
contactInfoTitleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
CONTACT_INFO_TITLE_STYLE_KEY,
|
||||||
|
'mb-6 text-2xl font-bold text-gray-900',
|
||||||
|
),
|
||||||
|
contactInfoTitleStyleClassKey: CONTACT_INFO_TITLE_STYLE_KEY,
|
||||||
|
address: resolveLocalizedValue(translate, contact?.address, ''),
|
||||||
|
addressKey: contact?.address || '',
|
||||||
phoneNumber: contact?.phoneNumber || '',
|
phoneNumber: contact?.phoneNumber || '',
|
||||||
email: contact?.email || '',
|
email: contact?.email || '',
|
||||||
location: contact?.location || '',
|
location: contact?.location || '',
|
||||||
|
|
@ -121,25 +165,27 @@ function buildContactContent(
|
||||||
bankBranch: contact?.bankDto?.branch || '',
|
bankBranch: contact?.bankDto?.branch || '',
|
||||||
bankAccountNumber: contact?.bankDto?.accountNumber || '',
|
bankAccountNumber: contact?.bankDto?.accountNumber || '',
|
||||||
bankIban: contact?.bankDto?.iban || '',
|
bankIban: contact?.bankDto?.iban || '',
|
||||||
|
bankStyleClass: contact?.bankDto?.styleClass || 'rounded-xl bg-white p-8 shadow-lg',
|
||||||
workHoursTitle: resolveLocalizedValue(translate, CONTACT_WORK_HOURS_TITLE_KEY),
|
workHoursTitle: resolveLocalizedValue(translate, CONTACT_WORK_HOURS_TITLE_KEY),
|
||||||
workHoursTitleKey: CONTACT_WORK_HOURS_TITLE_KEY,
|
workHoursTitleKey: CONTACT_WORK_HOURS_TITLE_KEY,
|
||||||
workWeekday: resolveLocalizedValue(translate, contact?.workHoursDto?.weekday || CONTACT_WORK_WEEKDAY_KEY),
|
workWeekday: resolveLocalizedValue(translate, contact?.workHoursDto?.weekday, ''),
|
||||||
workWeekdayKey: contact?.workHoursDto?.weekday || CONTACT_WORK_WEEKDAY_KEY,
|
workWeekdayKey: contact?.workHoursDto?.weekday || '',
|
||||||
workWeekend: resolveLocalizedValue(translate, contact?.workHoursDto?.weekend || CONTACT_WORK_WEEKEND_KEY),
|
workWeekend: resolveLocalizedValue(translate, contact?.workHoursDto?.weekend, ''),
|
||||||
workWeekendKey: contact?.workHoursDto?.weekend || CONTACT_WORK_WEEKEND_KEY,
|
workWeekendKey: contact?.workHoursDto?.weekend || '',
|
||||||
workWhatsapp: resolveLocalizedValue(
|
workWhatsapp: resolveLocalizedValue(translate, contact?.workHoursDto?.whatsapp, ''),
|
||||||
translate,
|
workWhatsappKey: contact?.workHoursDto?.whatsapp || '',
|
||||||
contact?.workHoursDto?.whatsapp || CONTACT_WORK_WHATSAPP_KEY,
|
workHoursStyleClass: contact?.workHoursDto?.styleClass || 'rounded-xl bg-white p-8 shadow-lg',
|
||||||
),
|
mapTitle: resolveLocalizedValue(translate, contact?.mapDto?.title, ''),
|
||||||
workWhatsappKey: contact?.workHoursDto?.whatsapp || CONTACT_WORK_WHATSAPP_KEY,
|
mapTitleKey: contact?.mapDto?.title || '',
|
||||||
mapTitle: resolveLocalizedValue(translate, contact?.mapDto?.title || CONTACT_MAP_TITLE_KEY),
|
|
||||||
mapTitleKey: contact?.mapDto?.title || CONTACT_MAP_TITLE_KEY,
|
|
||||||
mapSrc: contact?.mapDto?.src || '',
|
mapSrc: contact?.mapDto?.src || '',
|
||||||
mapWidth: contact?.mapDto?.width || '100%',
|
mapWidth: contact?.mapDto?.width || '100%',
|
||||||
mapHeight: contact?.mapDto?.height || '700',
|
mapHeight: contact?.mapDto?.height || '700',
|
||||||
mapAllowFullScreen: String(contact?.mapDto?.allowFullScreen ?? true),
|
mapAllowFullScreen: String(contact?.mapDto?.allowFullScreen ?? true),
|
||||||
mapLoading: contact?.mapDto?.loading || 'lazy',
|
mapLoading: contact?.mapDto?.loading || 'lazy',
|
||||||
mapReferrerPolicy: contact?.mapDto?.referrerPolicy || 'no-referrer-when-downgrade',
|
mapReferrerPolicy: contact?.mapDto?.referrerPolicy || 'no-referrer-when-downgrade',
|
||||||
|
mapContainerStyleClass: contact?.mapDto?.containerStyleClass || 'rounded-xl bg-white p-8 shadow-lg',
|
||||||
|
mapFrameStyleClass:
|
||||||
|
contact?.mapDto?.frameStyleClass || 'aspect-w-16 aspect-h-9 overflow-hidden rounded-xl bg-gray-200',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,18 +284,36 @@ const Contact: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.heroTitle,
|
value: content.heroTitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroTitleStyleClass',
|
||||||
|
label: content.heroTitleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroTitleStyleClass,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'heroSubtitle',
|
key: 'heroSubtitle',
|
||||||
label: content.heroSubtitleKey,
|
label: content.heroSubtitleKey,
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: content.heroSubtitle,
|
value: content.heroSubtitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroSubtitleStyleClass',
|
||||||
|
label: content.heroSubtitleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroSubtitleStyleClass,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'heroImage',
|
key: 'heroImage',
|
||||||
label: content.heroImageKey,
|
label: content.heroImageKey,
|
||||||
type: 'image',
|
type: 'image',
|
||||||
value: content.heroImage,
|
value: content.heroImage,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroSectionStyleClass',
|
||||||
|
label: content.heroSectionStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroSectionStyleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -266,6 +330,18 @@ const Contact: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.contactInfoTitle,
|
value: content.contactInfoTitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'contactInfoTitleStyleClass',
|
||||||
|
label: content.contactInfoTitleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.contactInfoTitleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'contactInfoCardStyleClass',
|
||||||
|
label: content.contactInfoCardStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.contactInfoCardStyleClass,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'address',
|
key: 'address',
|
||||||
label: content.addressKey,
|
label: content.addressKey,
|
||||||
|
|
@ -336,6 +412,12 @@ const Contact: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.bankIban,
|
value: content.bankIban,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'bankStyleClass',
|
||||||
|
label: 'Public.contact.bank.styleClass',
|
||||||
|
type: 'text',
|
||||||
|
value: content.bankStyleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -370,6 +452,12 @@ const Contact: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.workWhatsapp,
|
value: content.workWhatsapp,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'workHoursStyleClass',
|
||||||
|
label: 'Public.contact.workHours.styleClass',
|
||||||
|
type: 'text',
|
||||||
|
value: content.workHoursStyleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -423,6 +511,18 @@ const Contact: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.mapReferrerPolicy,
|
value: content.mapReferrerPolicy,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'mapContainerStyleClass',
|
||||||
|
label: 'Public.contact.map.containerStyleClass',
|
||||||
|
type: 'text',
|
||||||
|
value: content.mapContainerStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'mapFrameStyleClass',
|
||||||
|
label: 'Public.contact.map.frameStyleClass',
|
||||||
|
type: 'text',
|
||||||
|
value: content.mapFrameStyleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -460,6 +560,7 @@ const Contact: React.FC = () => {
|
||||||
bankBranch: content.bankBranch,
|
bankBranch: content.bankBranch,
|
||||||
bankAccountNumber: content.bankAccountNumber,
|
bankAccountNumber: content.bankAccountNumber,
|
||||||
bankIban: content.bankIban,
|
bankIban: content.bankIban,
|
||||||
|
bankStyleClass: content.bankStyleClass,
|
||||||
workHoursTitleKey: content.workHoursTitleKey,
|
workHoursTitleKey: content.workHoursTitleKey,
|
||||||
workHoursTitleValue: content.workHoursTitle,
|
workHoursTitleValue: content.workHoursTitle,
|
||||||
workWeekdayKey: content.workWeekdayKey,
|
workWeekdayKey: content.workWeekdayKey,
|
||||||
|
|
@ -468,6 +569,7 @@ const Contact: React.FC = () => {
|
||||||
workWeekendValue: content.workWeekend,
|
workWeekendValue: content.workWeekend,
|
||||||
workWhatsappKey: content.workWhatsappKey,
|
workWhatsappKey: content.workWhatsappKey,
|
||||||
workWhatsappValue: content.workWhatsapp,
|
workWhatsappValue: content.workWhatsapp,
|
||||||
|
workHoursStyleClass: content.workHoursStyleClass,
|
||||||
mapTitleKey: content.mapTitleKey,
|
mapTitleKey: content.mapTitleKey,
|
||||||
mapTitleValue: content.mapTitle,
|
mapTitleValue: content.mapTitle,
|
||||||
mapSrc: content.mapSrc,
|
mapSrc: content.mapSrc,
|
||||||
|
|
@ -476,6 +578,30 @@ const Contact: React.FC = () => {
|
||||||
mapAllowFullScreen: content.mapAllowFullScreen.toLowerCase() === 'true',
|
mapAllowFullScreen: content.mapAllowFullScreen.toLowerCase() === 'true',
|
||||||
mapLoading: content.mapLoading,
|
mapLoading: content.mapLoading,
|
||||||
mapReferrerPolicy: content.mapReferrerPolicy,
|
mapReferrerPolicy: content.mapReferrerPolicy,
|
||||||
|
mapContainerStyleClass: content.mapContainerStyleClass,
|
||||||
|
mapFrameStyleClass: content.mapFrameStyleClass,
|
||||||
|
styleTexts: [
|
||||||
|
{
|
||||||
|
key: content.heroSectionStyleClassKey,
|
||||||
|
value: content.heroSectionStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.heroTitleStyleClassKey,
|
||||||
|
value: content.heroTitleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.heroSubtitleStyleClassKey,
|
||||||
|
value: content.heroSubtitleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.contactInfoCardStyleClassKey,
|
||||||
|
value: content.contactInfoCardStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.contactInfoTitleStyleClassKey,
|
||||||
|
value: content.contactInfoTitleStyleClass,
|
||||||
|
},
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
await getConfig(false)
|
await getConfig(false)
|
||||||
|
|
@ -548,7 +674,7 @@ const Contact: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="relative bg-blue-900 py-12 text-white">
|
<div className={content?.heroSectionStyleClass || 'relative bg-blue-900 py-12 text-white'}>
|
||||||
<div
|
<div
|
||||||
className="absolute inset-0 opacity-20"
|
className="absolute inset-0 opacity-20"
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -558,8 +684,8 @@ const Contact: React.FC = () => {
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
<div className="container relative mx-auto pt-20">
|
<div className="container relative mx-auto pt-20">
|
||||||
<h1 className="ml-4 mb-2 mt-3 text-5xl font-bold text-white">{content?.heroTitle}</h1>
|
<h1 className={content?.heroTitleStyleClass || 'ml-4 mb-2 mt-3 text-5xl font-bold text-white'}>{content?.heroTitle}</h1>
|
||||||
<p className="ml-4 max-w-3xl text-xl">{content?.heroSubtitle}</p>
|
<p className={content?.heroSubtitleStyleClass || 'ml-4 max-w-3xl text-xl'}>{content?.heroSubtitle}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SelectableBlock>
|
</SelectableBlock>
|
||||||
|
|
@ -574,8 +700,8 @@ const Contact: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="rounded-xl bg-white p-8 shadow-lg">
|
<div className={content?.contactInfoCardStyleClass || 'rounded-xl bg-white p-8 shadow-lg'}>
|
||||||
<h2 className="mb-6 text-2xl font-bold text-gray-900">{content?.contactInfoTitle}</h2>
|
<h2 className={content?.contactInfoTitleStyleClass || 'mb-6 text-2xl font-bold text-gray-900'}>{content?.contactInfoTitle}</h2>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-start space-x-2">
|
<div className="flex items-start space-x-2">
|
||||||
<FaMapMarkerAlt className="mt-1 h-5 w-5 flex-shrink-0 text-blue-600" />
|
<FaMapMarkerAlt className="mt-1 h-5 w-5 flex-shrink-0 text-blue-600" />
|
||||||
|
|
@ -621,7 +747,7 @@ const Contact: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="rounded-xl bg-white p-8 shadow-lg">
|
<div className={content?.bankStyleClass || 'rounded-xl bg-white p-8 shadow-lg'}>
|
||||||
<h2 className="mb-6 text-2xl font-bold text-gray-900">{content?.bankTitle}</h2>
|
<h2 className="mb-6 text-2xl font-bold text-gray-900">{content?.bankTitle}</h2>
|
||||||
<div className="mb-2">
|
<div className="mb-2">
|
||||||
<img
|
<img
|
||||||
|
|
@ -645,7 +771,7 @@ const Contact: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="rounded-xl bg-white p-8 shadow-lg">
|
<div className={content?.workHoursStyleClass || 'rounded-xl bg-white p-8 shadow-lg'}>
|
||||||
<h2 className="mb-6 text-2xl font-bold text-gray-900">{content?.workHoursTitle}</h2>
|
<h2 className="mb-6 text-2xl font-bold text-gray-900">{content?.workHoursTitle}</h2>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
|
|
@ -671,9 +797,9 @@ const Contact: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="rounded-xl bg-white p-8 shadow-lg">
|
<div className={content?.mapContainerStyleClass || 'rounded-xl bg-white p-8 shadow-lg'}>
|
||||||
<h2 className="mb-2 text-center text-2xl font-bold text-gray-900">{content?.mapTitle}</h2>
|
<h2 className="mb-2 text-center text-2xl font-bold text-gray-900">{content?.mapTitle}</h2>
|
||||||
<div className="aspect-w-16 aspect-h-9 overflow-hidden rounded-xl bg-gray-200">
|
<div className={content?.mapFrameStyleClass || 'aspect-w-16 aspect-h-9 overflow-hidden rounded-xl bg-gray-200'}>
|
||||||
<iframe
|
<iframe
|
||||||
src={content?.mapSrc}
|
src={content?.mapSrc}
|
||||||
width={content?.mapWidth}
|
width={content?.mapWidth}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ interface HomeSlideServiceContent {
|
||||||
titleKey: string
|
titleKey: string
|
||||||
description: string
|
description: string
|
||||||
descriptionKey: string
|
descriptionKey: string
|
||||||
|
styleClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HomeSlideContent {
|
interface HomeSlideContent {
|
||||||
|
|
@ -32,6 +33,7 @@ interface HomeSlideContent {
|
||||||
titleKey: string
|
titleKey: string
|
||||||
subtitle: string
|
subtitle: string
|
||||||
subtitleKey: string
|
subtitleKey: string
|
||||||
|
styleClass: string
|
||||||
services: HomeSlideServiceContent[]
|
services: HomeSlideServiceContent[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,6 +43,7 @@ interface HomeFeatureContent {
|
||||||
titleKey: string
|
titleKey: string
|
||||||
description: string
|
description: string
|
||||||
descriptionKey: string
|
descriptionKey: string
|
||||||
|
styleClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HomeSolutionContent {
|
interface HomeSolutionContent {
|
||||||
|
|
@ -50,6 +53,7 @@ interface HomeSolutionContent {
|
||||||
titleKey: string
|
titleKey: string
|
||||||
description: string
|
description: string
|
||||||
descriptionKey: string
|
descriptionKey: string
|
||||||
|
styleClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HomeContent {
|
interface HomeContent {
|
||||||
|
|
@ -57,40 +61,75 @@ interface HomeContent {
|
||||||
heroBackgroundImageKey: string
|
heroBackgroundImageKey: string
|
||||||
heroPrimaryCtaLabel: string
|
heroPrimaryCtaLabel: string
|
||||||
heroPrimaryCtaKey: string
|
heroPrimaryCtaKey: string
|
||||||
|
heroPrimaryCtaStyle: string
|
||||||
|
heroPrimaryCtaStyleKey: string
|
||||||
heroSecondaryCtaLabel: string
|
heroSecondaryCtaLabel: string
|
||||||
heroSecondaryCtaKey: string
|
heroSecondaryCtaKey: string
|
||||||
|
heroSecondaryCtaStyle: string
|
||||||
|
heroSecondaryCtaStyleKey: string
|
||||||
featuresTitle: string
|
featuresTitle: string
|
||||||
featuresTitleKey: string
|
featuresTitleKey: string
|
||||||
|
featuresTitleStyle: string
|
||||||
|
featuresTitleStyleKey: string
|
||||||
featuresSubtitle: string
|
featuresSubtitle: string
|
||||||
featuresSubtitleKey: string
|
featuresSubtitleKey: string
|
||||||
|
featuresSubtitleStyle: string
|
||||||
|
featuresSubtitleStyleKey: string
|
||||||
solutionsTitle: string
|
solutionsTitle: string
|
||||||
solutionsTitleKey: string
|
solutionsTitleKey: string
|
||||||
|
solutionsTitleStyle: string
|
||||||
|
solutionsTitleStyleKey: string
|
||||||
solutionsSubtitle: string
|
solutionsSubtitle: string
|
||||||
solutionsSubtitleKey: string
|
solutionsSubtitleKey: string
|
||||||
|
solutionsSubtitleStyle: string
|
||||||
|
solutionsSubtitleStyleKey: string
|
||||||
ctaTitle: string
|
ctaTitle: string
|
||||||
ctaTitleKey: string
|
ctaTitleKey: string
|
||||||
|
ctaTitleStyle: string
|
||||||
|
ctaTitleStyleKey: string
|
||||||
ctaSubtitle: string
|
ctaSubtitle: string
|
||||||
ctaSubtitleKey: string
|
ctaSubtitleKey: string
|
||||||
|
ctaSubtitleStyle: string
|
||||||
|
ctaSubtitleStyleKey: string
|
||||||
ctaButtonLabel: string
|
ctaButtonLabel: string
|
||||||
ctaButtonLabelKey: string
|
ctaButtonLabelKey: string
|
||||||
|
ctaButtonStyle: string
|
||||||
|
ctaButtonStyleKey: string
|
||||||
slides: HomeSlideContent[]
|
slides: HomeSlideContent[]
|
||||||
features: HomeFeatureContent[]
|
features: HomeFeatureContent[]
|
||||||
solutions: HomeSolutionContent[]
|
solutions: HomeSolutionContent[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const HOME_HERO_BACKGROUND_KEY = 'Public.home.hero.backgroundImage'
|
|
||||||
const HOME_HERO_DEFAULT_IMAGE =
|
const HOME_HERO_DEFAULT_IMAGE =
|
||||||
'https://images.pexels.com/photos/3183150/pexels-photo-3183150.jpeg?auto=compress&cs=tinysrgb&w=1920'
|
'https://images.pexels.com/photos/3183150/pexels-photo-3183150.jpeg?auto=compress&cs=tinysrgb&w=1920'
|
||||||
|
const HOME_HERO_PRIMARY_CTA_STYLE_KEY = 'Public.home.hero.primaryCta.style'
|
||||||
|
const HOME_HERO_SECONDARY_CTA_STYLE_KEY = 'Public.home.hero.secondaryCta.style'
|
||||||
|
const HOME_FEATURES_TITLE_STYLE_KEY = 'Public.home.features.title.style'
|
||||||
|
const HOME_FEATURES_SUBTITLE_STYLE_KEY = 'Public.home.features.subtitle.style'
|
||||||
|
const HOME_SOLUTIONS_TITLE_STYLE_KEY = 'Public.home.solutions.title.style'
|
||||||
|
const HOME_SOLUTIONS_SUBTITLE_STYLE_KEY = 'Public.home.solutions.subtitle.style'
|
||||||
|
const HOME_CTA_TITLE_STYLE_KEY = 'Public.home.cta.title.style'
|
||||||
|
const HOME_CTA_SUBTITLE_STYLE_KEY = 'Public.home.cta.subtitle.style'
|
||||||
|
const HOME_CTA_BUTTON_STYLE_KEY = 'Public.home.cta.button.style'
|
||||||
|
|
||||||
const HOME_HERO_PRIMARY_CTA_KEY = 'Public.hero.cta.consultation'
|
const HOME_HERO_PRIMARY_CTA_STYLE_DEFAULT =
|
||||||
const HOME_HERO_SECONDARY_CTA_KEY = 'Public.hero.cta.discover'
|
'inline-flex items-center justify-center px-8 py-4 bg-gradient-to-r from-blue-500 to-purple-500 hover:from-blue-600 hover:to-purple-600 text-white rounded-lg font-semibold transition-all transform hover:scale-105'
|
||||||
const HOME_FEATURES_TITLE_KEY = 'Public.features.title'
|
const HOME_HERO_SECONDARY_CTA_STYLE_DEFAULT =
|
||||||
const HOME_FEATURES_SUBTITLE_KEY = 'Public.features.subtitle'
|
'inline-flex items-center justify-center px-8 py-4 bg-white/10 hover:bg-white/20 text-white rounded-lg font-semibold backdrop-blur-sm transition-all transform hover:scale-105'
|
||||||
const HOME_SOLUTIONS_TITLE_KEY = 'Public.solutions.title'
|
const HOME_FEATURES_TITLE_STYLE_DEFAULT = 'text-4xl font-bold text-gray-900 mb-4'
|
||||||
const HOME_SOLUTIONS_SUBTITLE_KEY = 'Public.solutions.subtitle'
|
const HOME_FEATURES_SUBTITLE_STYLE_DEFAULT = 'text-xl text-gray-600 max-w-2xl mx-auto'
|
||||||
const HOME_CTA_TITLE_KEY = 'Public.common.getStarted'
|
const HOME_SOLUTIONS_TITLE_STYLE_DEFAULT = 'text-4xl font-bold text-gray-900 mb-4'
|
||||||
const HOME_CTA_SUBTITLE_KEY = 'Public.common.contact'
|
const HOME_SOLUTIONS_SUBTITLE_STYLE_DEFAULT = 'text-xl text-gray-600 max-w-2xl mx-auto'
|
||||||
const HOME_CTA_BUTTON_KEY = 'Public.common.learnMore'
|
const HOME_CTA_TITLE_STYLE_DEFAULT = 'text-3xl font-bold text-white mb-4'
|
||||||
|
const HOME_CTA_SUBTITLE_STYLE_DEFAULT = 'text-white text-lg mb-8'
|
||||||
|
const HOME_CTA_BUTTON_STYLE_DEFAULT =
|
||||||
|
'bg-white text-blue-600 px-8 py-3 rounded-lg font-semibold hover:bg-blue-50 transition-colors'
|
||||||
|
const HOME_SLIDE_STYLE_DEFAULT = 'max-w-4xl mx-auto text-center'
|
||||||
|
const HOME_SLIDE_SERVICE_STYLE_DEFAULT =
|
||||||
|
'bg-white/5 backdrop-blur-sm rounded-2xl p-8 text-center hover:scale-105 hover:bg-white/10 transition-all'
|
||||||
|
const HOME_FEATURE_CARD_STYLE_DEFAULT =
|
||||||
|
'p-8 bg-white rounded-xl shadow-lg hover:shadow-xl transition-shadow'
|
||||||
|
const HOME_SOLUTION_CARD_STYLE_DEFAULT = 'p-8 h-full rounded-2xl'
|
||||||
|
|
||||||
function isLikelyLocalizationKey(value?: string) {
|
function isLikelyLocalizationKey(value?: string) {
|
||||||
return Boolean(value && /^[A-Za-z0-9_.-]+$/.test(value) && value.includes('.'))
|
return Boolean(value && /^[A-Za-z0-9_.-]+$/.test(value) && value.includes('.'))
|
||||||
|
|
@ -113,206 +152,121 @@ function resolveLocalizedValue(
|
||||||
return translatedValue === keyOrValue ? fallback || keyOrValue : translatedValue
|
return translatedValue === keyOrValue ? fallback || keyOrValue : translatedValue
|
||||||
}
|
}
|
||||||
|
|
||||||
function defaultSlides() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
titleKey: 'Public.hero.slide1.title',
|
|
||||||
subtitleKey: 'Public.hero.slide1.subtitle',
|
|
||||||
services: [
|
|
||||||
{
|
|
||||||
icon: 'FaCalendarAlt',
|
|
||||||
titleKey: 'Public.hero.slide1.service1.title',
|
|
||||||
descriptionKey: 'Public.hero.slide1.service1.desc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FaUsers',
|
|
||||||
titleKey: 'Public.hero.slide1.service2.title',
|
|
||||||
descriptionKey: 'Public.hero.slide1.service2.desc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FaShieldAlt',
|
|
||||||
titleKey: 'Public.hero.slide1.service3.title',
|
|
||||||
descriptionKey: 'Public.hero.slide1.service3.desc',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
titleKey: 'Public.hero.slide2.title',
|
|
||||||
subtitleKey: 'Public.hero.slide2.subtitle',
|
|
||||||
services: [
|
|
||||||
{
|
|
||||||
icon: 'FaChartBar',
|
|
||||||
titleKey: 'Public.hero.slide2.service1.title',
|
|
||||||
descriptionKey: 'Public.hero.slide2.service1.desc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FaCreditCard',
|
|
||||||
titleKey: 'Public.hero.slide2.service2.title',
|
|
||||||
descriptionKey: 'Public.hero.slide2.service2.desc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FaDatabase',
|
|
||||||
titleKey: 'Public.hero.slide2.service3.title',
|
|
||||||
descriptionKey: 'Public.hero.slide2.service3.desc',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
titleKey: 'Public.hero.slide3.title',
|
|
||||||
subtitleKey: 'Public.hero.slide3.subtitle',
|
|
||||||
services: [
|
|
||||||
{
|
|
||||||
icon: 'FaDesktop',
|
|
||||||
titleKey: 'Public.hero.slide3.service1.title',
|
|
||||||
descriptionKey: 'Public.hero.slide3.service1.desc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FaServer',
|
|
||||||
titleKey: 'Public.hero.slide3.service2.title',
|
|
||||||
descriptionKey: 'Public.hero.slide3.service2.desc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FaMobileAlt',
|
|
||||||
titleKey: 'Public.hero.slide3.service3.title',
|
|
||||||
descriptionKey: 'Public.hero.slide3.service3.desc',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
function defaultFeatures() {
|
|
||||||
return [
|
|
||||||
{ icon: 'FaUsers', titleKey: 'Public.features.reliable', descriptionKey: 'Public.features.reliable.desc' },
|
|
||||||
{
|
|
||||||
icon: 'FaCalendarAlt',
|
|
||||||
titleKey: 'App.Coordinator.Classroom.Planning',
|
|
||||||
descriptionKey: 'Public.features.rapid.desc',
|
|
||||||
},
|
|
||||||
{ icon: 'FaBookOpen', titleKey: 'Public.features.expert', descriptionKey: 'Public.features.expert.desc' },
|
|
||||||
{
|
|
||||||
icon: 'FaCreditCard',
|
|
||||||
titleKey: 'Public.features.muhasebe',
|
|
||||||
descriptionKey: 'Public.features.muhasebe.desc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FaRegComment',
|
|
||||||
titleKey: 'Public.features.iletisim',
|
|
||||||
descriptionKey: 'Public.features.iletisim.desc',
|
|
||||||
},
|
|
||||||
{ icon: 'FaPhone', titleKey: 'Public.features.mobil', descriptionKey: 'Public.features.mobil.desc' },
|
|
||||||
{ icon: 'FaChartBar', titleKey: 'Public.features.scalable', descriptionKey: 'Public.features.scalable.desc' },
|
|
||||||
{
|
|
||||||
icon: 'FaShieldAlt',
|
|
||||||
titleKey: 'Public.features.guvenlik',
|
|
||||||
descriptionKey: 'Public.features.guvenlik.desc',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
function defaultSolutions() {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
icon: 'FaDesktop',
|
|
||||||
colorClass: 'bg-blue-600',
|
|
||||||
titleKey: 'Public.services.web.title',
|
|
||||||
descriptionKey: 'Public.solutions.web.desc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FaMobileAlt',
|
|
||||||
colorClass: 'bg-purple-600',
|
|
||||||
titleKey: 'Public.services.mobile.title',
|
|
||||||
descriptionKey: 'Public.solutions.mobile.desc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FaServer',
|
|
||||||
colorClass: 'bg-green-600',
|
|
||||||
titleKey: 'Public.solutions.custom.title',
|
|
||||||
descriptionKey: 'Public.solutions.custom.desc',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: 'FaDatabase',
|
|
||||||
colorClass: 'bg-red-600',
|
|
||||||
titleKey: 'Public.solutions.database.title',
|
|
||||||
descriptionKey: 'Public.solutions.database.desc',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildHomeContent(home: HomeDto | undefined, translate: (key: string) => string): HomeContent {
|
function buildHomeContent(home: HomeDto | undefined, translate: (key: string) => string): HomeContent {
|
||||||
const slideItems = home?.slidesDto?.length ? home.slidesDto : defaultSlides()
|
const slideItems = home?.slidesDto || []
|
||||||
const featureItems = home?.featuresDto?.length ? home.featuresDto : defaultFeatures()
|
const featureItems = home?.featuresDto || []
|
||||||
const solutionItems = home?.solutionsDto?.length ? home.solutionsDto : defaultSolutions()
|
const solutionItems = home?.solutionsDto || []
|
||||||
|
|
||||||
return {
|
return {
|
||||||
heroBackgroundImage: resolveLocalizedValue(
|
heroBackgroundImage: resolveLocalizedValue(
|
||||||
translate,
|
translate,
|
||||||
home?.heroBackgroundImageKey || HOME_HERO_BACKGROUND_KEY,
|
home?.heroBackgroundImageKey,
|
||||||
HOME_HERO_DEFAULT_IMAGE,
|
HOME_HERO_DEFAULT_IMAGE,
|
||||||
),
|
),
|
||||||
heroBackgroundImageKey: home?.heroBackgroundImageKey || HOME_HERO_BACKGROUND_KEY,
|
heroBackgroundImageKey: home?.heroBackgroundImageKey || '',
|
||||||
heroPrimaryCtaLabel: resolveLocalizedValue(
|
heroPrimaryCtaLabel: resolveLocalizedValue(translate, home?.heroPrimaryCtaKey, ''),
|
||||||
|
heroPrimaryCtaKey: home?.heroPrimaryCtaKey || '',
|
||||||
|
heroPrimaryCtaStyle: resolveLocalizedValue(
|
||||||
translate,
|
translate,
|
||||||
home?.heroPrimaryCtaKey || HOME_HERO_PRIMARY_CTA_KEY,
|
HOME_HERO_PRIMARY_CTA_STYLE_KEY,
|
||||||
|
HOME_HERO_PRIMARY_CTA_STYLE_DEFAULT,
|
||||||
),
|
),
|
||||||
heroPrimaryCtaKey: home?.heroPrimaryCtaKey || HOME_HERO_PRIMARY_CTA_KEY,
|
heroPrimaryCtaStyleKey: HOME_HERO_PRIMARY_CTA_STYLE_KEY,
|
||||||
heroSecondaryCtaLabel: resolveLocalizedValue(
|
heroSecondaryCtaLabel: resolveLocalizedValue(translate, home?.heroSecondaryCtaKey, ''),
|
||||||
|
heroSecondaryCtaKey: home?.heroSecondaryCtaKey || '',
|
||||||
|
heroSecondaryCtaStyle: resolveLocalizedValue(
|
||||||
translate,
|
translate,
|
||||||
home?.heroSecondaryCtaKey || HOME_HERO_SECONDARY_CTA_KEY,
|
HOME_HERO_SECONDARY_CTA_STYLE_KEY,
|
||||||
|
HOME_HERO_SECONDARY_CTA_STYLE_DEFAULT,
|
||||||
),
|
),
|
||||||
heroSecondaryCtaKey: home?.heroSecondaryCtaKey || HOME_HERO_SECONDARY_CTA_KEY,
|
heroSecondaryCtaStyleKey: HOME_HERO_SECONDARY_CTA_STYLE_KEY,
|
||||||
featuresTitle: resolveLocalizedValue(translate, home?.featuresTitleKey || HOME_FEATURES_TITLE_KEY),
|
featuresTitle: resolveLocalizedValue(translate, home?.featuresTitleKey, ''),
|
||||||
featuresTitleKey: home?.featuresTitleKey || HOME_FEATURES_TITLE_KEY,
|
featuresTitleKey: home?.featuresTitleKey || '',
|
||||||
featuresSubtitle: resolveLocalizedValue(
|
featuresTitleStyle: resolveLocalizedValue(
|
||||||
translate,
|
translate,
|
||||||
home?.featuresSubtitleKey || HOME_FEATURES_SUBTITLE_KEY,
|
HOME_FEATURES_TITLE_STYLE_KEY,
|
||||||
|
HOME_FEATURES_TITLE_STYLE_DEFAULT,
|
||||||
),
|
),
|
||||||
featuresSubtitleKey: home?.featuresSubtitleKey || HOME_FEATURES_SUBTITLE_KEY,
|
featuresTitleStyleKey: HOME_FEATURES_TITLE_STYLE_KEY,
|
||||||
solutionsTitle: resolveLocalizedValue(translate, home?.solutionsTitleKey || HOME_SOLUTIONS_TITLE_KEY),
|
featuresSubtitle: resolveLocalizedValue(translate, home?.featuresSubtitleKey, ''),
|
||||||
solutionsTitleKey: home?.solutionsTitleKey || HOME_SOLUTIONS_TITLE_KEY,
|
featuresSubtitleKey: home?.featuresSubtitleKey || '',
|
||||||
solutionsSubtitle: resolveLocalizedValue(
|
featuresSubtitleStyle: resolveLocalizedValue(
|
||||||
translate,
|
translate,
|
||||||
home?.solutionsSubtitleKey || HOME_SOLUTIONS_SUBTITLE_KEY,
|
HOME_FEATURES_SUBTITLE_STYLE_KEY,
|
||||||
|
HOME_FEATURES_SUBTITLE_STYLE_DEFAULT,
|
||||||
),
|
),
|
||||||
solutionsSubtitleKey: home?.solutionsSubtitleKey || HOME_SOLUTIONS_SUBTITLE_KEY,
|
featuresSubtitleStyleKey: HOME_FEATURES_SUBTITLE_STYLE_KEY,
|
||||||
ctaTitle: resolveLocalizedValue(translate, home?.ctaTitleKey || HOME_CTA_TITLE_KEY),
|
solutionsTitle: resolveLocalizedValue(translate, home?.solutionsTitleKey, ''),
|
||||||
ctaTitleKey: home?.ctaTitleKey || HOME_CTA_TITLE_KEY,
|
solutionsTitleKey: home?.solutionsTitleKey || '',
|
||||||
ctaSubtitle: resolveLocalizedValue(translate, home?.ctaSubtitleKey || HOME_CTA_SUBTITLE_KEY),
|
solutionsTitleStyle: resolveLocalizedValue(
|
||||||
ctaSubtitleKey: home?.ctaSubtitleKey || HOME_CTA_SUBTITLE_KEY,
|
translate,
|
||||||
ctaButtonLabel: resolveLocalizedValue(translate, home?.ctaButtonLabelKey || HOME_CTA_BUTTON_KEY),
|
HOME_SOLUTIONS_TITLE_STYLE_KEY,
|
||||||
ctaButtonLabelKey: home?.ctaButtonLabelKey || HOME_CTA_BUTTON_KEY,
|
HOME_SOLUTIONS_TITLE_STYLE_DEFAULT,
|
||||||
slides: slideItems.map((slide, slideIndex) => ({
|
),
|
||||||
|
solutionsTitleStyleKey: HOME_SOLUTIONS_TITLE_STYLE_KEY,
|
||||||
|
solutionsSubtitle: resolveLocalizedValue(translate, home?.solutionsSubtitleKey, ''),
|
||||||
|
solutionsSubtitleKey: home?.solutionsSubtitleKey || '',
|
||||||
|
solutionsSubtitleStyle: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
HOME_SOLUTIONS_SUBTITLE_STYLE_KEY,
|
||||||
|
HOME_SOLUTIONS_SUBTITLE_STYLE_DEFAULT,
|
||||||
|
),
|
||||||
|
solutionsSubtitleStyleKey: HOME_SOLUTIONS_SUBTITLE_STYLE_KEY,
|
||||||
|
ctaTitle: resolveLocalizedValue(translate, home?.ctaTitleKey, ''),
|
||||||
|
ctaTitleKey: home?.ctaTitleKey || '',
|
||||||
|
ctaTitleStyle: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
HOME_CTA_TITLE_STYLE_KEY,
|
||||||
|
HOME_CTA_TITLE_STYLE_DEFAULT,
|
||||||
|
),
|
||||||
|
ctaTitleStyleKey: HOME_CTA_TITLE_STYLE_KEY,
|
||||||
|
ctaSubtitle: resolveLocalizedValue(translate, home?.ctaSubtitleKey, ''),
|
||||||
|
ctaSubtitleKey: home?.ctaSubtitleKey || '',
|
||||||
|
ctaSubtitleStyle: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
HOME_CTA_SUBTITLE_STYLE_KEY,
|
||||||
|
HOME_CTA_SUBTITLE_STYLE_DEFAULT,
|
||||||
|
),
|
||||||
|
ctaSubtitleStyleKey: HOME_CTA_SUBTITLE_STYLE_KEY,
|
||||||
|
ctaButtonLabel: resolveLocalizedValue(translate, home?.ctaButtonLabelKey, ''),
|
||||||
|
ctaButtonLabelKey: home?.ctaButtonLabelKey || '',
|
||||||
|
ctaButtonStyle: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
HOME_CTA_BUTTON_STYLE_KEY,
|
||||||
|
HOME_CTA_BUTTON_STYLE_DEFAULT,
|
||||||
|
),
|
||||||
|
ctaButtonStyleKey: HOME_CTA_BUTTON_STYLE_KEY,
|
||||||
|
slides: slideItems.map((slide) => ({
|
||||||
title: resolveLocalizedValue(translate, slide.titleKey, slide.titleKey),
|
title: resolveLocalizedValue(translate, slide.titleKey, slide.titleKey),
|
||||||
titleKey: slide.titleKey || `Public.home.dynamic.slide.${slideIndex + 1}.title`,
|
titleKey: slide.titleKey || '',
|
||||||
subtitle: resolveLocalizedValue(translate, slide.subtitleKey, slide.subtitleKey),
|
subtitle: resolveLocalizedValue(translate, slide.subtitleKey, slide.subtitleKey),
|
||||||
subtitleKey: slide.subtitleKey || `Public.home.dynamic.slide.${slideIndex + 1}.subtitle`,
|
subtitleKey: slide.subtitleKey || '',
|
||||||
services: (slide.services || []).map((service, serviceIndex) => ({
|
styleClass: slide.styleClass || HOME_SLIDE_STYLE_DEFAULT,
|
||||||
icon: service.icon || 'FaCircle',
|
services: (slide.services || []).map((service) => ({
|
||||||
|
icon: service.icon || '',
|
||||||
title: resolveLocalizedValue(translate, service.titleKey, service.titleKey),
|
title: resolveLocalizedValue(translate, service.titleKey, service.titleKey),
|
||||||
titleKey:
|
titleKey: service.titleKey || '',
|
||||||
service.titleKey ||
|
|
||||||
`Public.home.dynamic.slide.${slideIndex + 1}.service.${serviceIndex + 1}.title`,
|
|
||||||
description: resolveLocalizedValue(translate, service.descriptionKey, service.descriptionKey),
|
description: resolveLocalizedValue(translate, service.descriptionKey, service.descriptionKey),
|
||||||
descriptionKey:
|
descriptionKey: service.descriptionKey || '',
|
||||||
service.descriptionKey ||
|
styleClass: service.styleClass || HOME_SLIDE_SERVICE_STYLE_DEFAULT,
|
||||||
`Public.home.dynamic.slide.${slideIndex + 1}.service.${serviceIndex + 1}.description`,
|
|
||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
features: featureItems.map((feature, index) => ({
|
features: featureItems.map((feature) => ({
|
||||||
icon: feature.icon || 'FaCircle',
|
icon: feature.icon || '',
|
||||||
title: resolveLocalizedValue(translate, feature.titleKey, feature.titleKey),
|
title: resolveLocalizedValue(translate, feature.titleKey, feature.titleKey),
|
||||||
titleKey: feature.titleKey || `Public.home.dynamic.feature.${index + 1}.title`,
|
titleKey: feature.titleKey || '',
|
||||||
description: resolveLocalizedValue(translate, feature.descriptionKey, feature.descriptionKey),
|
description: resolveLocalizedValue(translate, feature.descriptionKey, feature.descriptionKey),
|
||||||
descriptionKey: feature.descriptionKey || `Public.home.dynamic.feature.${index + 1}.description`,
|
descriptionKey: feature.descriptionKey || '',
|
||||||
|
styleClass: feature.styleClass || HOME_FEATURE_CARD_STYLE_DEFAULT,
|
||||||
})),
|
})),
|
||||||
solutions: solutionItems.map((solution, index) => ({
|
solutions: solutionItems.map((solution) => ({
|
||||||
icon: solution.icon || 'FaCircle',
|
icon: solution.icon || '',
|
||||||
colorClass: solution.colorClass || 'bg-blue-600',
|
colorClass: solution.colorClass || '',
|
||||||
title: resolveLocalizedValue(translate, solution.titleKey, solution.titleKey),
|
title: resolveLocalizedValue(translate, solution.titleKey, solution.titleKey),
|
||||||
titleKey: solution.titleKey || `Public.home.dynamic.solution.${index + 1}.title`,
|
titleKey: solution.titleKey || '',
|
||||||
description: resolveLocalizedValue(translate, solution.descriptionKey, solution.descriptionKey),
|
description: resolveLocalizedValue(translate, solution.descriptionKey, solution.descriptionKey),
|
||||||
descriptionKey:
|
descriptionKey: solution.descriptionKey || '',
|
||||||
solution.descriptionKey || `Public.home.dynamic.solution.${index + 1}.description`,
|
styleClass: solution.styleClass || HOME_SOLUTION_CARD_STYLE_DEFAULT,
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -428,14 +382,23 @@ const Home: React.FC = () => {
|
||||||
if (
|
if (
|
||||||
fieldKey === 'heroBackgroundImage' ||
|
fieldKey === 'heroBackgroundImage' ||
|
||||||
fieldKey === 'heroPrimaryCtaLabel' ||
|
fieldKey === 'heroPrimaryCtaLabel' ||
|
||||||
|
fieldKey === 'heroPrimaryCtaStyle' ||
|
||||||
fieldKey === 'heroSecondaryCtaLabel' ||
|
fieldKey === 'heroSecondaryCtaLabel' ||
|
||||||
|
fieldKey === 'heroSecondaryCtaStyle' ||
|
||||||
fieldKey === 'featuresTitle' ||
|
fieldKey === 'featuresTitle' ||
|
||||||
|
fieldKey === 'featuresTitleStyle' ||
|
||||||
fieldKey === 'featuresSubtitle' ||
|
fieldKey === 'featuresSubtitle' ||
|
||||||
|
fieldKey === 'featuresSubtitleStyle' ||
|
||||||
fieldKey === 'solutionsTitle' ||
|
fieldKey === 'solutionsTitle' ||
|
||||||
|
fieldKey === 'solutionsTitleStyle' ||
|
||||||
fieldKey === 'solutionsSubtitle' ||
|
fieldKey === 'solutionsSubtitle' ||
|
||||||
|
fieldKey === 'solutionsSubtitleStyle' ||
|
||||||
fieldKey === 'ctaTitle' ||
|
fieldKey === 'ctaTitle' ||
|
||||||
|
fieldKey === 'ctaTitleStyle' ||
|
||||||
fieldKey === 'ctaSubtitle' ||
|
fieldKey === 'ctaSubtitle' ||
|
||||||
fieldKey === 'ctaButtonLabel'
|
fieldKey === 'ctaSubtitleStyle' ||
|
||||||
|
fieldKey === 'ctaButtonLabel' ||
|
||||||
|
fieldKey === 'ctaButtonStyle'
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
...current,
|
...current,
|
||||||
|
|
@ -452,12 +415,12 @@ const Home: React.FC = () => {
|
||||||
const slides = [...current.slides]
|
const slides = [...current.slides]
|
||||||
const target = { ...slides[index] }
|
const target = { ...slides[index] }
|
||||||
|
|
||||||
if (fieldKey === 'title' || fieldKey === 'subtitle') {
|
if (fieldKey === 'title' || fieldKey === 'subtitle' || fieldKey === 'styleClass') {
|
||||||
target[fieldKey] = nextValue
|
target[fieldKey] = nextValue
|
||||||
} else if (fieldKey.startsWith('service-')) {
|
} else if (fieldKey.startsWith('service-')) {
|
||||||
const parts = fieldKey.split('-')
|
const parts = fieldKey.split('-')
|
||||||
const serviceIndex = Number(parts[1])
|
const serviceIndex = Number(parts[1])
|
||||||
const serviceField = parts[2] as 'icon' | 'title' | 'description'
|
const serviceField = parts[2] as 'icon' | 'title' | 'description' | 'styleClass'
|
||||||
const services = [...target.services]
|
const services = [...target.services]
|
||||||
const service = { ...services[serviceIndex] }
|
const service = { ...services[serviceIndex] }
|
||||||
service[serviceField] = nextValue
|
service[serviceField] = nextValue
|
||||||
|
|
@ -480,7 +443,7 @@ const Home: React.FC = () => {
|
||||||
|
|
||||||
const features = [...current.features]
|
const features = [...current.features]
|
||||||
const feature = { ...features[index] }
|
const feature = { ...features[index] }
|
||||||
const key = fieldKey as 'icon' | 'title' | 'description'
|
const key = fieldKey as 'icon' | 'title' | 'description' | 'styleClass'
|
||||||
feature[key] = nextValue
|
feature[key] = nextValue
|
||||||
features[index] = feature
|
features[index] = feature
|
||||||
|
|
||||||
|
|
@ -498,7 +461,7 @@ const Home: React.FC = () => {
|
||||||
|
|
||||||
const solutions = [...current.solutions]
|
const solutions = [...current.solutions]
|
||||||
const solution = { ...solutions[index] }
|
const solution = { ...solutions[index] }
|
||||||
const key = fieldKey as 'icon' | 'title' | 'description' | 'colorClass'
|
const key = fieldKey as 'icon' | 'title' | 'description' | 'colorClass' | 'styleClass'
|
||||||
solution[key] = nextValue
|
solution[key] = nextValue
|
||||||
solutions[index] = solution
|
solutions[index] = solution
|
||||||
|
|
||||||
|
|
@ -535,12 +498,24 @@ const Home: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.heroPrimaryCtaLabel,
|
value: content.heroPrimaryCtaLabel,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroPrimaryCtaStyle',
|
||||||
|
label: content.heroPrimaryCtaStyleKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroPrimaryCtaStyle,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'heroSecondaryCtaLabel',
|
key: 'heroSecondaryCtaLabel',
|
||||||
label: content.heroSecondaryCtaKey,
|
label: content.heroSecondaryCtaKey,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.heroSecondaryCtaLabel,
|
value: content.heroSecondaryCtaLabel,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroSecondaryCtaStyle',
|
||||||
|
label: content.heroSecondaryCtaStyleKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroSecondaryCtaStyle,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -570,6 +545,12 @@ const Home: React.FC = () => {
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: slide.subtitle,
|
value: slide.subtitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'styleClass',
|
||||||
|
label: `Slide${index + 1}.StyleClass`,
|
||||||
|
type: 'text',
|
||||||
|
value: slide.styleClass,
|
||||||
|
},
|
||||||
...slide.services.flatMap((service, serviceIndex) => [
|
...slide.services.flatMap((service, serviceIndex) => [
|
||||||
{
|
{
|
||||||
key: `service-${serviceIndex}-icon`,
|
key: `service-${serviceIndex}-icon`,
|
||||||
|
|
@ -590,6 +571,12 @@ const Home: React.FC = () => {
|
||||||
type: 'textarea' as const,
|
type: 'textarea' as const,
|
||||||
value: service.description,
|
value: service.description,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: `service-${serviceIndex}-styleClass`,
|
||||||
|
label: `Slide${index + 1}.Service${serviceIndex + 1}.StyleClass`,
|
||||||
|
type: 'text' as const,
|
||||||
|
value: service.styleClass,
|
||||||
|
},
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
@ -607,12 +594,24 @@ const Home: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.featuresTitle,
|
value: content.featuresTitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'featuresTitleStyle',
|
||||||
|
label: content.featuresTitleStyleKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.featuresTitleStyle,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'featuresSubtitle',
|
key: 'featuresSubtitle',
|
||||||
label: content.featuresSubtitleKey,
|
label: content.featuresSubtitleKey,
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: content.featuresSubtitle,
|
value: content.featuresSubtitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'featuresSubtitleStyle',
|
||||||
|
label: content.featuresSubtitleStyleKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.featuresSubtitleStyle,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -649,6 +648,12 @@ const Home: React.FC = () => {
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: item.description,
|
value: item.description,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'styleClass',
|
||||||
|
label: `Feature${index + 1}.StyleClass`,
|
||||||
|
type: 'text',
|
||||||
|
value: item.styleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -665,12 +670,24 @@ const Home: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.solutionsTitle,
|
value: content.solutionsTitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'solutionsTitleStyle',
|
||||||
|
label: content.solutionsTitleStyleKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.solutionsTitleStyle,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'solutionsSubtitle',
|
key: 'solutionsSubtitle',
|
||||||
label: content.solutionsSubtitleKey,
|
label: content.solutionsSubtitleKey,
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: content.solutionsSubtitle,
|
value: content.solutionsSubtitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'solutionsSubtitleStyle',
|
||||||
|
label: content.solutionsSubtitleStyleKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.solutionsSubtitleStyle,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -713,6 +730,12 @@ const Home: React.FC = () => {
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: item.description,
|
value: item.description,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'styleClass',
|
||||||
|
label: `Solution${index + 1}.StyleClass`,
|
||||||
|
type: 'text',
|
||||||
|
value: item.styleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -729,18 +752,36 @@ const Home: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.ctaTitle,
|
value: content.ctaTitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'ctaTitleStyle',
|
||||||
|
label: content.ctaTitleStyleKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.ctaTitleStyle,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'ctaSubtitle',
|
key: 'ctaSubtitle',
|
||||||
label: content.ctaSubtitleKey,
|
label: content.ctaSubtitleKey,
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: content.ctaSubtitle,
|
value: content.ctaSubtitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'ctaSubtitleStyle',
|
||||||
|
label: content.ctaSubtitleStyleKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.ctaSubtitleStyle,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'ctaButtonLabel',
|
key: 'ctaButtonLabel',
|
||||||
label: content.ctaButtonLabelKey,
|
label: content.ctaButtonLabelKey,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.ctaButtonLabel,
|
value: content.ctaButtonLabel,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'ctaButtonStyle',
|
||||||
|
label: content.ctaButtonStyleKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.ctaButtonStyle,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -762,54 +803,71 @@ const Home: React.FC = () => {
|
||||||
heroBackgroundImageValue: content.heroBackgroundImage,
|
heroBackgroundImageValue: content.heroBackgroundImage,
|
||||||
heroPrimaryCtaKey: content.heroPrimaryCtaKey,
|
heroPrimaryCtaKey: content.heroPrimaryCtaKey,
|
||||||
heroPrimaryCtaValue: content.heroPrimaryCtaLabel,
|
heroPrimaryCtaValue: content.heroPrimaryCtaLabel,
|
||||||
|
heroPrimaryCtaStyleKey: content.heroPrimaryCtaStyleKey,
|
||||||
|
heroPrimaryCtaStyleValue: content.heroPrimaryCtaStyle,
|
||||||
heroSecondaryCtaKey: content.heroSecondaryCtaKey,
|
heroSecondaryCtaKey: content.heroSecondaryCtaKey,
|
||||||
heroSecondaryCtaValue: content.heroSecondaryCtaLabel,
|
heroSecondaryCtaValue: content.heroSecondaryCtaLabel,
|
||||||
|
heroSecondaryCtaStyleKey: content.heroSecondaryCtaStyleKey,
|
||||||
|
heroSecondaryCtaStyleValue: content.heroSecondaryCtaStyle,
|
||||||
featuresTitleKey: content.featuresTitleKey,
|
featuresTitleKey: content.featuresTitleKey,
|
||||||
featuresTitleValue: content.featuresTitle,
|
featuresTitleValue: content.featuresTitle,
|
||||||
|
featuresTitleStyleKey: content.featuresTitleStyleKey,
|
||||||
|
featuresTitleStyleValue: content.featuresTitleStyle,
|
||||||
featuresSubtitleKey: content.featuresSubtitleKey,
|
featuresSubtitleKey: content.featuresSubtitleKey,
|
||||||
featuresSubtitleValue: content.featuresSubtitle,
|
featuresSubtitleValue: content.featuresSubtitle,
|
||||||
|
featuresSubtitleStyleKey: content.featuresSubtitleStyleKey,
|
||||||
|
featuresSubtitleStyleValue: content.featuresSubtitleStyle,
|
||||||
solutionsTitleKey: content.solutionsTitleKey,
|
solutionsTitleKey: content.solutionsTitleKey,
|
||||||
solutionsTitleValue: content.solutionsTitle,
|
solutionsTitleValue: content.solutionsTitle,
|
||||||
|
solutionsTitleStyleKey: content.solutionsTitleStyleKey,
|
||||||
|
solutionsTitleStyleValue: content.solutionsTitleStyle,
|
||||||
solutionsSubtitleKey: content.solutionsSubtitleKey,
|
solutionsSubtitleKey: content.solutionsSubtitleKey,
|
||||||
solutionsSubtitleValue: content.solutionsSubtitle,
|
solutionsSubtitleValue: content.solutionsSubtitle,
|
||||||
|
solutionsSubtitleStyleKey: content.solutionsSubtitleStyleKey,
|
||||||
|
solutionsSubtitleStyleValue: content.solutionsSubtitleStyle,
|
||||||
ctaTitleKey: content.ctaTitleKey,
|
ctaTitleKey: content.ctaTitleKey,
|
||||||
ctaTitleValue: content.ctaTitle,
|
ctaTitleValue: content.ctaTitle,
|
||||||
|
ctaTitleStyleKey: content.ctaTitleStyleKey,
|
||||||
|
ctaTitleStyleValue: content.ctaTitleStyle,
|
||||||
ctaSubtitleKey: content.ctaSubtitleKey,
|
ctaSubtitleKey: content.ctaSubtitleKey,
|
||||||
ctaSubtitleValue: content.ctaSubtitle,
|
ctaSubtitleValue: content.ctaSubtitle,
|
||||||
|
ctaSubtitleStyleKey: content.ctaSubtitleStyleKey,
|
||||||
|
ctaSubtitleStyleValue: content.ctaSubtitleStyle,
|
||||||
ctaButtonLabelKey: content.ctaButtonLabelKey,
|
ctaButtonLabelKey: content.ctaButtonLabelKey,
|
||||||
ctaButtonLabelValue: content.ctaButtonLabel,
|
ctaButtonLabelValue: content.ctaButtonLabel,
|
||||||
|
ctaButtonStyleKey: content.ctaButtonStyleKey,
|
||||||
|
ctaButtonStyleValue: content.ctaButtonStyle,
|
||||||
slides: content.slides.map((slide, slideIndex) => ({
|
slides: content.slides.map((slide, slideIndex) => ({
|
||||||
titleKey: slide.titleKey || `Public.home.dynamic.slide.${slideIndex + 1}.title`,
|
titleKey: slide.titleKey || '',
|
||||||
titleValue: slide.title,
|
titleValue: slide.title,
|
||||||
subtitleKey: slide.subtitleKey || `Public.home.dynamic.slide.${slideIndex + 1}.subtitle`,
|
subtitleKey: slide.subtitleKey || '',
|
||||||
subtitleValue: slide.subtitle,
|
subtitleValue: slide.subtitle,
|
||||||
|
styleClass: slide.styleClass,
|
||||||
services: slide.services.map((service, serviceIndex) => ({
|
services: slide.services.map((service, serviceIndex) => ({
|
||||||
icon: service.icon,
|
icon: service.icon,
|
||||||
titleKey:
|
titleKey: service.titleKey || '',
|
||||||
service.titleKey ||
|
|
||||||
`Public.home.dynamic.slide.${slideIndex + 1}.service.${serviceIndex + 1}.title`,
|
|
||||||
titleValue: service.title,
|
titleValue: service.title,
|
||||||
descriptionKey:
|
descriptionKey: service.descriptionKey || '',
|
||||||
service.descriptionKey ||
|
|
||||||
`Public.home.dynamic.slide.${slideIndex + 1}.service.${serviceIndex + 1}.description`,
|
|
||||||
descriptionValue: service.description,
|
descriptionValue: service.description,
|
||||||
|
styleClass: service.styleClass,
|
||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
features: content.features.map((feature, index) => ({
|
features: content.features.map((feature, index) => ({
|
||||||
icon: feature.icon,
|
icon: feature.icon,
|
||||||
titleKey: feature.titleKey || `Public.home.dynamic.feature.${index + 1}.title`,
|
titleKey: feature.titleKey || '',
|
||||||
titleValue: feature.title,
|
titleValue: feature.title,
|
||||||
descriptionKey: feature.descriptionKey || `Public.home.dynamic.feature.${index + 1}.description`,
|
descriptionKey: feature.descriptionKey || '',
|
||||||
descriptionValue: feature.description,
|
descriptionValue: feature.description,
|
||||||
|
styleClass: feature.styleClass,
|
||||||
})),
|
})),
|
||||||
solutions: content.solutions.map((solution, index) => ({
|
solutions: content.solutions.map((solution, index) => ({
|
||||||
icon: solution.icon,
|
icon: solution.icon,
|
||||||
colorClass: solution.colorClass,
|
colorClass: solution.colorClass,
|
||||||
titleKey: solution.titleKey || `Public.home.dynamic.solution.${index + 1}.title`,
|
titleKey: solution.titleKey || '',
|
||||||
titleValue: solution.title,
|
titleValue: solution.title,
|
||||||
descriptionKey:
|
descriptionKey: solution.descriptionKey || '',
|
||||||
solution.descriptionKey || `Public.home.dynamic.solution.${index + 1}.description`,
|
|
||||||
descriptionValue: solution.description,
|
descriptionValue: solution.description,
|
||||||
|
styleClass: solution.styleClass,
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -918,7 +976,7 @@ const Home: React.FC = () => {
|
||||||
}}
|
}}
|
||||||
className="h-full"
|
className="h-full"
|
||||||
>
|
>
|
||||||
<div className="container mx-auto px-4 pt-32">
|
<div className={`container mx-auto px-4 pt-32 ${slide.styleClass || ''}`}>
|
||||||
<div className="max-w-4xl mx-auto text-center">
|
<div className="max-w-4xl mx-auto text-center">
|
||||||
<h1 className="text-3xl md:text-6xl font-bold mb-6 text-white animate-fade-in">
|
<h1 className="text-3xl md:text-6xl font-bold mb-6 text-white animate-fade-in">
|
||||||
{slide.title}
|
{slide.title}
|
||||||
|
|
@ -930,14 +988,14 @@ const Home: React.FC = () => {
|
||||||
<div className="flex flex-col md:flex-row justify-center gap-6 mb-16">
|
<div className="flex flex-col md:flex-row justify-center gap-6 mb-16">
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.public.contact}
|
to={ROUTES_ENUM.public.contact}
|
||||||
className="inline-flex items-center justify-center px-8 py-4 bg-gradient-to-r from-blue-500 to-purple-500 hover:from-blue-600 hover:to-purple-600 text-white rounded-lg font-semibold transition-all transform hover:scale-105"
|
className={content?.heroPrimaryCtaStyle}
|
||||||
>
|
>
|
||||||
{content?.heroPrimaryCtaLabel}{' '}
|
{content?.heroPrimaryCtaLabel}{' '}
|
||||||
<FaArrowRight className="ml-2" size={20} />
|
<FaArrowRight className="ml-2" size={20} />
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.public.products}
|
to={ROUTES_ENUM.public.products}
|
||||||
className="inline-flex items-center justify-center px-8 py-4 bg-white/10 hover:bg-white/20 text-white rounded-lg font-semibold backdrop-blur-sm transition-all transform hover:scale-105"
|
className={content?.heroSecondaryCtaStyle}
|
||||||
>
|
>
|
||||||
{content?.heroSecondaryCtaLabel}
|
{content?.heroSecondaryCtaLabel}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -947,7 +1005,10 @@ const Home: React.FC = () => {
|
||||||
{slide.services.map((service, i) => (
|
{slide.services.map((service, i) => (
|
||||||
<div
|
<div
|
||||||
key={i}
|
key={i}
|
||||||
className="bg-white/5 backdrop-blur-sm rounded-2xl p-8 text-center hover:scale-105 hover:bg-white/10 transition-all"
|
className={
|
||||||
|
service.styleClass ||
|
||||||
|
'bg-white/5 backdrop-blur-sm rounded-2xl p-8 text-center hover:scale-105 hover:bg-white/10 transition-all'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{(() => {
|
{(() => {
|
||||||
const IconComponent = navigationIcon[service.icon || '']
|
const IconComponent = navigationIcon[service.icon || '']
|
||||||
|
|
@ -1029,10 +1090,10 @@ const Home: React.FC = () => {
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="text-center mb-16">
|
<div className="text-center mb-16">
|
||||||
<h2 className="text-4xl font-bold text-gray-900 mb-4">
|
<h2 className={content?.featuresTitleStyle}>
|
||||||
{content?.featuresTitle}
|
{content?.featuresTitle}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
<p className={content?.featuresSubtitleStyle}>
|
||||||
{content?.featuresSubtitle}
|
{content?.featuresSubtitle}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1047,7 +1108,12 @@ const Home: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="p-8 bg-white rounded-xl shadow-lg hover:shadow-xl transition-shadow">
|
<div
|
||||||
|
className={
|
||||||
|
feature.styleClass ||
|
||||||
|
'p-8 bg-white rounded-xl shadow-lg hover:shadow-xl transition-shadow'
|
||||||
|
}
|
||||||
|
>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
{(() => {
|
{(() => {
|
||||||
const IconComponent = navigationIcon[feature.icon || '']
|
const IconComponent = navigationIcon[feature.icon || '']
|
||||||
|
|
@ -1073,10 +1139,10 @@ const Home: React.FC = () => {
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="text-center mb-16">
|
<div className="text-center mb-16">
|
||||||
<h2 className="text-4xl font-bold text-gray-900 mb-4">
|
<h2 className={content?.solutionsTitleStyle}>
|
||||||
{content?.solutionsTitle}
|
{content?.solutionsTitle}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xl text-gray-600 max-w-2xl mx-auto">
|
<p className={content?.solutionsSubtitleStyle}>
|
||||||
{content?.solutionsSubtitle}
|
{content?.solutionsSubtitle}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -1091,7 +1157,7 @@ const Home: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className={`${s.colorClass} p-8 h-full rounded-2xl`}>
|
<div className={`${s.colorClass} ${s.styleClass || 'p-8 h-full rounded-2xl'}`}>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
{(() => {
|
{(() => {
|
||||||
const IconComponent = navigationIcon[s.icon || '']
|
const IconComponent = navigationIcon[s.icon || '']
|
||||||
|
|
@ -1116,11 +1182,11 @@ const Home: React.FC = () => {
|
||||||
>
|
>
|
||||||
<section className="bg-blue-600 py-16">
|
<section className="bg-blue-600 py-16">
|
||||||
<div className="container mx-auto px-4 text-center">
|
<div className="container mx-auto px-4 text-center">
|
||||||
<h2 className="text-3xl font-bold text-white mb-4">{content?.ctaTitle}</h2>
|
<h2 className={content?.ctaTitleStyle}>{content?.ctaTitle}</h2>
|
||||||
<p className="text-white text-lg mb-8">{content?.ctaSubtitle}</p>
|
<p className={content?.ctaSubtitleStyle}>{content?.ctaSubtitle}</p>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.public.contact}
|
to={ROUTES_ENUM.public.contact}
|
||||||
className="bg-white text-blue-600 px-8 py-3 rounded-lg font-semibold hover:bg-blue-50 transition-colors"
|
className={content?.ctaButtonStyle}
|
||||||
>
|
>
|
||||||
{content?.ctaButtonLabel}
|
{content?.ctaButtonLabel}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { FaCheckCircle } from 'react-icons/fa'
|
import { FaCheckCircle } from 'react-icons/fa'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
|
|
@ -23,6 +23,14 @@ interface ServiceCardContent {
|
||||||
titleKey: string
|
titleKey: string
|
||||||
description: string
|
description: string
|
||||||
descriptionKey?: string
|
descriptionKey?: string
|
||||||
|
cardStyleClassKey: string
|
||||||
|
cardStyleClass: string
|
||||||
|
titleStyleClassKey: string
|
||||||
|
titleStyleClass: string
|
||||||
|
descriptionStyleClassKey: string
|
||||||
|
descriptionStyleClass: string
|
||||||
|
featureStyleClassKey: string
|
||||||
|
featureStyleClass: string
|
||||||
features: Array<{
|
features: Array<{
|
||||||
key: string
|
key: string
|
||||||
value: string
|
value: string
|
||||||
|
|
@ -33,6 +41,10 @@ interface SupportCardContent {
|
||||||
icon: string
|
icon: string
|
||||||
title: string
|
title: string
|
||||||
titleKey: string
|
titleKey: string
|
||||||
|
cardStyleClassKey: string
|
||||||
|
cardStyleClass: string
|
||||||
|
titleStyleClassKey: string
|
||||||
|
titleStyleClass: string
|
||||||
features: Array<{
|
features: Array<{
|
||||||
key: string
|
key: string
|
||||||
value: string
|
value: string
|
||||||
|
|
@ -42,22 +54,40 @@ interface SupportCardContent {
|
||||||
interface ServicesContent {
|
interface ServicesContent {
|
||||||
heroTitle: string
|
heroTitle: string
|
||||||
heroTitleKey: string
|
heroTitleKey: string
|
||||||
|
heroSectionStyleClassKey: string
|
||||||
|
heroSectionStyleClass: string
|
||||||
|
heroTitleStyleClassKey: string
|
||||||
|
heroTitleStyleClass: string
|
||||||
heroSubtitle: string
|
heroSubtitle: string
|
||||||
heroSubtitleKey: string
|
heroSubtitleKey: string
|
||||||
|
heroSubtitleStyleClassKey: string
|
||||||
|
heroSubtitleStyleClass: string
|
||||||
heroImage: string
|
heroImage: string
|
||||||
heroImageKey: string
|
heroImageKey: string
|
||||||
serviceItems: ServiceCardContent[]
|
serviceItems: ServiceCardContent[]
|
||||||
supportTitle: string
|
supportTitle: string
|
||||||
supportTitleKey: string
|
supportTitleKey: string
|
||||||
|
supportTitleStyleClassKey: string
|
||||||
|
supportTitleStyleClass: string
|
||||||
|
supportButtonStyleClassKey: string
|
||||||
|
supportButtonStyleClass: string
|
||||||
supportItems: SupportCardContent[]
|
supportItems: SupportCardContent[]
|
||||||
supportButtonLabel: string
|
supportButtonLabel: string
|
||||||
supportButtonLabelKey: string
|
supportButtonLabelKey: string
|
||||||
ctaTitle: string
|
ctaTitle: string
|
||||||
ctaTitleKey: string
|
ctaTitleKey: string
|
||||||
|
ctaSectionStyleClassKey: string
|
||||||
|
ctaSectionStyleClass: string
|
||||||
|
ctaTitleStyleClassKey: string
|
||||||
|
ctaTitleStyleClass: string
|
||||||
ctaDescription: string
|
ctaDescription: string
|
||||||
ctaDescriptionKey: string
|
ctaDescriptionKey: string
|
||||||
|
ctaDescriptionStyleClassKey: string
|
||||||
|
ctaDescriptionStyleClass: string
|
||||||
ctaButtonLabel: string
|
ctaButtonLabel: string
|
||||||
ctaButtonLabelKey: string
|
ctaButtonLabelKey: string
|
||||||
|
ctaButtonStyleClassKey: string
|
||||||
|
ctaButtonStyleClass: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const SERVICES_HERO_IMAGE =
|
const SERVICES_HERO_IMAGE =
|
||||||
|
|
@ -70,6 +100,15 @@ const SERVICES_SUPPORT_BUTTON_KEY = 'Public.services.support.contactButton'
|
||||||
const SERVICES_CTA_TITLE_KEY = 'Public.services.cta.title'
|
const SERVICES_CTA_TITLE_KEY = 'Public.services.cta.title'
|
||||||
const SERVICES_CTA_DESCRIPTION_KEY = 'Public.services.cta.description'
|
const SERVICES_CTA_DESCRIPTION_KEY = 'Public.services.cta.description'
|
||||||
const SERVICES_CTA_BUTTON_KEY = 'Public.services.support.contactButton'
|
const SERVICES_CTA_BUTTON_KEY = 'Public.services.support.contactButton'
|
||||||
|
const SERVICES_HERO_SECTION_STYLE_KEY = 'Public.services.hero.sectionStyleClass'
|
||||||
|
const SERVICES_HERO_TITLE_STYLE_KEY = 'Public.services.hero.titleStyleClass'
|
||||||
|
const SERVICES_HERO_SUBTITLE_STYLE_KEY = 'Public.services.hero.subtitleStyleClass'
|
||||||
|
const SERVICES_SUPPORT_TITLE_STYLE_KEY = 'Public.services.support.titleStyleClass'
|
||||||
|
const SERVICES_SUPPORT_BUTTON_STYLE_KEY = 'Public.services.support.buttonStyleClass'
|
||||||
|
const SERVICES_CTA_SECTION_STYLE_KEY = 'Public.services.cta.sectionStyleClass'
|
||||||
|
const SERVICES_CTA_TITLE_STYLE_KEY = 'Public.services.cta.titleStyleClass'
|
||||||
|
const SERVICES_CTA_DESCRIPTION_STYLE_KEY = 'Public.services.cta.descriptionStyleClass'
|
||||||
|
const SERVICES_CTA_BUTTON_STYLE_KEY = 'Public.services.cta.buttonStyleClass'
|
||||||
|
|
||||||
function isLikelyLocalizationKey(value?: string) {
|
function isLikelyLocalizationKey(value?: string) {
|
||||||
return Boolean(value && /^[A-Za-z0-9_.-]+$/.test(value) && value.includes('.'))
|
return Boolean(value && /^[A-Za-z0-9_.-]+$/.test(value) && value.includes('.'))
|
||||||
|
|
@ -99,8 +138,26 @@ function buildServicesContent(
|
||||||
return {
|
return {
|
||||||
heroTitle: resolveLocalizedValue(translate, SERVICES_HERO_TITLE_KEY, 'Services'),
|
heroTitle: resolveLocalizedValue(translate, SERVICES_HERO_TITLE_KEY, 'Services'),
|
||||||
heroTitleKey: SERVICES_HERO_TITLE_KEY,
|
heroTitleKey: SERVICES_HERO_TITLE_KEY,
|
||||||
|
heroSectionStyleClassKey: SERVICES_HERO_SECTION_STYLE_KEY,
|
||||||
|
heroSectionStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
SERVICES_HERO_SECTION_STYLE_KEY,
|
||||||
|
'relative bg-blue-900 text-white py-12',
|
||||||
|
),
|
||||||
|
heroTitleStyleClassKey: SERVICES_HERO_TITLE_STYLE_KEY,
|
||||||
|
heroTitleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
SERVICES_HERO_TITLE_STYLE_KEY,
|
||||||
|
'text-5xl font-bold ml-4 mt-3 mb-2 text-white',
|
||||||
|
),
|
||||||
heroSubtitle: resolveLocalizedValue(translate, SERVICES_HERO_SUBTITLE_KEY),
|
heroSubtitle: resolveLocalizedValue(translate, SERVICES_HERO_SUBTITLE_KEY),
|
||||||
heroSubtitleKey: SERVICES_HERO_SUBTITLE_KEY,
|
heroSubtitleKey: SERVICES_HERO_SUBTITLE_KEY,
|
||||||
|
heroSubtitleStyleClassKey: SERVICES_HERO_SUBTITLE_STYLE_KEY,
|
||||||
|
heroSubtitleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
SERVICES_HERO_SUBTITLE_STYLE_KEY,
|
||||||
|
'text-xl max-w-3xl ml-4',
|
||||||
|
),
|
||||||
heroImage: resolveLocalizedValue(translate, SERVICES_HERO_IMAGE_KEY, SERVICES_HERO_IMAGE),
|
heroImage: resolveLocalizedValue(translate, SERVICES_HERO_IMAGE_KEY, SERVICES_HERO_IMAGE),
|
||||||
heroImageKey: SERVICES_HERO_IMAGE_KEY,
|
heroImageKey: SERVICES_HERO_IMAGE_KEY,
|
||||||
serviceItems: services
|
serviceItems: services
|
||||||
|
|
@ -115,6 +172,30 @@ function buildServicesContent(
|
||||||
descriptionKey:
|
descriptionKey:
|
||||||
(item.description && isLikelyLocalizationKey(item.description) ? item.description : undefined) ||
|
(item.description && isLikelyLocalizationKey(item.description) ? item.description : undefined) ||
|
||||||
`Public.services.dynamic.service.${index + 1}.description`,
|
`Public.services.dynamic.service.${index + 1}.description`,
|
||||||
|
cardStyleClassKey: `Public.services.dynamic.service.${index + 1}.cardStyleClass`,
|
||||||
|
cardStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.services.dynamic.service.${index + 1}.cardStyleClass`,
|
||||||
|
'bg-white rounded-xl shadow-lg p-8 hover:shadow-xl transition-shadow',
|
||||||
|
),
|
||||||
|
titleStyleClassKey: `Public.services.dynamic.service.${index + 1}.titleStyleClass`,
|
||||||
|
titleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.services.dynamic.service.${index + 1}.titleStyleClass`,
|
||||||
|
'text-2xl font-bold text-gray-900 mb-4',
|
||||||
|
),
|
||||||
|
descriptionStyleClassKey: `Public.services.dynamic.service.${index + 1}.descriptionStyleClass`,
|
||||||
|
descriptionStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.services.dynamic.service.${index + 1}.descriptionStyleClass`,
|
||||||
|
'text-gray-600 mb-6',
|
||||||
|
),
|
||||||
|
featureStyleClassKey: `Public.services.dynamic.service.${index + 1}.featureStyleClass`,
|
||||||
|
featureStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.services.dynamic.service.${index + 1}.featureStyleClass`,
|
||||||
|
'flex items-center text-gray-700',
|
||||||
|
),
|
||||||
features: (item.features ?? []).map((feature, featureIndex) => ({
|
features: (item.features ?? []).map((feature, featureIndex) => ({
|
||||||
key:
|
key:
|
||||||
(isLikelyLocalizationKey(feature) ? feature : undefined) ||
|
(isLikelyLocalizationKey(feature) ? feature : undefined) ||
|
||||||
|
|
@ -124,6 +205,18 @@ function buildServicesContent(
|
||||||
})),
|
})),
|
||||||
supportTitle: resolveLocalizedValue(translate, SERVICES_SUPPORT_TITLE_KEY),
|
supportTitle: resolveLocalizedValue(translate, SERVICES_SUPPORT_TITLE_KEY),
|
||||||
supportTitleKey: SERVICES_SUPPORT_TITLE_KEY,
|
supportTitleKey: SERVICES_SUPPORT_TITLE_KEY,
|
||||||
|
supportTitleStyleClassKey: SERVICES_SUPPORT_TITLE_STYLE_KEY,
|
||||||
|
supportTitleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
SERVICES_SUPPORT_TITLE_STYLE_KEY,
|
||||||
|
'text-3xl font-bold text-center mb-10',
|
||||||
|
),
|
||||||
|
supportButtonStyleClassKey: SERVICES_SUPPORT_BUTTON_STYLE_KEY,
|
||||||
|
supportButtonStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
SERVICES_SUPPORT_BUTTON_STYLE_KEY,
|
||||||
|
'block text-center bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 transition-colors',
|
||||||
|
),
|
||||||
supportItems: services
|
supportItems: services
|
||||||
.filter((item) => item.type === 'support')
|
.filter((item) => item.type === 'support')
|
||||||
.map((item, index) => ({
|
.map((item, index) => ({
|
||||||
|
|
@ -132,6 +225,18 @@ function buildServicesContent(
|
||||||
titleKey:
|
titleKey:
|
||||||
(isLikelyLocalizationKey(item.title) ? item.title : undefined) ||
|
(isLikelyLocalizationKey(item.title) ? item.title : undefined) ||
|
||||||
`Public.services.dynamic.support.${index + 1}.title`,
|
`Public.services.dynamic.support.${index + 1}.title`,
|
||||||
|
cardStyleClassKey: `Public.services.dynamic.support.${index + 1}.cardStyleClass`,
|
||||||
|
cardStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.services.dynamic.support.${index + 1}.cardStyleClass`,
|
||||||
|
'bg-white rounded-xl shadow-lg p-8 border border-gray-200',
|
||||||
|
),
|
||||||
|
titleStyleClassKey: `Public.services.dynamic.support.${index + 1}.titleStyleClass`,
|
||||||
|
titleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
`Public.services.dynamic.support.${index + 1}.titleStyleClass`,
|
||||||
|
'text-xl font-bold mb-4',
|
||||||
|
),
|
||||||
features: (item.features ?? []).map((feature, featureIndex) => ({
|
features: (item.features ?? []).map((feature, featureIndex) => ({
|
||||||
key:
|
key:
|
||||||
(isLikelyLocalizationKey(feature) ? feature : undefined) ||
|
(isLikelyLocalizationKey(feature) ? feature : undefined) ||
|
||||||
|
|
@ -143,16 +248,39 @@ function buildServicesContent(
|
||||||
supportButtonLabelKey: SERVICES_SUPPORT_BUTTON_KEY,
|
supportButtonLabelKey: SERVICES_SUPPORT_BUTTON_KEY,
|
||||||
ctaTitle: resolveLocalizedValue(translate, SERVICES_CTA_TITLE_KEY),
|
ctaTitle: resolveLocalizedValue(translate, SERVICES_CTA_TITLE_KEY),
|
||||||
ctaTitleKey: SERVICES_CTA_TITLE_KEY,
|
ctaTitleKey: SERVICES_CTA_TITLE_KEY,
|
||||||
|
ctaSectionStyleClassKey: SERVICES_CTA_SECTION_STYLE_KEY,
|
||||||
|
ctaSectionStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
SERVICES_CTA_SECTION_STYLE_KEY,
|
||||||
|
'bg-blue-900 text-white py-16',
|
||||||
|
),
|
||||||
|
ctaTitleStyleClassKey: SERVICES_CTA_TITLE_STYLE_KEY,
|
||||||
|
ctaTitleStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
SERVICES_CTA_TITLE_STYLE_KEY,
|
||||||
|
'text-3xl font-bold mb-6 text-white',
|
||||||
|
),
|
||||||
ctaDescription: resolveLocalizedValue(translate, SERVICES_CTA_DESCRIPTION_KEY),
|
ctaDescription: resolveLocalizedValue(translate, SERVICES_CTA_DESCRIPTION_KEY),
|
||||||
ctaDescriptionKey: SERVICES_CTA_DESCRIPTION_KEY,
|
ctaDescriptionKey: SERVICES_CTA_DESCRIPTION_KEY,
|
||||||
|
ctaDescriptionStyleClassKey: SERVICES_CTA_DESCRIPTION_STYLE_KEY,
|
||||||
|
ctaDescriptionStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
SERVICES_CTA_DESCRIPTION_STYLE_KEY,
|
||||||
|
'text-xl mb-8 max-w-2xl mx-auto',
|
||||||
|
),
|
||||||
ctaButtonLabel: resolveLocalizedValue(translate, SERVICES_CTA_BUTTON_KEY),
|
ctaButtonLabel: resolveLocalizedValue(translate, SERVICES_CTA_BUTTON_KEY),
|
||||||
ctaButtonLabelKey: SERVICES_CTA_BUTTON_KEY,
|
ctaButtonLabelKey: SERVICES_CTA_BUTTON_KEY,
|
||||||
|
ctaButtonStyleClassKey: SERVICES_CTA_BUTTON_STYLE_KEY,
|
||||||
|
ctaButtonStyleClass: resolveLocalizedValue(
|
||||||
|
translate,
|
||||||
|
SERVICES_CTA_BUTTON_STYLE_KEY,
|
||||||
|
'bg-white text-blue-900 px-8 py-3 rounded-lg font-semibold hover:bg-blue-50 transition-colors',
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Services: React.FC = () => {
|
const Services: React.FC = () => {
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
const navigate = useNavigate()
|
|
||||||
const { setLang } = useStoreActions((actions) => actions.locale)
|
const { setLang } = useStoreActions((actions) => actions.locale)
|
||||||
const { getConfig } = useStoreActions((actions) => actions.abpConfig)
|
const { getConfig } = useStoreActions((actions) => actions.abpConfig)
|
||||||
const configCultureName = useStoreState(
|
const configCultureName = useStoreState(
|
||||||
|
|
@ -249,11 +377,20 @@ const Services: React.FC = () => {
|
||||||
fieldKey === 'heroTitle' ||
|
fieldKey === 'heroTitle' ||
|
||||||
fieldKey === 'heroSubtitle' ||
|
fieldKey === 'heroSubtitle' ||
|
||||||
fieldKey === 'heroImage' ||
|
fieldKey === 'heroImage' ||
|
||||||
|
fieldKey === 'heroSectionStyleClass' ||
|
||||||
|
fieldKey === 'heroTitleStyleClass' ||
|
||||||
|
fieldKey === 'heroSubtitleStyleClass' ||
|
||||||
fieldKey === 'supportTitle' ||
|
fieldKey === 'supportTitle' ||
|
||||||
|
fieldKey === 'supportTitleStyleClass' ||
|
||||||
fieldKey === 'supportButtonLabel' ||
|
fieldKey === 'supportButtonLabel' ||
|
||||||
|
fieldKey === 'supportButtonStyleClass' ||
|
||||||
fieldKey === 'ctaTitle' ||
|
fieldKey === 'ctaTitle' ||
|
||||||
|
fieldKey === 'ctaSectionStyleClass' ||
|
||||||
|
fieldKey === 'ctaTitleStyleClass' ||
|
||||||
fieldKey === 'ctaDescription' ||
|
fieldKey === 'ctaDescription' ||
|
||||||
|
fieldKey === 'ctaDescriptionStyleClass' ||
|
||||||
fieldKey === 'ctaButtonLabel'
|
fieldKey === 'ctaButtonLabel'
|
||||||
|
|| fieldKey === 'ctaButtonStyleClass'
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
...current,
|
...current,
|
||||||
|
|
@ -360,18 +497,36 @@ const Services: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.heroTitle,
|
value: content.heroTitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroTitleStyleClass',
|
||||||
|
label: content.heroTitleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroTitleStyleClass,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'heroSubtitle',
|
key: 'heroSubtitle',
|
||||||
label: content.heroSubtitleKey,
|
label: content.heroSubtitleKey,
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: content.heroSubtitle,
|
value: content.heroSubtitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroSubtitleStyleClass',
|
||||||
|
label: content.heroSubtitleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroSubtitleStyleClass,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'heroImage',
|
key: 'heroImage',
|
||||||
label: content.heroImageKey,
|
label: content.heroImageKey,
|
||||||
type: 'image',
|
type: 'image',
|
||||||
value: content.heroImage,
|
value: content.heroImage,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'heroSectionStyleClass',
|
||||||
|
label: content.heroSectionStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.heroSectionStyleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -388,12 +543,24 @@ const Services: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.supportTitle,
|
value: content.supportTitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'supportTitleStyleClass',
|
||||||
|
label: content.supportTitleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.supportTitleStyleClass,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'supportButtonLabel',
|
key: 'supportButtonLabel',
|
||||||
label: content.supportButtonLabelKey,
|
label: content.supportButtonLabelKey,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.supportButtonLabel,
|
value: content.supportButtonLabel,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'supportButtonStyleClass',
|
||||||
|
label: content.supportButtonStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.supportButtonStyleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -410,18 +577,42 @@ const Services: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.ctaTitle,
|
value: content.ctaTitle,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'ctaTitleStyleClass',
|
||||||
|
label: content.ctaTitleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.ctaTitleStyleClass,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'ctaDescription',
|
key: 'ctaDescription',
|
||||||
label: content.ctaDescriptionKey,
|
label: content.ctaDescriptionKey,
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: content.ctaDescription,
|
value: content.ctaDescription,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'ctaDescriptionStyleClass',
|
||||||
|
label: content.ctaDescriptionStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.ctaDescriptionStyleClass,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'ctaButtonLabel',
|
key: 'ctaButtonLabel',
|
||||||
label: content.ctaButtonLabelKey,
|
label: content.ctaButtonLabelKey,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: content.ctaButtonLabel,
|
value: content.ctaButtonLabel,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'ctaButtonStyleClass',
|
||||||
|
label: content.ctaButtonStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.ctaButtonStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'ctaSectionStyleClass',
|
||||||
|
label: content.ctaSectionStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: content.ctaSectionStyleClass,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -458,6 +649,30 @@ const Services: React.FC = () => {
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
value: item.description,
|
value: item.description,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'cardStyleClass',
|
||||||
|
label: item.cardStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: item.cardStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'titleStyleClass',
|
||||||
|
label: item.titleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: item.titleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'descriptionStyleClass',
|
||||||
|
label: item.descriptionStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: item.descriptionStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'featureStyleClass',
|
||||||
|
label: item.featureStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: item.featureStyleClass,
|
||||||
|
},
|
||||||
...item.features.map((feature, featureIndex) => ({
|
...item.features.map((feature, featureIndex) => ({
|
||||||
key: `feature-${featureIndex}`,
|
key: `feature-${featureIndex}`,
|
||||||
label:
|
label:
|
||||||
|
|
@ -495,6 +710,18 @@ const Services: React.FC = () => {
|
||||||
type: 'text',
|
type: 'text',
|
||||||
value: item.title,
|
value: item.title,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'cardStyleClass',
|
||||||
|
label: item.cardStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: item.cardStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'titleStyleClass',
|
||||||
|
label: item.titleStyleClassKey,
|
||||||
|
type: 'text',
|
||||||
|
value: item.titleStyleClass,
|
||||||
|
},
|
||||||
...item.features.map((feature, featureIndex) => ({
|
...item.features.map((feature, featureIndex) => ({
|
||||||
key: `feature-${featureIndex}`,
|
key: `feature-${featureIndex}`,
|
||||||
label:
|
label:
|
||||||
|
|
@ -560,6 +787,72 @@ const Services: React.FC = () => {
|
||||||
value: feature.value,
|
value: feature.value,
|
||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
|
styleTexts: [
|
||||||
|
{
|
||||||
|
key: content.heroSectionStyleClassKey,
|
||||||
|
value: content.heroSectionStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.heroTitleStyleClassKey,
|
||||||
|
value: content.heroTitleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.heroSubtitleStyleClassKey,
|
||||||
|
value: content.heroSubtitleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.supportTitleStyleClassKey,
|
||||||
|
value: content.supportTitleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.supportButtonStyleClassKey,
|
||||||
|
value: content.supportButtonStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.ctaSectionStyleClassKey,
|
||||||
|
value: content.ctaSectionStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.ctaTitleStyleClassKey,
|
||||||
|
value: content.ctaTitleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.ctaDescriptionStyleClassKey,
|
||||||
|
value: content.ctaDescriptionStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: content.ctaButtonStyleClassKey,
|
||||||
|
value: content.ctaButtonStyleClass,
|
||||||
|
},
|
||||||
|
...content.serviceItems.flatMap((item) => [
|
||||||
|
{
|
||||||
|
key: item.cardStyleClassKey,
|
||||||
|
value: item.cardStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: item.titleStyleClassKey,
|
||||||
|
value: item.titleStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: item.descriptionStyleClassKey,
|
||||||
|
value: item.descriptionStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: item.featureStyleClassKey,
|
||||||
|
value: item.featureStyleClass,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
...content.supportItems.flatMap((item) => [
|
||||||
|
{
|
||||||
|
key: item.cardStyleClassKey,
|
||||||
|
value: item.cardStyleClass,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: item.titleStyleClassKey,
|
||||||
|
value: item.titleStyleClass,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
await getConfig(false)
|
await getConfig(false)
|
||||||
|
|
@ -628,7 +921,7 @@ const Services: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="relative bg-blue-900 text-white py-12">
|
<div className={content?.heroSectionStyleClass || 'relative bg-blue-900 text-white py-12'}>
|
||||||
<div
|
<div
|
||||||
className="absolute inset-0 opacity-20"
|
className="absolute inset-0 opacity-20"
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -638,8 +931,8 @@ const Services: React.FC = () => {
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
<div className="container mx-auto pt-20 relative">
|
<div className="container mx-auto pt-20 relative">
|
||||||
<h1 className="text-5xl font-bold ml-4 mt-3 mb-2 text-white">{content?.heroTitle}</h1>
|
<h1 className={content?.heroTitleStyleClass || 'text-5xl font-bold ml-4 mt-3 mb-2 text-white'}>{content?.heroTitle}</h1>
|
||||||
<p className="text-xl max-w-3xl ml-4">{content?.heroSubtitle}</p>
|
<p className={content?.heroSubtitleStyleClass || 'text-xl max-w-3xl ml-4'}>{content?.heroSubtitle}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SelectableBlock>
|
</SelectableBlock>
|
||||||
|
|
@ -658,17 +951,17 @@ const Services: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="bg-white rounded-xl shadow-lg p-8 hover:shadow-xl transition-shadow">
|
<div className={service.cardStyleClass || 'bg-white rounded-xl shadow-lg p-8 hover:shadow-xl transition-shadow'}>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
{IconComponent && (
|
{IconComponent && (
|
||||||
<IconComponent className={`w-12 h-12 ${getIconColor(index)}`} />
|
<IconComponent className={`w-12 h-12 ${getIconColor(index)}`} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-2xl font-bold text-gray-900 mb-4">{service.title}</h3>
|
<h3 className={service.titleStyleClass || 'text-2xl font-bold text-gray-900 mb-4'}>{service.title}</h3>
|
||||||
<p className="text-gray-600 mb-6">{service.description}</p>
|
<p className={service.descriptionStyleClass || 'text-gray-600 mb-6'}>{service.description}</p>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{(service.features ?? []).map((feature, fIndex) => (
|
{(service.features ?? []).map((feature, fIndex) => (
|
||||||
<li key={fIndex} className="flex items-center text-gray-700">
|
<li key={fIndex} className={service.featureStyleClass || 'flex items-center text-gray-700'}>
|
||||||
<span className="w-2 h-2 bg-blue-600 rounded-full mr-2"></span>
|
<span className="w-2 h-2 bg-blue-600 rounded-full mr-2"></span>
|
||||||
{feature.value}
|
{feature.value}
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -691,7 +984,7 @@ const Services: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<h2 className="text-3xl font-bold text-center mb-10">{content?.supportTitle}</h2>
|
<h2 className={content?.supportTitleStyleClass || 'text-3xl font-bold text-center mb-10'}>{content?.supportTitle}</h2>
|
||||||
</SelectableBlock>
|
</SelectableBlock>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
{content?.supportItems.map((plan, index) => {
|
{content?.supportItems.map((plan, index) => {
|
||||||
|
|
@ -705,13 +998,13 @@ const Services: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="bg-white rounded-xl shadow-lg p-8 border border-gray-200">
|
<div className={plan.cardStyleClass || 'bg-white rounded-xl shadow-lg p-8 border border-gray-200'}>
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
{IconComponent && (
|
{IconComponent && (
|
||||||
<IconComponent className={`w-12 h-12 ${getIconColor(index)}`} />
|
<IconComponent className={`w-12 h-12 ${getIconColor(index)}`} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-xl font-bold mb-4">{plan.title}</h3>
|
<h3 className={plan.titleStyleClass || 'text-xl font-bold mb-4'}>{plan.title}</h3>
|
||||||
<ul className="space-y-3 mb-8">
|
<ul className="space-y-3 mb-8">
|
||||||
{(plan.features ?? []).map((feature, fIndex) => (
|
{(plan.features ?? []).map((feature, fIndex) => (
|
||||||
<li key={fIndex} className="flex items-center space-x-2 text-gray-700">
|
<li key={fIndex} className="flex items-center space-x-2 text-gray-700">
|
||||||
|
|
@ -722,7 +1015,7 @@ const Services: React.FC = () => {
|
||||||
</ul>
|
</ul>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.public.contact}
|
to={ROUTES_ENUM.public.contact}
|
||||||
className="block text-center bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 transition-colors"
|
className={content?.supportButtonStyleClass || 'block text-center bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 transition-colors'}
|
||||||
>
|
>
|
||||||
{content?.supportButtonLabel}
|
{content?.supportButtonLabel}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
@ -741,13 +1034,13 @@ const Services: React.FC = () => {
|
||||||
isDesignMode={isDesignMode}
|
isDesignMode={isDesignMode}
|
||||||
onSelect={handleSelectBlock}
|
onSelect={handleSelectBlock}
|
||||||
>
|
>
|
||||||
<div className="bg-blue-900 text-white py-16">
|
<div className={content?.ctaSectionStyleClass || 'bg-blue-900 text-white py-16'}>
|
||||||
<div className="container mx-auto px-4 text-center">
|
<div className="container mx-auto px-4 text-center">
|
||||||
<h2 className="text-3xl font-bold mb-6 text-white">{content?.ctaTitle}</h2>
|
<h2 className={content?.ctaTitleStyleClass || 'text-3xl font-bold mb-6 text-white'}>{content?.ctaTitle}</h2>
|
||||||
<p className="text-xl mb-8 max-w-2xl mx-auto">{content?.ctaDescription}</p>
|
<p className={content?.ctaDescriptionStyleClass || 'text-xl mb-8 max-w-2xl mx-auto'}>{content?.ctaDescription}</p>
|
||||||
<Link
|
<Link
|
||||||
to={ROUTES_ENUM.public.contact}
|
to={ROUTES_ENUM.public.contact}
|
||||||
className="bg-white text-blue-900 px-8 py-3 rounded-lg font-semibold hover:bg-blue-50 transition-colors"
|
className={content?.ctaButtonStyleClass || 'bg-white text-blue-900 px-8 py-3 rounded-lg font-semibold hover:bg-blue-50 transition-colors'}
|
||||||
>
|
>
|
||||||
{content?.ctaButtonLabel}
|
{content?.ctaButtonLabel}
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,14 @@ const SAFELIST_COLORS = 'colors'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}', './safelist.txt'],
|
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}', './safelist.txt'],
|
||||||
|
safelist: [
|
||||||
|
{
|
||||||
|
// Covers most utility groups used by designer-entered class strings.
|
||||||
|
pattern:
|
||||||
|
/^(container|block|inline-block|inline-flex|hidden|absolute|relative|fixed|sticky|top-|right-|bottom-|left-|z-|w-|h-|min-w-|min-h-|max-w-|max-h-|m-|mx-|my-|mt-|mr-|mb-|ml-|p-|px-|py-|pt-|pr-|pb-|pl-|space-x-|space-y-|gap-|grid|grid-cols-|col-span-|row-span-|flex|flex-col|flex-row|flex-wrap|items-|justify-|self-|content-|overflow-|truncate|rounded|rounded-|border|border-|shadow|shadow-|text-|font-|leading-|tracking-|uppercase|lowercase|capitalize|bg-|from-|via-|to-|opacity-|backdrop-blur|transition|duration-|ease-|transform|scale-|rotate-|translate-|cursor-|select-|pointer-events-|ring-|outline-|whitespace-|break-|object-|aspect-|prose|prose-.*)$/,
|
||||||
|
variants: ['hover', 'focus', 'active', 'dark', 'sm', 'md', 'lg', 'xl', '2xl'],
|
||||||
|
},
|
||||||
|
],
|
||||||
darkMode: 'class',
|
darkMode: 'class',
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue