wagtail-enap-designsystem 1.2.1.136__py3-none-any.whl → 1.2.1.138__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (19) hide show
  1. enap_designsystem/blocks/__init__.py +2 -0
  2. enap_designsystem/blocks/form.py +160 -24
  3. enap_designsystem/blocks/html_blocks.py +39 -15
  4. enap_designsystem/blocks/semana_blocks.py +4 -0
  5. enap_designsystem/settings.py +2 -2
  6. enap_designsystem/templates/enap_designsystem/blocks/apresentacao_block.html +1 -2
  7. enap_designsystem/templates/enap_designsystem/blocks/cards_titles.html +35 -5
  8. enap_designsystem/templates/enap_designsystem/blocks/job_vacancy_filtered_block.html +7 -0
  9. enap_designsystem/templates/enap_designsystem/blocks/logos_simple_block.html +1 -1
  10. enap_designsystem/templates/enap_designsystem/blocks/numeros_block.html +58 -179
  11. enap_designsystem/templates/enap_designsystem/blocks/video_hero_banner.html +23 -9
  12. enap_designsystem/templates/enap_designsystem/form_templates/formulario_page.html +397 -1080
  13. enap_designsystem/templates/enap_designsystem/includes/form_field.html +935 -1
  14. enap_designsystem/templates/enap_designsystem/sistema_votacao_page.html +76 -18
  15. {wagtail_enap_designsystem-1.2.1.136.dist-info → wagtail_enap_designsystem-1.2.1.138.dist-info}/METADATA +1 -1
  16. {wagtail_enap_designsystem-1.2.1.136.dist-info → wagtail_enap_designsystem-1.2.1.138.dist-info}/RECORD +19 -19
  17. {wagtail_enap_designsystem-1.2.1.136.dist-info → wagtail_enap_designsystem-1.2.1.138.dist-info}/WHEEL +0 -0
  18. {wagtail_enap_designsystem-1.2.1.136.dist-info → wagtail_enap_designsystem-1.2.1.138.dist-info}/licenses/LICENSE +0 -0
  19. {wagtail_enap_designsystem-1.2.1.136.dist-info → wagtail_enap_designsystem-1.2.1.138.dist-info}/top_level.txt +0 -0
@@ -132,6 +132,7 @@ from .html_blocks import SuapEventsBlock
132
132
  from .html_blocks import EventsCarouselBlock
133
133
  from .html_blocks import DropdownBlock
134
134
  from .html_blocks import ClientesBlock
135
+ from .html_blocks import VideoHeroBannerBlock
135
136
 
136
137
 
137
138
  from .html_blocks import ButtonBlock, ImageBlock, RichTextBlock, QuoteBlock
@@ -205,6 +206,7 @@ class BannerStreamBlock(StreamBlock):
205
206
  banner_image_cta = Banner_Image_cta(label="🖼️ Banner Imagem + CTA")
206
207
  hero = HeroBlockv3(label="⭐ Hero Moderno")
207
208
  hero_animada = HeroAnimadaBlock(label="🎬 Hero Animado")
209
+ video_hero_banner = VideoHeroBannerBlock(label="Banner com video")
208
210
 
209
211
  class Meta:
210
212
  label = "🎨 Banners e Heroes"
@@ -662,7 +662,7 @@ class CheckboxMultiRedirectFieldBlock(blocks.StructBlock):
662
662
 
663
663
  class Meta:
664
664
  icon = "redirect"
665
- label = "☑️🔀 Checkbox Multi-Redirecionamento"
665
+ label = "🔀 Checkbox Multi-Redirecionamento"
666
666
 
667
667
 
668
668
  class ConditionalFieldBlock(blocks.StructBlock):
@@ -1870,46 +1870,78 @@ class FormularioPage(Page):
1870
1870
 
1871
1871
  return total_score, score_details
1872
1872
 
1873
+ # Substituir o método get_all_steps() na classe FormularioPage
1874
+
1873
1875
  def get_all_steps(self):
1874
- """Retorna todas as etapas organizadas com seções - COM ORDENAÇÃO"""
1876
+ """PROCESSA CAMPOS SEM ANINHAMENTO INFINITO - VERSÃO CORRIGIDA"""
1875
1877
  steps = []
1876
1878
 
1877
- # DEBUG TEMPORÁRIO
1878
- print(f"=== GET_ALL_STEPS - PROCESSANDO {len(self.form_steps)} STEPS ===")
1879
+ def extract_fields_safely(fields, depth=0, max_depth=3):
1880
+ """
1881
+ Extrai campos com limite de profundidade para evitar aninhamento infinito
1882
+ """
1883
+ if depth > max_depth:
1884
+ print(f"⚠️ Limite de profundidade atingido no nível {depth}")
1885
+ return []
1886
+
1887
+ extracted_fields = []
1888
+
1889
+ for field_block in fields:
1890
+ # Sempre adicionar o campo principal
1891
+ extracted_fields.append(field_block)
1892
+
1893
+ # Processar campos aninhados apenas se necessário
1894
+ if hasattr(field_block, 'value') and isinstance(field_block.value, dict):
1895
+
1896
+ # Campos condicionais normais
1897
+ if field_block.block_type == 'conditional_field_condicional':
1898
+ conditional_options = field_block.value.get('conditional_options_con', [])
1899
+ for option in conditional_options:
1900
+ if hasattr(option, 'value') and 'fields_to_show_con' in option.value:
1901
+ nested_fields = option.value['fields_to_show_con']
1902
+ # NÃO adicionar aqui - será processado pelo frontend
1903
+ print(f"Campo condicional encontrado com {len(nested_fields)} campos aninhados")
1904
+
1905
+ # Campos multi-redirect
1906
+ elif field_block.block_type == 'checkbox_multi_redirect_field':
1907
+ redirect_options = field_block.value.get('redirect_options', [])
1908
+ for option in redirect_options:
1909
+ if hasattr(option, 'value') and 'fields_to_show' in option.value:
1910
+ nested_fields = option.value['fields_to_show']
1911
+ # NÃO adicionar aqui - será processado pelo frontend
1912
+ print(f"Campo multi-redirect encontrado com {len(nested_fields)} campos aninhados")
1913
+
1914
+ return extracted_fields
1879
1915
 
1880
- # Criar lista de steps com ordem
1881
- steps_with_order = []
1916
+ print(f"=== PROCESSANDO {len(self.form_steps)} STEPS (Versão Corrigida) ===")
1917
+
1918
+ # Processar cada step
1882
1919
  for index, step_block in enumerate(self.form_steps):
1883
1920
  order = step_block.value.get('order', str(index + 1))
1884
- print(f"Step {index}: order='{order}'")
1885
-
1886
1921
  try:
1887
1922
  order_num = int(order) if order else index + 1
1888
1923
  except (ValueError, TypeError):
1889
1924
  order_num = index + 1
1890
1925
 
1891
- steps_with_order.append((order_num, index, step_block))
1892
-
1893
- # Ordenar por order_num
1894
- steps_with_order.sort(key=lambda x: x[0])
1895
- print(f"Ordem final: {[(x[0], x[1]) for x in steps_with_order]}")
1896
-
1897
- # Processar steps na ordem correta
1898
- for position, (order_num, original_index, step_block) in enumerate(steps_with_order):
1926
+ # Extrair campos de forma segura (sem recursão infinita)
1927
+ step_fields = extract_fields_safely(step_block.value['fields'])
1928
+
1899
1929
  step_data = {
1900
- 'number': position + 1,
1901
- 'original_number': original_index + 1,
1930
+ 'number': index + 1,
1931
+ 'original_number': index + 1,
1902
1932
  'order': order_num,
1903
1933
  'logo': step_block.value.get('logo'),
1904
1934
  'logo_alt': step_block.value.get('logo_alt', ''),
1905
- 'fields': step_block.value['fields'],
1935
+ 'fields': step_fields, # Apenas campos do nível principal
1906
1936
  'id': step_block.id,
1907
1937
  'sections': []
1908
1938
  }
1909
1939
 
1910
- # Organizar campos em seções
1940
+ print(f"✅ Step {index + 1}: {len(step_fields)} campos (sem aninhamento)")
1941
+
1942
+ # Organizar em seções
1911
1943
  current_section = None
1912
- for field_block in step_block.value['fields']:
1944
+ for field_block in step_fields:
1913
1945
  if field_block.block_type == 'section_header':
1914
1946
  current_section = {
1915
1947
  'title': field_block.value['title'],
@@ -1925,14 +1957,118 @@ class FormularioPage(Page):
1925
1957
  'fields': []
1926
1958
  }
1927
1959
  step_data['sections'].append(current_section)
1928
-
1929
1960
  current_section['fields'].append(field_block)
1930
1961
 
1931
1962
  steps.append(step_data)
1932
- print(f"Step processado: {position + 1} (ordem {order_num})")
1933
1963
 
1934
- print(f"=== RETORNANDO {len(steps)} STEPS ===")
1964
+ total_fields = sum(len(step['fields']) for step in steps)
1965
+ print(f"🎉 RESULTADO: {len(steps)} steps com {total_fields} campos principais")
1966
+
1935
1967
  return steps
1968
+
1969
+
1970
+ # TAMBÉM ADICIONAR este método para extrair dados condicionais de forma mais limpa
1971
+
1972
+ def build_conditional_data(self):
1973
+ """Constrói dados condicionais de forma mais organizada"""
1974
+ conditional_data = {}
1975
+
1976
+ for step_index, step_block in enumerate(self.form_steps):
1977
+ for field_block in step_block.value['fields']:
1978
+ field_id = f"{field_block.block_type}_{field_block.id}"
1979
+
1980
+ # Campos condicionais "condicional"
1981
+ if field_block.block_type == 'conditional_field_condicional':
1982
+ options_data = {}
1983
+
1984
+ for option in field_block.value.get('conditional_options_con', []):
1985
+ option_value = option.value['value_con']
1986
+ action = option.value['action_con']
1987
+
1988
+ if action == 'show_fields_con':
1989
+ # Extrair IDs dos campos que devem aparecer
1990
+ nested_field_ids = []
1991
+ for nested_field in option.value.get('fields_to_show_con', []):
1992
+ nested_id = f"{nested_field.block_type}_{nested_field.id}"
1993
+ nested_field_ids.append(nested_id)
1994
+
1995
+ options_data[option_value] = {
1996
+ 'action': 'show_fields',
1997
+ 'field_ids': nested_field_ids
1998
+ }
1999
+ else:
2000
+ options_data[option_value] = {
2001
+ 'action': 'nothing'
2002
+ }
2003
+
2004
+ conditional_data[field_id] = {
2005
+ 'type': 'conditional_field_condicional',
2006
+ 'options': options_data
2007
+ }
2008
+
2009
+ # Campos multi-redirect
2010
+ elif field_block.block_type == 'checkbox_multi_redirect_field':
2011
+ options_data = {}
2012
+
2013
+ for option in field_block.value.get('redirect_options', []):
2014
+ option_value = option.value['value']
2015
+ action = option.value['action']
2016
+
2017
+ if action == 'show_fields':
2018
+ nested_field_ids = []
2019
+ for nested_field in option.value.get('fields_to_show', []):
2020
+ nested_id = f"{nested_field.block_type}_{nested_field.id}"
2021
+ nested_field_ids.append(nested_id)
2022
+
2023
+ options_data[option_value] = {
2024
+ 'action': 'show_fields',
2025
+ 'field_ids': nested_field_ids
2026
+ }
2027
+ else:
2028
+ options_data[option_value] = {
2029
+ 'action': action
2030
+ }
2031
+
2032
+ conditional_data[field_id] = {
2033
+ 'type': 'checkbox_multi_redirect_field',
2034
+ 'field_type': field_block.value.get('field_type', 'checkbox'),
2035
+ 'options': options_data
2036
+ }
2037
+
2038
+ return conditional_data
2039
+
2040
+
2041
+ # SUBSTITUIR também o método get_context para incluir os dados condicionais corretos
2042
+
2043
+ def get_context(self, request, *args, **kwargs):
2044
+ """Adiciona contexto personalizado - VERSÃO CORRIGIDA"""
2045
+ context = super().get_context(request, *args, **kwargs)
2046
+
2047
+ # Informações básicas dos steps
2048
+ context['total_form_steps'] = len(self.form_steps)
2049
+ context['all_steps'] = self.get_all_steps()
2050
+
2051
+ # Dados condicionais organizados
2052
+ conditional_data = self.build_conditional_data()
2053
+ context['conditional_data_json'] = json.dumps(conditional_data)
2054
+
2055
+ # Extrair nome do usuário
2056
+ full_name = 'Usuário'
2057
+ if request.method == 'POST':
2058
+ for key, value in request.POST.items():
2059
+ if key.startswith('nome_completo_field_') and value:
2060
+ full_name = value.strip()
2061
+ break
2062
+
2063
+ context['full_name'] = full_name
2064
+
2065
+ # Status de sucesso
2066
+ if request.GET.get('success'):
2067
+ context['form_success'] = True
2068
+ context['email_sent'] = request.GET.get('email_sent') == '1'
2069
+ context['admin_notified'] = request.GET.get('admin_notified') == '1'
2070
+
2071
+ return context
1936
2072
  class Meta:
1937
2073
  verbose_name = "Formulário Dinâmico"
1938
2074
  verbose_name_plural = "Formulários Dinâmicos"
@@ -53,7 +53,7 @@ BRAND_COLOR_CHOICES = [
53
53
  ('#007D7A', 'Verde Link ENAP (#007D7A)'),
54
54
  ('#AD6BFC', 'Roxo Gnova (#AD6BFC)'),
55
55
  ('#B396FC', 'Roxo Claro Gnova (#B396FC)'),
56
- ('#FFFFFF', 'Branco (#FFFFFF)'),
56
+ ('#2F134F', 'Roxo Escuro LIIA (#2F134F)'),
57
57
  ]
58
58
 
59
59
  ENAP_GREEN_COLORS = [
@@ -69,6 +69,7 @@ ENAP_GREEN_COLORS = [
69
69
  ('#FFFFFF', 'Branco (#FFFFFF)'),
70
70
  ('#F8F9FA', 'Cinza Claro (#F8F9FA)'),
71
71
  ('#E9ECEF', 'Cinza Médio (#E9ECEF)'),
72
+ ('#525258', 'Cinza Escuro (#525258)'),
72
73
  ]
73
74
 
74
75
  BACKGROUND_COLOR_CHOICES = [
@@ -7912,19 +7913,12 @@ class NumerosBlock(blocks.StructBlock):
7912
7913
  default='#FFFFFF',
7913
7914
  help_text="Cor de fundo do quadrado de conteúdo"
7914
7915
  )
7915
-
7916
- # Grid de cards
7917
- tipo_grid_numeros = blocks.ChoiceBlock(
7918
- choices=[
7919
- ('numeros-grid-1', '1 card por linha'),
7920
- ('numeros-grid-2', 'Até 2 cards por linha'),
7921
- ('numeros-grid-3', 'Até 3 cards por linha'),
7922
- ('numeros-grid-4', 'Até 4 cards por linha'),
7923
- ('numeros-grid-5', 'Até 5 cards por linha'),
7924
- ],
7925
- default='numeros-grid-4',
7926
- help_text="Quantos cards por linha no desktop",
7927
- label="Layout do grid de números"
7916
+
7917
+ cor_line = blocks.ChoiceBlock(
7918
+ choices=BACKGROUND_COLOR_CHOICES,
7919
+ default='#FFF0D9',
7920
+ help_text="Cor do da linha debaixo",
7921
+ required=False
7928
7922
  )
7929
7923
 
7930
7924
  # Lista de cards de números
@@ -7966,4 +7960,34 @@ class NumerosBlock(blocks.StructBlock):
7966
7960
  template = 'enap_designsystem/blocks/numeros_block.html'
7967
7961
  icon = 'snippet'
7968
7962
  label = 'Grid de Números/Estatísticas'
7969
- help_text = 'Componente para exibir números e estatísticas importantes'
7963
+ help_text = 'Componente para exibir números e estatísticas importantes'
7964
+
7965
+ class VideoHeroBannerBlock(blocks.StructBlock):
7966
+
7967
+ background_image = ImageChooserBlock(required=False, help_text="Imagem de fundo para o banner.")
7968
+
7969
+ cor_fundo = blocks.ChoiceBlock(
7970
+ choices=BACKGROUND_COLOR_CHOICES,
7971
+ required=False,
7972
+ default='#F8F9FA', # Cinza claro ENAP
7973
+ help_text="Cor de fundo do componente"
7974
+ )
7975
+
7976
+ altura_banner = blocks.CharBlock(required=False, help_text="Altura do banner (ex: 600px, 80vh).")
7977
+
7978
+ video_file = DocumentChooserBlock(
7979
+ label="Arquivo de vídeo",
7980
+ required=False,
7981
+ help_text="Upload direto do arquivo de vídeo (MP4, WebM, etc.)"
7982
+ )
7983
+
7984
+ titulo = blocks.CharBlock(required=False, help_text="Título principal.")
7985
+
7986
+ subtitulo = blocks.RichTextBlock(required=False, help_text="Subtítulo com suporte a formatação.")
7987
+
7988
+ logo = ImageChooserBlock(required=False, help_text="Logo sobre o banner.")
7989
+
7990
+ class Meta:
7991
+ template = "enap_designsystem/blocks/video_hero_banner.html"
7992
+ icon = "media"
7993
+ label = "Video Hero Banner"
@@ -70,6 +70,10 @@ BRAND_TEXTS_CHOICES = [
70
70
  # Cores para backgrounds - removendo duplicatas
71
71
  BRAND_BG_CHOICES = [
72
72
  ('#FFFFFF', 'Branco (#FFFFFF)'),
73
+ ('transparent', 'Transparente'),
74
+ ('rgba(0,0,0,0)', 'Transparente (rgba)'),
75
+ ('rgba(255,255,255,0.5)', 'Branco Semi-transparente'),
76
+ ('rgba(0,0,0,0.5)', 'Preto Semi-transparente'),
73
77
  ('#F8F9FA', 'Cinza Claro (#F8F9FA)'),
74
78
  ('#000000', 'Preto (#000000)'),
75
79
  ('enap-green', 'Verde ENAP'),
@@ -4,7 +4,7 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
4
4
 
5
5
  RECAPTCHA_PUBLIC_KEY = "6Lf_9MMrAAAAAOAsVXk8F5scxr6vsZJzC2jJnGHb"
6
6
  RECAPTCHA_PRIVATE_KEY = "6Lf_9MMrAAAAAJqd_uA1_ekq3F-bD24KRhBcfKCF"
7
-
7
+ DATA_UPLOAD_MAX_NUMBER_FIELDS = 9000000
8
8
  WAGTAIL_404_TEMPLATE = '404.html'
9
9
 
10
10
  STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
@@ -25,4 +25,4 @@ TEMPLATES = [
25
25
  ],
26
26
  },
27
27
  },
28
- ]
28
+ ]
@@ -16,8 +16,7 @@
16
16
  <!-- Quadrado de conteúdo -->
17
17
  <div class="apresentacao-conteudo-box rounded-lg mb-8 shadow-lg text-left"
18
18
  style="background-color: {{ value.cor_quadrado }};">
19
- <div class="apresentacao-texto leading-relaxed"
20
- style="color: {{ value.cor_titulo }};">
19
+ <div class="apresentacao-texto leading-relaxed">
21
20
  {{ value.conteudo|richtext }}
22
21
  </div>
23
22
  </div>
@@ -13,7 +13,7 @@
13
13
  <div class="secao-overlay">
14
14
 
15
15
  <!-- Container principal -->
16
- <div class="container mx-auto px-4 py-16 lg:py-24">
16
+ <div class="container titulo-cards mx-auto px-4 py-16 lg:py-24">
17
17
 
18
18
  <!-- Título centralizado -->
19
19
  {% if value.titulo %}
@@ -98,13 +98,13 @@
98
98
  <style>
99
99
  .secao-apresentacao-cards {
100
100
  position: relative;
101
- min-height: 600px;
101
+ min-height: 500px;
102
102
  }
103
103
 
104
104
  .secao-background {
105
105
  position: relative;
106
106
  width: 100%;
107
- min-height: 600px;
107
+ min-height: 500px;
108
108
  }
109
109
 
110
110
  .secao-overlay {
@@ -115,15 +115,36 @@
115
115
  bottom: 0;
116
116
  background: rgba(106, 27, 154, 0.15);
117
117
  backdrop-filter: blur(0.5px);
118
+ display: flex;
119
+ }
120
+
121
+ .card-item {
122
+ width: 300px;
123
+ flex: 0 0 268px;
124
+ display: flex;
125
+ flex-direction: column;
126
+ align-items: center;
127
+ justify-content: center;
128
+ text-align: center;
129
+ height: 230px;
130
+ background-color: rgba(106, 27, 154, 0.15);
131
+ box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.16);
132
+ color: #1351b4;
133
+ font-weight: 500;
134
+ padding: 0px;
135
+ text-decoration: none;
136
+ border-radius: 20px;
118
137
  }
119
138
 
120
139
  .titulo-secao {
121
- font-size: 2.5rem;
122
- font-weight: 700;
123
140
  line-height: 1.2;
124
141
  text-align: center;
125
142
  margin-bottom: 0;
126
143
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
144
+ font-weight: 500;
145
+ font-style: Medium;
146
+ font-size: 48px;
147
+ letter-spacing: 0px;
127
148
  }
128
149
 
129
150
  .cards-container {
@@ -197,6 +218,7 @@
197
218
  flex: 1;
198
219
  display: flex;
199
220
  flex-direction: column;
221
+ align-items: flex-start;
200
222
  }
201
223
 
202
224
  .card-titulo {
@@ -205,6 +227,7 @@
205
227
  margin-bottom: 0.5rem;
206
228
  line-height: 1.4;
207
229
  color: #FFFFFF;
230
+ text-align: left;
208
231
  }
209
232
 
210
233
  .card-subtitulo {
@@ -305,5 +328,12 @@
305
328
  font-size: 1rem;
306
329
  }
307
330
  }
331
+
332
+ .titulo-cards{
333
+ display: flex;
334
+ flex-direction: column;
335
+ justify-content: center;
336
+ gap: 48px;
337
+ }
308
338
  </style></document_content>
309
339
  </invoke>
@@ -117,6 +117,13 @@
117
117
  align-items: center;
118
118
  }
119
119
 
120
+ .image-curso {
121
+ width: 100%;
122
+ border-radius: 12px;
123
+ overflow: hidden;
124
+ height: auto;
125
+ }
126
+
120
127
  .space-10px{
121
128
  display: flex;
122
129
  flex-direction: column;
@@ -21,7 +21,7 @@
21
21
  {% for logo_card in value.lista_logos %}
22
22
  <div class="logo-card {% if value.centralizar_logos %}text-center{% endif %}">
23
23
  <div class="logo-image-container">
24
- {% image logo_card.logo fill-200x200 class="logo-image" alt="Logo" %}
24
+ {% image logo_card.logo original class="logo-image" alt="Logo" %}
25
25
  </div>
26
26
  </div>
27
27
  {% endfor %}