<?phpuse Twig\Environment;use Twig\Error\LoaderError;use Twig\Error\RuntimeError;use Twig\Extension\CoreExtension;use Twig\Extension\SandboxExtension;use Twig\Markup;use Twig\Sandbox\SecurityError;use Twig\Sandbox\SecurityNotAllowedTagError;use Twig\Sandbox\SecurityNotAllowedFilterError;use Twig\Sandbox\SecurityNotAllowedFunctionError;use Twig\Sandbox\SecurityNotAllowedTestError;use Twig\Source;use Twig\Template;use Twig\TemplateWrapper;/* application/whileresume/application/jobs/dashboard.html.twig */class __TwigTemplate_e306429a77277e7ea85b497d31a6c7ce extends Template{ private Source $source; /** * @var array<string, Template> */ private array $macros = []; public function __construct(Environment $env) { parent::__construct($env); $this->source = $this->getSourceContext(); $this->blocks = [ 'title' => [$this, 'block_title'], 'description' => [$this, 'block_description'], 'robots' => [$this, 'block_robots'], 'css' => [$this, 'block_css'], 'body' => [$this, 'block_body'], 'footerjs' => [$this, 'block_footerjs'], ]; } protected function doGetParent(array $context): bool|string|Template|TemplateWrapper { // line 1 return "application/whileresume/application/jobs/layout-social.html.twig"; } protected function doDisplay(array $context, array $blocks = []): iterable { $macros = $this->macros; $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"]; $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "application/whileresume/application/jobs/dashboard.html.twig")); $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"]; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "application/whileresume/application/jobs/dashboard.html.twig")); // line 5 $macros["promo"] = $this->macros["promo"] = $this->load("application/whileresume/_macros/promo_card.html.twig", 5)->unwrap(); // line 1 $this->parent = $this->load("application/whileresume/application/jobs/layout-social.html.twig", 1); yield from $this->parent->unwrap()->yield($context, array_merge($this->blocks, $blocks)); $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof); $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof); } // line 7 /** * @return iterable<null|scalar|\Stringable> */ public function block_title(array $context, array $blocks = []): iterable { $macros = $this->macros; $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"]; $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "title")); $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"]; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "title")); if ((((array_key_exists("currentSubKeyword", $context) && !(null === (isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword", $context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.', 7, $this->source); })()))) && array_key_exists("currentCityFilter", $context)) && !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 7, $this->source); })())))) { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword", $context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.', 7, $this->source); })()), "html", null, true); yield " "; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 7, $this->source); })()), "label", [], "any", false, false, false, 7), "html", null, true); } elseif ((array_key_exists("currentFilter", $context) && !(null === (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 7, $this->source); })())))) { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env, $this->source, ($context["currentFilter"] ?? null), "shortTitle", [], "any", true, true, false, 7)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 7, $this->source); })()), "shortTitle", [], "any", false, false, false, 7), CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 7, $this->source); })()), "label", [], "any", false, false, false, 7))) : (CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 7, $this->source); })()), "label", [], "any", false, false, false, 7))), "html", null, true); yield " — WhileResume"; } else { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.title", [], "whr-public"), "html", null, true); } $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof); $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof); yield from []; } // line 8 /** * @return iterable<null|scalar|\Stringable> */ public function block_description(array $context, array $blocks = []): iterable { $macros = $this->macros; $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"]; $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "description")); $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"]; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "description")); if ((((array_key_exists("currentSubKeyword", $context) && !(null === (isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword", $context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.', 8, $this->source); })()))) && array_key_exists("currentCityFilter", $context)) && !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 8, $this->source); })())))) { yield "Découvrez les offres \""; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword", $context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.', 8, $this->source); })()), "html", null, true); yield "\" à "; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 8, $this->source); })()), "label", [], "any", false, false, false, 8), "html", null, true); yield "."; } elseif (((array_key_exists("currentFilter", $context) && !(null === (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 8, $this->source); })()))) && !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 8, $this->source); })()), "shortDescription", [], "any", false, false, false, 8)))) { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 8, $this->source); })()), "shortDescription", [], "any", false, false, false, 8), "html", null, true); } else { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.description", [], "whr-public"), "html", null, true); } $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof); $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof); yield from []; } // line 9 /** * @return iterable<null|scalar|\Stringable> */ public function block_robots(array $context, array $blocks = []): iterable { $macros = $this->macros; $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"]; $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "robots")); $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"]; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "robots")); yield "index,follow"; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof); $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof); yield from []; } // line 11 /** * @return iterable<null|scalar|\Stringable> */ public function block_css(array $context, array $blocks = []): iterable { $macros = $this->macros; $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"]; $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "css")); $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"]; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "css")); // line 12 yield " <style> /* ─── Page dashboard /jobs ─── */ .jobs-dash{max-width:880px;margin:0 auto} .jobs-dash-header{margin-bottom:18px} .jobs-dash-title{font-size:24px;font-weight:800;color:#1E1B2E;line-height:1.2;letter-spacing:-0.02em;margin:0 0 6px} @media(min-width:768px){.jobs-dash-title{font-size:28px}} .jobs-dash-subtitle{font-size:14px;color:#6B7280;margin:0 0 18px} /* ─── Bandeau contexte ville (badge + bouton ALL) ─── */ .city-context-bar{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0 0 16px;padding:10px 14px;background:#F5F3FF;border:1px solid rgba(108,58,237,.15);border-radius:12px} .city-context-label{font-size:11px;font-weight:600;color:#6B7280;text-transform:uppercase;letter-spacing:.06em} .city-context-badge{display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:100px;background:#fff;color:var(--theme-color,#6C3AED);font-size:13px;font-weight:600;border:1px solid rgba(108,58,237,.2)} .city-context-badge-icon{font-size:14px;line-height:1} .city-context-clear-btn{margin-left:auto;display:inline-flex;align-items:center;gap:4px;padding:5px 12px;border-radius:100px;background:transparent;color:var(--theme-color,#6C3AED);font-size:12px;font-weight:600;border:1px dashed rgba(108,58,237,.4);cursor:pointer;text-decoration:none;font-family:inherit;transition:background .15s,border-style .15s,border-color .15s} .city-context-clear-btn:hover{background:#fff;border-style:solid;border-color:var(--theme-color,#6C3AED);color:var(--theme-color,#6C3AED)} .city-context-clear-btn svg{width:11px;height:11px} /* Widget recherche */ .wr-search-widget{background:#fff;border-radius:14px;box-shadow:0 0 20px 0 rgba(0,0,0,0.05);padding:10px;margin-bottom:14px;position:relative;z-index:50} .wr-search-input-wrap{display:flex;align-items:center;gap:10px;padding:8px 14px;border-radius:10px;background:#F9FAFB;border:1px solid #E5E7EB;transition:border-color .2s,background .2s} .wr-search-input-wrap:focus-within{border-color:rgba(108,58,237,.3);background:#fff} .wr-search-icon{color:#9CA3AF;display:flex;flex-shrink:0} .wr-search-input{flex:1;border:none;outline:none;background:transparent;font-size:14px;color:#1E1B2E;padding:4px 0;font-family:inherit;min-width:0} .wr-search-input::placeholder{color:#9CA3AF} .wr-search-clear{background:none;border:none;color:#9CA3AF;cursor:pointer;padding:4px;display:none;font-family:inherit} .wr-search-clear.visible{display:flex;align-items:center} .wr-search-clear:hover{color:#6B7280} .wr-search-clear svg{width:14px;height:14px} .wr-search-kbd-hint{display:none;align-items:center;padding:3px 8px;background:#fff;border:1px solid #E5E7EB;border-radius:6px;font-size:10.5px;font-weight:600;color:#6B7280;font-family:inherit;letter-spacing:.02em;white-space:nowrap;flex-shrink:0} .wr-search-input-wrap:focus-within .wr-search-kbd-hint{display:inline-flex} /* Chips keywords */ .search-keywords{display:flex;flex-wrap:wrap;gap:6px;margin:0 4px 18px} .search-keyword-chip{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:100px;background:#F5F3FF;color:var(--theme-color,#6C3AED);font-size:12.5px;font-weight:500;cursor:pointer;border:1px solid transparent;transition:background .15s,border-color .15s,transform .15s;font-family:inherit} .search-keyword-chip:hover{background:#EDE9FE;border-color:rgba(108,58,237,.2);transform:translateY(-1px);color:var(--theme-color,#6C3AED)} .search-keyword-chip.active{background:var(--theme-color,#6C3AED);color:#fff;border-color:var(--theme-color,#6C3AED)} .search-keyword-chip-icon{font-size:13px;line-height:1} .search-keywords-label{font-size:11px;font-weight:600;color:#9CA3AF;text-transform:uppercase;letter-spacing:.06em;margin-right:4px;align-self:center} /* ─── Sections de filtres SEO (chips → liens directs vers /jobs/{slug}) ─── */ .filter-section{margin:0 0 14px} .filter-section-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;padding:0 4px;flex-wrap:wrap} @media(max-width:540px){ .dash-filter-search{max-width:100%;width:100%} } .filter-section-title{display:flex;align-items:center;gap:7px;font-size:11.5px;font-weight:700;color:#6B7280;text-transform:uppercase;letter-spacing:.06em;margin:0} .filter-section-title-icon{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:6px;background:#F5F3FF;color:var(--theme-color,#6C3AED)} .filter-section-title-icon svg{width:11px;height:11px} .filter-section-toggle{background:none;border:none;font-size:11px;color:var(--theme-color,#6C3AED);font-weight:600;cursor:pointer;font-family:inherit;padding:4px 8px;border-radius:6px;transition:background .15s} .filter-section-toggle:hover{background:#F5F3FF} .filter-chips{display:flex;flex-wrap:wrap;gap:6px;padding:0 4px} .filter-chip{display:inline-flex;align-items:center;gap:5px;padding:7px 13px;border-radius:100px;background:#fff;color:#374151;font-size:12.5px;font-weight:500;cursor:pointer;border:1px solid #E5E7EB;text-decoration:none;transition:background .15s,border-color .15s,transform .15s,color .15s;font-family:inherit;white-space:nowrap} .filter-chip:hover{background:#F5F3FF;border-color:rgba(108,58,237,.3);color:var(--theme-color,#6C3AED);transform:translateY(-1px)} .filter-chip.active{background:var(--theme-color,#6C3AED);border-color:var(--theme-color,#6C3AED);color:#fff} .filter-chip.active:hover{background:#5B21B6;color:#fff} .filter-chip-icon{font-size:14px;line-height:1} .filter-chip-arrow{display:inline-flex;color:currentColor;opacity:.5;margin-left:2px} .filter-chip-arrow svg{width:10px;height:10px} /* Mode \"compact\" : sections initialement collapsées si > 6 items */ .filter-chips.collapsed{max-height:80px;overflow:hidden;position:relative} .filter-chips.collapsed::after{content:\"\";position:absolute;left:0;right:0;bottom:0;height:30px;background:linear-gradient(to bottom,transparent,#FAFAFA);pointer-events:none} /* ─── Bouton \"Voir plus\" sous les chips villes/métiers ─── */ .dash-filter-more-wrap{display:flex;justify-content:center;margin-top:10px;padding:0 4px} .dash-filter-more-btn{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;background:transparent;color:var(--theme-color,#6C3AED);border:1px dashed rgba(108,58,237,.35);border-radius:100px;font-size:12px;font-weight:600;font-family:inherit;cursor:pointer;transition:background .15s,border-style .15s,border-color .15s} .dash-filter-more-btn:hover{background:#F5F3FF;border-style:solid;border-color:var(--theme-color,#6C3AED)} .dash-filter-more-icon{display:inline-flex;align-items:center;color:currentColor;transition:transform .2s} .dash-filter-more-icon svg{width:12px;height:12px} .dash-filter-more-btn.is-expanded .dash-filter-more-icon{transform:rotate(180deg)} /* ─── Input de recherche dans le header (toujours visible) ─── */ .dash-filter-search{display:block;position:relative;flex:1;max-width:240px} @keyframes dashFilterFadeIn{from{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:translateY(0)}} .dash-filter-search-input{width:100%;padding:5px 10px 5px 28px;border:1px solid #E5E7EB;border-radius:100px;font-size:12px;color:#1E1B2E;background:#FAFAFA;font-family:inherit;outline:none;box-sizing:border-box;transition:border-color .15s,background .15s} .dash-filter-search-input:focus{border-color:rgba(108,58,237,.4);background:#fff} .dash-filter-search-input::placeholder{color:#9CA3AF} .dash-filter-search-icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:#9CA3AF;pointer-events:none;display:flex} .dash-filter-search-icon svg{width:11px;height:11px} /* État \"aucun résultat\" sous le filtre live */ .dash-filter-empty{display:none;padding:14px 12px;font-size:12.5px;color:#9CA3AF;font-style:italic;text-align:center;width:100%} .filter-chips.is-no-results .dash-filter-empty{display:block} /* Bandeau résultats */ .jobs-results-info{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 4px 14px;font-size:12px;color:#6B7280} .jobs-results-info strong{color:#1E1B2E;font-weight:700} /* Liste cards (style \"similar-card\" comme dans show.html.twig) */ .jobs-list{display:flex;flex-direction:column;gap:10px} .jobs-card{background:#fff;border-radius:14px;padding:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04);display:flex;align-items:center;gap:14px;text-decoration:none;color:inherit;transition:transform .15s,box-shadow .2s} .jobs-card:hover{transform:translateY(-1px);box-shadow:0 4px 20px rgba(108,58,237,.1);color:inherit} .jobs-card-logo{width:50px;height:50px;border-radius:12px;background:linear-gradient(135deg,#EDE9FE,#DDD6FE);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:20px;color:var(--theme-color,#6C3AED);flex-shrink:0;overflow:hidden} .jobs-card-logo img{width:100%;height:100%;object-fit:cover;border-radius:8px} .jobs-card-logo svg{width:24px;height:24px;opacity:.85} .jobs-card-info{flex:1;min-width:0} .jobs-card-title{font-size:14px;font-weight:700;color:#1E1B2E;line-height:1.3;margin:0 0 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .jobs-card-meta{font-size:12px;color:#6B7280;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .jobs-card-salary{font-size:11px;font-weight:600;color:var(--theme-color,#6C3AED);background:#F5F3FF;padding:3px 9px;border-radius:100px;white-space:nowrap;flex-shrink:0} .jobs-card-arrow{flex-shrink:0;color:#9CA3AF;transition:color .15s,transform .15s} .jobs-card:hover .jobs-card-arrow{color:var(--theme-color,#6C3AED);transform:translateX(2px)} .jobs-card-arrow svg{width:18px;height:18px} /* Skeleton (pendant chargement) */ .jobs-skeleton{display:flex;flex-direction:column;gap:10px} .jobs-skel-card{background:#fff;border-radius:14px;padding:14px;display:flex;align-items:center;gap:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04)} .jobs-skel-logo{width:50px;height:50px;border-radius:12px;background:linear-gradient(90deg,#F3F4F6 0%,#E5E7EB 50%,#F3F4F6 100%);background-size:200% 100%;animation:jobsSkelShim 1.4s ease-in-out infinite;flex-shrink:0} .jobs-skel-info{flex:1} .jobs-skel-line{height:14px;background:linear-gradient(90deg,#F3F4F6 0%,#E5E7EB 50%,#F3F4F6 100%);background-size:200% 100%;animation:jobsSkelShim 1.4s ease-in-out infinite;border-radius:4px;margin-bottom:6px} .jobs-skel-line.s1{width:60%} .jobs-skel-line.s2{width:40%;height:12px;margin-bottom:0} @keyframes jobsSkelShim{0%{background-position:200% 0}100%{background-position:-200% 0}} /* Bouton charger plus */ .jobs-load-more{display:flex;width:100%;padding:14px;margin-top:16px;background:#fff;color:var(--theme-color,#6C3AED);border:1.5px dashed rgba(108,58,237,.35);border-radius:12px;font-size:13.5px;font-weight:700;cursor:pointer;font-family:inherit;align-items:center;justify-content:center;gap:8px;transition:background .15s,border-color .15s} .jobs-load-more:hover{background:#F5F3FF;border-color:var(--theme-color,#6C3AED);border-style:solid;color:var(--theme-color,#6C3AED)} .jobs-load-more svg{width:14px;height:14px} .jobs-load-more:disabled{opacity:.6;cursor:not-allowed} .jobs-load-more.loading{cursor:wait} .jobs-load-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(108,58,237,.2);border-top-color:var(--theme-color,#6C3AED);border-radius:50%;animation:jobsLoadSpin .7s linear infinite} @keyframes jobsLoadSpin{to{transform:rotate(360deg)}} /* État vide */ .jobs-empty{text-align:center;padding:40px 20px;background:#fff;border-radius:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04)} .jobs-empty-icon{display:inline-flex;align-items:center;justify-content:center;width:56px;height:56px;border-radius:16px;background:#F5F3FF;color:var(--theme-color,#6C3AED);margin-bottom:14px} .jobs-empty-icon svg{width:24px;height:24px} .jobs-empty-title{font-size:16px;font-weight:700;color:#1E1B2E;margin:0 0 6px} .jobs-empty-text{font-size:13px;color:#6B7280;margin:0} </style> "; // line 143 yield " "; yield (string) $macros["promo"]->getTemplateForMacro("macro_styles", $context, 143, $this->getSourceContext())->macro_styles(...[]); yield ""; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof); $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof); yield from []; } // line 146 /** * @return iterable<null|scalar|\Stringable> */ public function block_body(array $context, array $blocks = []): iterable { $macros = $this->macros; $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"]; $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "body")); $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"]; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "body")); // line 147 yield " <div class=\"jobs-dash\"> <div class=\"jobs-dash-header\"> "; // line 150 if ((((array_key_exists("currentSubKeyword", $context) && !(null === (isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword", $context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.', 150, $this->source); })()))) && array_key_exists("currentCityFilter", $context)) && !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 150, $this->source); })())))) { // line 151 yield " "; // line 152 yield " <h1 class=\"jobs-dash-title\"> "; // line 153 if ( !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 153, $this->source); })()), "icon", [], "any", false, false, false, 153))) { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 153, $this->source); })()), "icon", [], "any", false, false, false, 153), "html", null, true); yield " "; } yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword", $context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.', 153, $this->source); })()), "html", null, true); yield " "; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.cityHeadingIn", [], "whr-public"), "html", null, true); yield " "; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 153, $this->source); })()), "label", [], "any", false, false, false, 153), "html", null, true); yield " </h1> <p class=\"jobs-dash-subtitle\">"; // line 155 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.cityKeywordSubtitle", ["%keyword%" => (isset($context["currentSubKeyword"]) || array_key_exists("currentSubKeyword", $context) ? $context["currentSubKeyword"] : (function () { throw new RuntimeError('Variable "currentSubKeyword" does not exist.', 155, $this->source); })()), "%city%" => CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 155, $this->source); })()), "label", [], "any", false, false, false, 155)], "whr-public"), "html", null, true); yield "</p> "; } elseif (( // line 156array_key_exists("currentFilter", $context) && !(null === (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 156, $this->source); })())))) { // line 157 yield " <h1 class=\"jobs-dash-title\"> "; // line 158 if ( !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 158, $this->source); })()), "icon", [], "any", false, false, false, 158))) { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 158, $this->source); })()), "icon", [], "any", false, false, false, 158), "html", null, true); yield " "; } yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env, $this->source, ($context["currentFilter"] ?? null), "shortTitle", [], "any", true, true, false, 158)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 158, $this->source); })()), "shortTitle", [], "any", false, false, false, 158), CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 158, $this->source); })()), "label", [], "any", false, false, false, 158))) : (CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 158, $this->source); })()), "label", [], "any", false, false, false, 158))), "html", null, true); yield " </h1> "; // line 160 if ( !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 160, $this->source); })()), "shortDescription", [], "any", false, false, false, 160))) { // line 161 yield " <p class=\"jobs-dash-subtitle\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 161, $this->source); })()), "shortDescription", [], "any", false, false, false, 161), "html", null, true); yield "</p> "; } else { // line 163 yield " <p class=\"jobs-dash-subtitle\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.subtitle", [], "whr-public"), "html", null, true); yield "</p> "; } // line 165 yield " "; } else { // line 166 yield " <h1 class=\"jobs-dash-title\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.heading", [], "whr-public"), "html", null, true); yield "</h1> <p class=\"jobs-dash-subtitle\">"; // line 167 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.subtitle", [], "whr-public"), "html", null, true); yield "</p> "; } // line 169 yield " "; // line 171 yield " "; if ((array_key_exists("currentCityFilter", $context) && !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 171, $this->source); })())))) { // line 172 yield " <div class=\"city-context-bar\"> <span class=\"city-context-label\">"; // line 173 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.contextLabel", [], "whr-public"), "html", null, true); yield "</span> <span class=\"city-context-badge\"> "; // line 175 if ( !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 175, $this->source); })()), "icon", [], "any", false, false, false, 175))) { yield "<span class=\"city-context-badge-icon\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 175, $this->source); })()), "icon", [], "any", false, false, false, 175), "html", null, true); yield "</span>"; } // line 176 yield " <span>"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 176, $this->source); })()), "label", [], "any", false, false, false, 176), "html", null, true); yield "</span> </span> <a href=\""; // line 178 if ((CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 178, $this->source); })()), "request", [], "any", false, false, false, 178), "locale", [], "any", false, false, false, 178) == "en")) { yield (string) $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("whileresume_jobs_list"); } else { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_whileresume_jobs_list", ["_locale" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 178, $this->source); })()), "request", [], "any", false, false, false, 178), "locale", [], "any", false, false, false, 178)]), "html", null, true); } yield "\" class=\"city-context-clear-btn\" title=\""; // line 180 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.clearCity", [], "whr-public"), "html", null, true); yield "\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\" transform=\"rotate(180 12 12)\"/></svg> "; // line 182 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.allCities", [], "whr-public"), "html", null, true); yield " </a> </div> "; } // line 186 yield " </div> "; // line 189 yield " <div class=\"wr-search-widget\"> <div class=\"wr-search-input-wrap\"> <span class=\"wr-search-icon\"> <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg> </span> <input type=\"text\" id=\"dashSearchInput\" class=\"wr-search-input\" placeholder=\""; // line 195 if ((array_key_exists("currentCityFilter", $context) && !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 195, $this->source); })())))) { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.searchInCity", ["%city%" => CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 195, $this->source); })()), "label", [], "any", false, false, false, 195)], "whr-public"), "html", null, true); } else { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.show.searchPlaceholder", [], "whr-public"), "html", null, true); } yield "\" value=\""; // line 196 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((array_key_exists("initialQuery", $context)) ? (Twig\Extension\CoreExtension::default((isset($context["initialQuery"]) || array_key_exists("initialQuery", $context) ? $context["initialQuery"] : (function () { throw new RuntimeError('Variable "initialQuery" does not exist.', 196, $this->source); })()), "")) : ("")), "html", null, true); yield "\" autocomplete=\"off\"> <span class=\"wr-search-kbd-hint\" id=\"dashSearchKbdHint\">"; // line 198 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.pressEnter", [], "whr-public"), "html", null, true); yield "</span> <button type=\"button\" id=\"dashSearchClear\" class=\"wr-search-clear\" aria-label=\"Clear\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg> </button> </div> </div> "; // line 206 yield " "; if ((array_key_exists("searchKeywords", $context) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["searchKeywords"]) || array_key_exists("searchKeywords", $context) ? $context["searchKeywords"] : (function () { throw new RuntimeError('Variable "searchKeywords" does not exist.', 206, $this->source); })())) > 0))) { // line 207 yield " <div class=\"search-keywords\"> <span class=\"search-keywords-label\">"; // line 208 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.show.keywordsLabel", [], "whr-public"), "html", null, true); yield "</span> "; // line 209 $context['_parent'] = $context; $context['_seq'] = CoreExtension::ensureTraversable((isset($context["searchKeywords"]) || array_key_exists("searchKeywords", $context) ? $context["searchKeywords"] : (function () { throw new RuntimeError('Variable "searchKeywords" does not exist.', 209, $this->source); })())); foreach ($context['_seq'] as $context["_key"] => $context["kw"]) { // line 210 yield " "; // line 211 yield " "; $context["kwSlug"] = Twig\Extension\CoreExtension::trim(Twig\Extension\CoreExtension::replace(Twig\Extension\CoreExtension::lower($this->env->getCharset(), Twig\Extension\CoreExtension::replace(CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "label", [], "any", false, false, false, 211), ["à" => "a", "â" => "a", "ä" => "a", "á" => "a", "ã" => "a", "å" => "a", "À" => "a", "Â" => "a", "Ä" => "a", "Á" => "a", "Ã" => "a", "Å" => "a", "é" => "e", "è" => "e", "ê" => "e", "ë" => "e", "ẽ" => "e", "É" => "e", "È" => "e", "Ê" => "e", "Ë" => "e", "î" => "i", "ï" => "i", "ì" => "i", "í" => "i", "Î" => "i", "Ï" => "i", "Ì" => "i", "Í" => "i", "ô" => "o", "ö" => "o", "ò" => "o", "ó" => "o", "õ" => "o", "ø" => "o", "Ô" => "o", "Ö" => "o", "Ò" => "o", "Ó" => "o", "Õ" => "o", "Ø" => "o", "û" => "u", "ü" => "u", "ù" => "u", "ú" => "u", "Û" => "u", "Ü" => "u", "Ù" => "u", "Ú" => "u", "ÿ" => "y", "ý" => "y", "Ÿ" => "y", "Ý" => "y", "ç" => "c", "Ç" => "c", "ñ" => "n", "Ñ" => "n", "œ" => "oe", "Œ" => "oe", "æ" => "ae", "Æ" => "ae", "\x27" => "-", " " => "-", "/" => "-", "_" => "-", "." => "-", "," => "-", "(" => "", "*" => "", ")" => "", "&" => "-and-", "+" => "-plus-", "#" => "", "?" => "", "!" => "", "\"" => "", "’" => "-", "`" => "-"])), ["--" => "-", "---" => "-"]), "-"); // line 234 yield " "; // line 235 if ((array_key_exists("currentCityFilter", $context) && !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 235, $this->source); })())))) { // line 236 yield " "; // line 237 yield " <a href=\""; if ((CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 237, $this->source); })()), "request", [], "any", false, false, false, 237), "locale", [], "any", false, false, false, 237) == "en")) { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_filter_keyword", ["slug" => CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 237, $this->source); })()), "slug", [], "any", false, false, false, 237), "keyword" => (isset($context["kwSlug"]) || array_key_exists("kwSlug", $context) ? $context["kwSlug"] : (function () { throw new RuntimeError('Variable "kwSlug" does not exist.', 237, $this->source); })())]), "html", null, true); } else { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_filter_keyword", ["_locale" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 237, $this->source); })()), "request", [], "any", false, false, false, 237), "locale", [], "any", false, false, false, 237), "slug" => CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 237, $this->source); })()), "slug", [], "any", false, false, false, 237), "keyword" => (isset($context["kwSlug"]) || array_key_exists("kwSlug", $context) ? $context["kwSlug"] : (function () { throw new RuntimeError('Variable "kwSlug" does not exist.', 237, $this->source); })())]), "html", null, true); } yield "\" class=\"search-keyword-chip"; // line 238 if ((array_key_exists("currentSubKeywordSlug", $context) && ((isset($context["currentSubKeywordSlug"]) || array_key_exists("currentSubKeywordSlug", $context) ? $context["currentSubKeywordSlug"] : (function () { throw new RuntimeError('Variable "currentSubKeywordSlug" does not exist.', 238, $this->source); })()) == (isset($context["kwSlug"]) || array_key_exists("kwSlug", $context) ? $context["kwSlug"] : (function () { throw new RuntimeError('Variable "kwSlug" does not exist.', 238, $this->source); })())))) { yield " active"; } yield "\"> "; // line 239 if ( !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "icon", [], "any", false, false, false, 239))) { yield "<span class=\"search-keyword-chip-icon\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "icon", [], "any", false, false, false, 239), "html", null, true); yield "</span>"; } // line 240 yield " <span>"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "label", [], "any", false, false, false, 240), "html", null, true); yield "</span> </a> "; } else { // line 243 yield " "; // line 244 yield " <button type=\"button\" class=\"search-keyword-chip\" data-keyword=\""; // line 246 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "searchKeyword", [], "any", true, true, false, 246)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "searchKeyword", [], "any", false, false, false, 246), CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "label", [], "any", false, false, false, 246))) : (CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "label", [], "any", false, false, false, 246))), "html", null, true); yield "\"> "; // line 247 if ( !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "icon", [], "any", false, false, false, 247))) { yield "<span class=\"search-keyword-chip-icon\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "icon", [], "any", false, false, false, 247), "html", null, true); yield "</span>"; } // line 248 yield " <span>"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "label", [], "any", false, false, false, 248), "html", null, true); yield "</span> </button> "; } // line 251 yield " "; } $_parent = $context['_parent']; unset($context['_seq'], $context['_key'], $context['kw'], $context['_parent']); $context = array_intersect_key($context, $_parent); $context += $_parent; // line 252 yield " </div> "; } // line 254 yield " "; // line 256 yield " "; if ((array_key_exists("sidebarFiltersCities", $context) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities", $context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.', 256, $this->source); })())) > 0))) { // line 257 yield " "; $context["citiesInitial"] = 14; // line 258 yield " <div class=\"filter-section\" id=\"filterSectionCities\"> <div class=\"filter-section-head\"> <h3 class=\"filter-section-title\"> <span class=\"filter-section-title-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg> </span> "; // line 264 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.popularCities", [], "whr-public"), "html", null, true); yield " </h3> "; // line 267 yield " "; if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities", $context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.', 267, $this->source); })())) > (isset($context["citiesInitial"]) || array_key_exists("citiesInitial", $context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.', 267, $this->source); })()))) { // line 268 yield " <div class=\"dash-filter-search\"> <span class=\"dash-filter-search-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg> </span> <input type=\"text\" class=\"dash-filter-search-input\" data-search-target=\"filterChipsCities\" placeholder=\""; // line 275 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.filterSearchCity", [], "whr-public"), "html", null, true); yield "\" autocomplete=\"off\"> </div> "; } // line 279 yield " </div> <div class=\"filter-chips dash-filter-chips\" id=\"filterChipsCities\" data-initial=\""; // line 280 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["citiesInitial"]) || array_key_exists("citiesInitial", $context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.', 280, $this->source); })()), "html", null, true); yield "\"> "; // line 281 $context['_parent'] = $context; $context['_seq'] = CoreExtension::ensureTraversable((isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities", $context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.', 281, $this->source); })())); $context['loop'] = [ 'parent' => $context['_parent'], 'index0' => 0, 'index' => 1, 'first' => true, ]; if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) { $length = count($context['_seq']); $context['loop']['revindex0'] = $length - 1; $context['loop']['revindex'] = $length; $context['loop']['length'] = $length; $context['loop']['last'] = 1 === $length; } foreach ($context['_seq'] as $context["_key"] => $context["f"]) { // line 282 yield " <a href=\""; if ((CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 282, $this->source); })()), "request", [], "any", false, false, false, 282), "locale", [], "any", false, false, false, 282) == "en")) { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_filter", ["slug" => CoreExtension::getAttribute($this->env, $this->source, $context["f"], "slug", [], "any", false, false, false, 282)]), "html", null, true); } else { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_filter", ["_locale" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 282, $this->source); })()), "request", [], "any", false, false, false, 282), "locale", [], "any", false, false, false, 282), "slug" => CoreExtension::getAttribute($this->env, $this->source, $context["f"], "slug", [], "any", false, false, false, 282)]), "html", null, true); } yield "\" class=\"filter-chip dash-filter-item"; // line 283 if (((array_key_exists("currentFilter", $context) && !(null === (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 283, $this->source); })()))) && (CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 283, $this->source); })()), "slug", [], "any", false, false, false, 283) == CoreExtension::getAttribute($this->env, $this->source, $context["f"], "slug", [], "any", false, false, false, 283)))) { yield " active"; } yield "\" data-filter-slug=\""; // line 284 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["f"], "slug", [], "any", false, false, false, 284), "html", null, true); yield "\" data-filter-label=\""; // line 285 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["f"], "label", [], "any", false, false, false, 285), "html", null, true); yield "\" data-index=\""; // line 286 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["loop"], "index0", [], "any", false, false, false, 286), "html", null, true); yield "\""; if ((CoreExtension::getAttribute($this->env, $this->source, $context["loop"], "index0", [], "any", false, false, false, 286) >= (isset($context["citiesInitial"]) || array_key_exists("citiesInitial", $context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.', 286, $this->source); })()))) { yield " style=\"display:none\""; } yield "> "; // line 287 if ( !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env, $this->source, $context["f"], "icon", [], "any", false, false, false, 287))) { yield "<span class=\"filter-chip-icon\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["f"], "icon", [], "any", false, false, false, 287), "html", null, true); yield "</span>"; } // line 288 yield " <span>"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["f"], "label", [], "any", false, false, false, 288), "html", null, true); yield "</span> <span class=\"filter-chip-arrow\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\"/></svg> </span> </a> "; ++$context['loop']['index0']; ++$context['loop']['index']; $context['loop']['first'] = false; if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) { --$context['loop']['revindex0']; --$context['loop']['revindex']; $context['loop']['last'] = 0 === $context['loop']['revindex0']; } } $_parent = $context['_parent']; unset($context['_seq'], $context['_key'], $context['f'], $context['_parent'], $context['loop']); $context = array_intersect_key($context, $_parent); $context += $_parent; // line 294 yield " <div class=\"dash-filter-empty\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.filterNoResults", [], "whr-public"), "html", null, true); yield "</div> </div> "; // line 296 if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities", $context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.', 296, $this->source); })())) > (isset($context["citiesInitial"]) || array_key_exists("citiesInitial", $context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.', 296, $this->source); })()))) { // line 297 yield " <div class=\"dash-filter-more-wrap\"> <button type=\"button\" class=\"dash-filter-more-btn\" data-target=\"filterChipsCities\" data-section=\"filterSectionCities\"> <span class=\"dash-filter-more-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg> </span> <span class=\"dash-filter-more-label\" data-more=\""; // line 302 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showMoreCities", ["%n%" => (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities", $context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.', 302, $this->source); })())) - (isset($context["citiesInitial"]) || array_key_exists("citiesInitial", $context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.', 302, $this->source); })()))], "whr-public"), "html", null, true); yield "\" data-less=\""; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showLessCities", [], "whr-public"), "html", null, true); yield "\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showMoreCities", ["%n%" => (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCities"]) || array_key_exists("sidebarFiltersCities", $context) ? $context["sidebarFiltersCities"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCities" does not exist.', 302, $this->source); })())) - (isset($context["citiesInitial"]) || array_key_exists("citiesInitial", $context) ? $context["citiesInitial"] : (function () { throw new RuntimeError('Variable "citiesInitial" does not exist.', 302, $this->source); })()))], "whr-public"), "html", null, true); yield "</span> </button> </div> "; } // line 306 yield " </div> "; } // line 308 yield " "; // line 310 yield " "; if ((array_key_exists("sidebarFiltersCategories", $context) && (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories", $context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.', 310, $this->source); })())) > 0))) { // line 311 yield " "; $context["categoriesInitial"] = 8; // line 312 yield " <div class=\"filter-section\" id=\"filterSectionCategories\"> <div class=\"filter-section-head\"> <h3 class=\"filter-section-title\"> <span class=\"filter-section-title-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"2\" y=\"7\" width=\"20\" height=\"14\" rx=\"2\"/><path d=\"M16 7V5a4 4 0 00-8 0v2\"/></svg> </span> "; // line 318 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.popularCategories", [], "whr-public"), "html", null, true); yield " </h3> "; // line 321 yield " "; if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories", $context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.', 321, $this->source); })())) > (isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial", $context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.', 321, $this->source); })()))) { // line 322 yield " <div class=\"dash-filter-search\"> <span class=\"dash-filter-search-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg> </span> <input type=\"text\" class=\"dash-filter-search-input\" data-search-target=\"filterChipsCategories\" placeholder=\""; // line 329 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.filterSearchCategory", [], "whr-public"), "html", null, true); yield "\" autocomplete=\"off\"> </div> "; } // line 333 yield " </div> <div class=\"filter-chips dash-filter-chips\" id=\"filterChipsCategories\" data-initial=\""; // line 334 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape((isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial", $context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.', 334, $this->source); })()), "html", null, true); yield "\"> "; // line 335 $context['_parent'] = $context; $context['_seq'] = CoreExtension::ensureTraversable((isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories", $context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.', 335, $this->source); })())); $context['loop'] = [ 'parent' => $context['_parent'], 'index0' => 0, 'index' => 1, 'first' => true, ]; if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) { $length = count($context['_seq']); $context['loop']['revindex0'] = $length - 1; $context['loop']['revindex'] = $length; $context['loop']['length'] = $length; $context['loop']['last'] = 1 === $length; } foreach ($context['_seq'] as $context["_key"] => $context["f"]) { // line 336 yield " <a href=\""; if ((CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 336, $this->source); })()), "request", [], "any", false, false, false, 336), "locale", [], "any", false, false, false, 336) == "en")) { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_filter", ["slug" => CoreExtension::getAttribute($this->env, $this->source, $context["f"], "slug", [], "any", false, false, false, 336)]), "html", null, true); } else { yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_filter", ["_locale" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 336, $this->source); })()), "request", [], "any", false, false, false, 336), "locale", [], "any", false, false, false, 336), "slug" => CoreExtension::getAttribute($this->env, $this->source, $context["f"], "slug", [], "any", false, false, false, 336)]), "html", null, true); } yield "\" class=\"filter-chip dash-filter-item"; // line 337 if (((array_key_exists("currentFilter", $context) && !(null === (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 337, $this->source); })()))) && (CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentFilter"]) || array_key_exists("currentFilter", $context) ? $context["currentFilter"] : (function () { throw new RuntimeError('Variable "currentFilter" does not exist.', 337, $this->source); })()), "slug", [], "any", false, false, false, 337) == CoreExtension::getAttribute($this->env, $this->source, $context["f"], "slug", [], "any", false, false, false, 337)))) { yield " active"; } yield "\" data-filter-slug=\""; // line 338 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["f"], "slug", [], "any", false, false, false, 338), "html", null, true); yield "\" data-filter-label=\""; // line 339 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["f"], "label", [], "any", false, false, false, 339), "html", null, true); yield "\" data-index=\""; // line 340 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["loop"], "index0", [], "any", false, false, false, 340), "html", null, true); yield "\""; if ((CoreExtension::getAttribute($this->env, $this->source, $context["loop"], "index0", [], "any", false, false, false, 340) >= (isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial", $context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.', 340, $this->source); })()))) { yield " style=\"display:none\""; } yield "> "; // line 341 if ( !Twig\Extension\CoreExtension::testEmpty(CoreExtension::getAttribute($this->env, $this->source, $context["f"], "icon", [], "any", false, false, false, 341))) { yield "<span class=\"filter-chip-icon\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["f"], "icon", [], "any", false, false, false, 341), "html", null, true); yield "</span>"; } // line 342 yield " <span>"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, $context["f"], "label", [], "any", false, false, false, 342), "html", null, true); yield "</span> <span class=\"filter-chip-arrow\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\"/></svg> </span> </a> "; ++$context['loop']['index0']; ++$context['loop']['index']; $context['loop']['first'] = false; if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) { --$context['loop']['revindex0']; --$context['loop']['revindex']; $context['loop']['last'] = 0 === $context['loop']['revindex0']; } } $_parent = $context['_parent']; unset($context['_seq'], $context['_key'], $context['f'], $context['_parent'], $context['loop']); $context = array_intersect_key($context, $_parent); $context += $_parent; // line 348 yield " <div class=\"dash-filter-empty\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.filterNoResults", [], "whr-public"), "html", null, true); yield "</div> </div> "; // line 350 if ((Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories", $context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.', 350, $this->source); })())) > (isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial", $context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.', 350, $this->source); })()))) { // line 351 yield " <div class=\"dash-filter-more-wrap\"> <button type=\"button\" class=\"dash-filter-more-btn\" data-target=\"filterChipsCategories\" data-section=\"filterSectionCategories\"> <span class=\"dash-filter-more-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg> </span> <span class=\"dash-filter-more-label\" data-more=\""; // line 356 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showMoreCategories", ["%n%" => (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories", $context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.', 356, $this->source); })())) - (isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial", $context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.', 356, $this->source); })()))], "whr-public"), "html", null, true); yield "\" data-less=\""; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showLessCategories", [], "whr-public"), "html", null, true); yield "\">"; yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.showMoreCategories", ["%n%" => (Twig\Extension\CoreExtension::length($this->env->getCharset(), (isset($context["sidebarFiltersCategories"]) || array_key_exists("sidebarFiltersCategories", $context) ? $context["sidebarFiltersCategories"] : (function () { throw new RuntimeError('Variable "sidebarFiltersCategories" does not exist.', 356, $this->source); })())) - (isset($context["categoriesInitial"]) || array_key_exists("categoriesInitial", $context) ? $context["categoriesInitial"] : (function () { throw new RuntimeError('Variable "categoriesInitial" does not exist.', 356, $this->source); })()))], "whr-public"), "html", null, true); yield "</span> </button> </div> "; } // line 360 yield " </div> "; } // line 362 yield " "; // line 364 yield " <div class=\"jobs-results-info\" id=\"jobsResultsInfo\"> <span id=\"jobsResultsCount\">"; // line 365 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.loading", [], "whr-public"), "html", null, true); yield "</span> </div> "; // line 369 yield " <div class=\"jobs-list\" id=\"jobsList\"> <div class=\"jobs-skeleton\"> "; // line 371 $context['_parent'] = $context; $context['_seq'] = CoreExtension::ensureTraversable(range(1, 5)); foreach ($context['_seq'] as $context["_key"] => $context["i"]) { // line 372 yield " <div class=\"jobs-skel-card\"> <div class=\"jobs-skel-logo\"></div> <div class=\"jobs-skel-info\"> <div class=\"jobs-skel-line s1\"></div> <div class=\"jobs-skel-line s2\"></div> </div> </div> "; } $_parent = $context['_parent']; unset($context['_seq'], $context['_key'], $context['i'], $context['_parent']); $context = array_intersect_key($context, $_parent); $context += $_parent; // line 380 yield " </div> </div> "; // line 384 yield " <button type=\"button\" class=\"jobs-load-more\" id=\"jobsLoadMore\" style=\"display:none;\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg> <span id=\"jobsLoadMoreLabel\">"; // line 386 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.loadMore", [], "whr-public"), "html", null, true); yield "</span> </button> "; // line 392 yield " "; if ((null === CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 392, $this->source); })()), "user", [], "any", false, false, false, 392))) { // line 393 yield " "; yield (string) $macros["promo"]->getTemplateForMacro("macro_card_template", $context, 393, $this->getSourceContext())->macro_card_template(...[["template_id" => "jobs-promo-card-template", "login_url" => (((CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, // line 395(isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 395, $this->source); })()), "request", [], "any", false, false, false, 395), "locale", [], "any", false, false, false, 395) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_gestion_candidates_dashboard")) : ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_gestion_candidates_dashboard", ["_locale" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, // line 397(isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 397, $this->source); })()), "request", [], "any", false, false, false, 397), "locale", [], "any", false, false, false, 397)])))]]); // line 398 yield " "; } // line 400 yield " </div>"; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof); $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof); yield from []; } // line 404 /** * @return iterable<null|scalar|\Stringable> */ public function block_footerjs(array $context, array $blocks = []): iterable { $macros = $this->macros; $__internal_5a27a8ba21ca79b61932376b2fa922d2 = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"]; $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "footerjs")); $__internal_6f47bbe9983af81f1e7450e9a3e3768f = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"]; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block", "footerjs")); // line 405 yield " <script> (function(){ \x27use strict\x27; try { var LOCALE = \x27"; // line 410 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 410, $this->source); })()), "request", [], "any", false, false, false, 410), "locale", [], "any", false, false, false, 410), "html", null, true); yield "\x27; var IS_AUTHENTICATED = "; // line 411 yield (string) (((($tmp = CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 411, $this->source); })()), "user", [], "any", false, false, false, 411)) && $tmp instanceof Markup ? (string) $tmp : $tmp)) ? ("true") : ("false")); yield "; var SEARCH_API_URL = \x27"; // line 413 yield (string) (((CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 413, $this->source); })()), "request", [], "any", false, false, false, 413), "locale", [], "any", false, false, false, 413) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_api_search")) : ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_api_search", ["_locale" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 413, $this->source); })()), "request", [], "any", false, false, false, 413), "locale", [], "any", false, false, false, 413)]), "html", null, true))); yield "\x27; var JOB_SHOW_URL_TEMPLATE = \x27"; // line 414 yield (string) (((CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 414, $this->source); })()), "request", [], "any", false, false, false, 414), "locale", [], "any", false, false, false, 414) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_api_search", ["slug" => "__SLUG__"])) : ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_job_show", ["_locale" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 414, $this->source); })()), "request", [], "any", false, false, false, 414), "locale", [], "any", false, false, false, 414), "slug" => "__SLUG__"]), "html", null, true))); yield "\x27; var PAGE_SIZE = 10; var currentQuery = "; // line 417 yield (string) json_encode(((array_key_exists("initialQuery", $context)) ? (Twig\Extension\CoreExtension::default((isset($context["initialQuery"]) || array_key_exists("initialQuery", $context) ? $context["initialQuery"] : (function () { throw new RuntimeError('Variable "initialQuery" does not exist.', 417, $this->source); })()), "")) : (""))); yield "; var currentOffset = 0; var currentTotal = 0; var isFetching = false; // Contexte ville (vient du serveur si on est sur /jobs/paris/... sinon vide) var CITY_KEYWORD = "; // line 423 yield (string) json_encode(((array_key_exists("currentCityKeyword", $context)) ? (Twig\Extension\CoreExtension::default((isset($context["currentCityKeyword"]) || array_key_exists("currentCityKeyword", $context) ? $context["currentCityKeyword"] : (function () { throw new RuntimeError('Variable "currentCityKeyword" does not exist.', 423, $this->source); })()), "")) : (""))); yield "; // Slug ville pour générer les URLs de redirection au submit var CITY_SLUG = "; // line 426 yield (string) (((array_key_exists("currentCityFilter", $context) && !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 426, $this->source); })())))) ? (json_encode(CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 426, $this->source); })()), "slug", [], "any", false, false, false, 426))) : ("null")); yield "; // URL pour le dashboard global (sans ville) var DASHBOARD_URL = \x27"; // line 429 yield (string) (((CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 429, $this->source); })()), "request", [], "any", false, false, false, 429), "locale", [], "any", false, false, false, 429) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("whileresume_jobs_list")) : ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_whileresume_jobs_list", ["_locale" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, (isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 429, $this->source); })()), "request", [], "any", false, false, false, 429), "locale", [], "any", false, false, false, 429)]), "html", null, true))); yield "\x27; // Templates URL pour /jobs/{citySlug} et /jobs/{citySlug}/{keyword} var CITY_LANDING_URL_TEMPLATE = "; // line 432 yield (string) (((array_key_exists("currentCityFilter", $context) && !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 432, $this->source); })())))) ? (json_encode((((CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, // line 433(isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 433, $this->source); })()), "request", [], "any", false, false, false, 433), "locale", [], "any", false, false, false, 433) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_filter", ["slug" => CoreExtension::getAttribute($this->env, $this->source, // line 434(isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 434, $this->source); })()), "slug", [], "any", false, false, false, 434)])) : ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_filter", ["_locale" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, // line 435(isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 435, $this->source); })()), "request", [], "any", false, false, false, 435), "locale", [], "any", false, false, false, 435), "slug" => CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 435, $this->source); })()), "slug", [], "any", false, false, false, 435)]))))) : ("null")); // line 436 yield "; var CITY_KEYWORD_URL_TEMPLATE = "; // line 437 yield (string) (((array_key_exists("currentCityFilter", $context) && !(null === (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 437, $this->source); })())))) ? (json_encode((((CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, // line 438(isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 438, $this->source); })()), "request", [], "any", false, false, false, 438), "locale", [], "any", false, false, false, 438) == "en")) ? ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("cvs_application_jobs_filter_keyword", ["slug" => CoreExtension::getAttribute($this->env, $this->source, // line 439(isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 439, $this->source); })()), "slug", [], "any", false, false, false, 439), "keyword" => "kwplaceholder"])) : ($this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("locale_cvs_application_jobs_filter_keyword", ["_locale" => CoreExtension::getAttribute($this->env, $this->source, CoreExtension::getAttribute($this->env, $this->source, // line 440(isset($context["app"]) || array_key_exists("app", $context) ? $context["app"] : (function () { throw new RuntimeError('Variable "app" does not exist.', 440, $this->source); })()), "request", [], "any", false, false, false, 440), "locale", [], "any", false, false, false, 440), "slug" => CoreExtension::getAttribute($this->env, $this->source, (isset($context["currentCityFilter"]) || array_key_exists("currentCityFilter", $context) ? $context["currentCityFilter"] : (function () { throw new RuntimeError('Variable "currentCityFilter" does not exist.', 440, $this->source); })()), "slug", [], "any", false, false, false, 440), "keyword" => "kwplaceholder"]))))) : ("null")); // line 441 yield "; // Liste des keywords BDD avec leur slug (pour le matching côté client au submit) var KEYWORDS_DATA = [ "; // line 445 $context['_parent'] = $context; $context['_seq'] = CoreExtension::ensureTraversable(((array_key_exists("searchKeywords", $context)) ? (Twig\Extension\CoreExtension::default((isset($context["searchKeywords"]) || array_key_exists("searchKeywords", $context) ? $context["searchKeywords"] : (function () { throw new RuntimeError('Variable "searchKeywords" does not exist.', 445, $this->source); })()), [])) : ([]))); $context['loop'] = [ 'parent' => $context['_parent'], 'index0' => 0, 'index' => 1, 'first' => true, ]; if (is_array($context['_seq']) || (is_object($context['_seq']) && $context['_seq'] instanceof \Countable)) { $length = count($context['_seq']); $context['loop']['revindex0'] = $length - 1; $context['loop']['revindex'] = $length; $context['loop']['length'] = $length; $context['loop']['last'] = 1 === $length; } foreach ($context['_seq'] as $context["_key"] => $context["kw"]) { // line 446 yield " "; $context["kwSlugForJs"] = Twig\Extension\CoreExtension::trim(Twig\Extension\CoreExtension::replace(Twig\Extension\CoreExtension::lower($this->env->getCharset(), Twig\Extension\CoreExtension::replace(CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "label", [], "any", false, false, false, 446), ["à" => "a", "â" => "a", "ä" => "a", "á" => "a", "ã" => "a", "å" => "a", "À" => "a", "Â" => "a", "Ä" => "a", "Á" => "a", "Ã" => "a", "Å" => "a", "é" => "e", "è" => "e", "ê" => "e", "ë" => "e", "ẽ" => "e", "É" => "e", "È" => "e", "Ê" => "e", "Ë" => "e", "î" => "i", "ï" => "i", "ì" => "i", "í" => "i", "Î" => "i", "Ï" => "i", "Ì" => "i", "Í" => "i", "ô" => "o", "ö" => "o", "ò" => "o", "ó" => "o", "õ" => "o", "ø" => "o", "Ô" => "o", "Ö" => "o", "Ò" => "o", "Ó" => "o", "Õ" => "o", "Ø" => "o", "û" => "u", "ü" => "u", "ù" => "u", "ú" => "u", "Û" => "u", "Ü" => "u", "Ù" => "u", "Ú" => "u", "ÿ" => "y", "ý" => "y", "Ÿ" => "y", "Ý" => "y", "ç" => "c", "Ç" => "c", "ñ" => "n", "Ñ" => "n", "œ" => "oe", "Œ" => "oe", "æ" => "ae", "Æ" => "ae", "\x27" => "-", " " => "-", "/" => "-", "_" => "-", "." => "-", "," => "-", "(" => "", "*" => "", ")" => "", "&" => "-and-", "+" => "-plus-", "#" => "", "?" => "", "!" => "", "\"" => "", "’" => "-", "`" => "-"])), ["--" => "-", "---" => "-"]), "-"); // line 468 yield " { label: "; yield (string) json_encode(CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "label", [], "any", false, false, false, 468)); yield ", searchKeyword: "; yield (string) json_encode((((($tmp = CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "searchKeyword", [], "any", false, false, false, 468)) && $tmp instanceof Markup ? (string) $tmp : $tmp)) ? (CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "searchKeyword", [], "any", false, false, false, 468)) : (CoreExtension::getAttribute($this->env, $this->source, $context["kw"], "label", [], "any", false, false, false, 468)))); yield ", slug: "; yield (string) json_encode((isset($context["kwSlugForJs"]) || array_key_exists("kwSlugForJs", $context) ? $context["kwSlugForJs"] : (function () { throw new RuntimeError('Variable "kwSlugForJs" does not exist.', 468, $this->source); })())); yield " }"; if ( !(($tmp = CoreExtension::getAttribute($this->env, $this->source, $context["loop"], "last", [], "any", false, false, false, 468)) && $tmp instanceof Markup ? (string) $tmp : $tmp)) { yield ","; } // line 469 yield " "; ++$context['loop']['index0']; ++$context['loop']['index']; $context['loop']['first'] = false; if (isset($context['loop']['revindex0'], $context['loop']['revindex'])) { --$context['loop']['revindex0']; --$context['loop']['revindex']; $context['loop']['last'] = 0 === $context['loop']['revindex0']; } } $_parent = $context['_parent']; unset($context['_seq'], $context['_key'], $context['kw'], $context['_parent'], $context['loop']); $context = array_intersect_key($context, $_parent); $context += $_parent; // line 470 yield " ]; var input = document.getElementById(\x27dashSearchInput\x27); var clearBtn = document.getElementById(\x27dashSearchClear\x27); var listEl = document.getElementById(\x27jobsList\x27); var infoEl = document.getElementById(\x27jobsResultsCount\x27); var loadMoreBtn = document.getElementById(\x27jobsLoadMore\x27); var loadMoreLabel = document.getElementById(\x27jobsLoadMoreLabel\x27); function escapeHtml(s){ if(s == null) return \x27\x27; return String(s).replace(/[&<>\"\x27]/g, function(c){ return {\x27&\x27:\x27&\x27,\x27<\x27:\x27<\x27,\x27>\x27:\x27>\x27,\x27\"\x27:\x27"\x27,\"\x27\":\x27'\x27}[c]; }); } function buildJobCard(item){ // Fallback logo : icône \"immeuble\" stylisée si pas de logo entreprise var fallbackLogo = \x27<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\x27 + \x27<path d=\"M3 21h18\"/>\x27 + \x27<path d=\"M5 21V7l8-4v18\"/>\x27 + \x27<path d=\"M19 21V11l-6-4\"/>\x27 + \x27<path d=\"M9 9h.01\"/>\x27 + \x27<path d=\"M9 13h.01\"/>\x27 + \x27<path d=\"M9 17h.01\"/>\x27 + \x27</svg>\x27; var logoHtml = item.logo ? \x27<img src=\"\x27 + escapeHtml(item.logo) + \x27\" alt=\"\" onerror=\"this.parentNode.innerHTML=\\\x27\x27 + fallbackLogo.replace(/\x27/g, \"\\\\\x27\") + \x27\\\x27;\">\x27 : fallbackLogo; var meta = []; if(item.companyName) meta.push(escapeHtml(item.companyName)); if(item.city) meta.push(escapeHtml(item.city)); if(item.employmentType) meta.push(escapeHtml(item.employmentType)); var salaryHtml = (item.salaryMin && item.salaryMax) ? \x27<span class=\"jobs-card-salary\">\x27 + item.salaryMin + \x27–\x27 + item.salaryMax + \x27 \x27 + escapeHtml(item.devise || \x27\x27) + \x27</span>\x27 : \x27\x27; var url = item.url || JOB_SHOW_URL_TEMPLATE.replace(\x27__SLUG__\x27, encodeURIComponent(item.slug)); var a = document.createElement(\x27a\x27); a.href = url; a.className = \x27jobs-card\x27; a.innerHTML = \x27<div class=\"jobs-card-logo\">\x27 + logoHtml + \x27</div>\x27 + \x27<div class=\"jobs-card-info\">\x27 + \x27<div class=\"jobs-card-title\">\x27 + escapeHtml(item.title || \x27\x27) + \x27</div>\x27 + \x27<div class=\"jobs-card-meta\">\x27 + meta.join(\x27 · \x27) + \x27</div>\x27 + \x27</div>\x27 + salaryHtml + \x27<span class=\"jobs-card-arrow\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"9 18 15 12 9 6\"/></svg></span>\x27; return a; } /** * Clone la promo card depuis le <template> rendu par la macro Twig. * Le HTML est défini une seule fois dans _macros/promo_card.html.twig. * Retourne null si le template n\x27est pas présent (ex: user connecté). */ function buildPromoCard(){ var tpl = document.getElementById(\x27jobs-promo-card-template\x27); if(!tpl || !tpl.content) return null; var node = tpl.content.firstElementChild; return node ? node.cloneNode(true) : null; } function renderEmpty(){ listEl.innerHTML = \x27<div class=\"jobs-empty\">\x27 + \x27<div class=\"jobs-empty-icon\">\x27 + \x27<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg>\x27 + \x27</div>\x27 + \x27<div class=\"jobs-empty-title\">"; // line 543 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.emptyTitle", [], "whr-public"), "js"), "html", null, true); yield "</div>\x27 + \x27<div class=\"jobs-empty-text\">"; // line 544 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.emptyText", [], "whr-public"), "js"), "html", null, true); yield "</div>\x27 + \x27</div>\x27; } function setLoadMoreState(state){ if(!loadMoreBtn) return; if(state === \x27loading\x27){ loadMoreBtn.classList.add(\x27loading\x27); loadMoreBtn.disabled = true; loadMoreLabel.innerHTML = \x27<span class=\"jobs-load-spinner\"></span> "; // line 553 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.loadingMore", [], "whr-public"), "js"), "html", null, true); yield "\x27; } else { loadMoreBtn.classList.remove(\x27loading\x27); loadMoreBtn.disabled = false; loadMoreLabel.textContent = \x27"; // line 557 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.loadMore", [], "whr-public"), "js"), "html", null, true); yield "\x27; } } function fetchJobs(query, offset, append){ if(isFetching) return; isFetching = true; if(!append){ // Nouvelle recherche : on remet à zéro et affiche skeleton listEl.innerHTML = \x27<div class=\"jobs-skeleton\">\x27 + Array(5).fill(0).map(function(){ return \x27<div class=\"jobs-skel-card\"><div class=\"jobs-skel-logo\"></div><div class=\"jobs-skel-info\"><div class=\"jobs-skel-line s1\"></div><div class=\"jobs-skel-line s2\"></div></div></div>\x27; }).join(\x27\x27) + \x27</div>\x27; if(infoEl) infoEl.textContent = \x27"; // line 573 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.loading", [], "whr-public"), "js"), "html", null, true); yield "\x27; if(loadMoreBtn) loadMoreBtn.style.display = \x27none\x27; } else { setLoadMoreState(\x27loading\x27); } var url = SEARCH_API_URL + \x27?q=\x27 + encodeURIComponent(query || \x27\x27) + \x27&locale=\x27 + LOCALE + \x27&limit=\x27 + PAGE_SIZE + \x27&offset=\x27 + offset; if(CITY_KEYWORD){ url += \x27&city=\x27 + encodeURIComponent(CITY_KEYWORD); } // Dashboard sans filtre : on demande explicitement les dernières offres if(!query && !CITY_KEYWORD){ url += \x27&all=1\x27; } fetch(url, {headers:{\x27Accept\x27:\x27application/json\x27}}) .then(function(r){ return r.ok ? r.json() : null; }) .then(function(data){ isFetching = false; if(!data){ if(!append) renderEmpty(); setLoadMoreState(\x27idle\x27); return; } var items = data.items || []; currentTotal = data.total || 0; if(!append){ listEl.innerHTML = \x27\x27; if(items.length === 0){ renderEmpty(); if(infoEl) infoEl.innerHTML = \x27<strong>0</strong> "; // line 600 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.resultsCount", [], "whr-public"), "js"), "html", null, true); yield "\x27; if(loadMoreBtn) loadMoreBtn.style.display = \x27none\x27; return; } } // Insérer la promo card après la 5ème offre (uniquement au 1er chargement, // si user non connecté et qu\x27on a au moins 5 offres) var insertPromoAt = (!append && !IS_AUTHENTICATED && items.length >= 5) ? 5 : -1; items.forEach(function(item, idx){ listEl.appendChild(buildJobCard(item)); if(idx === insertPromoAt - 1){ var promoNode = buildPromoCard(); if(promoNode) listEl.appendChild(promoNode); } }); currentOffset = offset + items.length; if(infoEl){ infoEl.innerHTML = \x27<strong>\x27 + currentTotal + \x27</strong> "; // line 621 yield (string) $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("job.dashboard.resultsCount", [], "whr-public"), "js"), "html", null, true); yield "\x27; } // Afficher / cacher \"Charger plus\" if(loadMoreBtn){ if(currentOffset < currentTotal){ loadMoreBtn.style.display = \x27flex\x27; } else { loadMoreBtn.style.display = \x27none\x27; } setLoadMoreState(\x27idle\x27); } }) .catch(function(err){ isFetching = false; console.error(\x27[whr-dash] fetch error\x27, err); setLoadMoreState(\x27idle\x27); }); } /** * Slugifie un texte côté client. DOIT produire EXACTEMENT le même slug * que la méthode PHP slugify() du JobsController et que le filtre Twig * utilisé pour rendre les chips. */ function slugify(text){ if(!text) return \x27\x27; var t = String(text); // Pré-remplacements sémantiques t = t.replace(/&/g, \x27-and-\x27).replace(/\\+/g, \x27-plus-\x27) .replace(/[œŒ]/g, \x27oe\x27).replace(/[æÆ]/g, \x27ae\x27); // Translitération accents → ASCII via NFD + strip diacritics t = t.normalize ? t.normalize(\x27NFD\x27).replace(/[\\u0300-\\u036f]/g, \x27\x27) : t; t = t.toLowerCase(); // Tout ce qui n\x27est pas a-z 0-9 → tiret t = t.replace(/[^a-z0-9]+/g, \x27-\x27); return t.replace(/^-+|-+\$/g, \x27\x27); } /** * Tente de matcher un texte tapé avec un keyword en BDD (par slug ou label). * Retourne l\x27objet keyword si trouvé, null sinon. */ function findMatchingKeyword(text){ if(!text || !KEYWORDS_DATA || !KEYWORDS_DATA.length) return null; var slug = slugify(text); if(!slug) return null; for(var i = 0; i < KEYWORDS_DATA.length; i++){ var kw = KEYWORDS_DATA[i]; // Match sur slug exact OU label/searchKeyword exact (case insensitive) if(kw.slug === slug) return kw; if(slugify(kw.searchKeyword) === slug) return kw; } return null; } /** * Au submit : décide où rediriger l\x27utilisateur en fonction du contexte. * - Si on est sur une ville et le texte matche un keyword BDD → /jobs/{ville}/{slug-kw} * - Sinon si on est sur une ville → /jobs/{ville}?search={texte} * - Sinon (pas de ville) → /jobs?q={texte} * - Si texte vide ET ville définie → /jobs/{ville} (reset) * - Si texte vide ET pas de ville → /jobs (reset) */ function submitSearch(query){ query = (query || \x27\x27).trim(); // Reset (recherche vide) if(!query){ if(CITY_SLUG && CITY_LANDING_URL_TEMPLATE){ window.location.href = CITY_LANDING_URL_TEMPLATE; } else { window.location.href = DASHBOARD_URL; } return; } // Cas 1 : on est sur une ville if(CITY_SLUG && CITY_KEYWORD_URL_TEMPLATE){ var matched = findMatchingKeyword(query); if(matched && matched.slug){ // Match BDD → URL slug propre /jobs/paris/developpeur window.location.href = CITY_KEYWORD_URL_TEMPLATE.replace(\x27kwplaceholder\x27, encodeURIComponent(matched.slug)); return; } // Pas de match → fallback ?search=texte window.location.href = CITY_LANDING_URL_TEMPLATE + \x27?search=\x27 + encodeURIComponent(query); return; } // Cas 2 : pas de ville → dashboard global avec ?q= window.location.href = DASHBOARD_URL + \x27?q=\x27 + encodeURIComponent(query); } /** * Lance la search côté UI (sans redirection — utilisée pour les chips et * pour la \"Charger plus\"). */ function startSearch(query){ currentQuery = query; currentOffset = 0; currentTotal = 0; fetchJobs(query, 0, false); // Update clear button if(clearBtn){ if(query) clearBtn.classList.add(\x27visible\x27); else clearBtn.classList.remove(\x27visible\x27); } // Update active chip (uniquement les chips qui sont des <button>, pas les <a>) document.querySelectorAll(\x27button.search-keyword-chip\x27).forEach(function(c){ if(c.getAttribute(\x27data-keyword\x27) === query) c.classList.add(\x27active\x27); else c.classList.remove(\x27active\x27); }); } // ═══ Submit-only : Entrée déclenche la search ET change l\x27URL ═══ if(input){ input.addEventListener(\x27keydown\x27, function(e){ if(e.key === \x27Enter\x27 || e.keyCode === 13){ e.preventDefault(); submitSearch(input.value); } }); // Affiche bouton clear si query initiale if(input.value.trim()){ if(clearBtn) clearBtn.classList.add(\x27visible\x27); } } // Bouton clear : reset complet → redirection vers /jobs ou /jobs/{ville} if(clearBtn){ clearBtn.addEventListener(\x27click\x27, function(){ submitSearch(\x27\x27); }); } // Chips keywords (cas dashboard global, sans contexte ville → comportement local) // En contexte ville, les chips sont des <a href> directs gérés par le navigateur. document.querySelectorAll(\x27button.search-keyword-chip\x27).forEach(function(chip){ chip.addEventListener(\x27click\x27, function(){ var kw = chip.getAttribute(\x27data-keyword\x27); if(!kw) return; // Sur dashboard global : on submit (redirige vers /jobs?q=kw) submitSearch(kw); }); }); // Bouton \"Charger plus\" if(loadMoreBtn){ loadMoreBtn.addEventListener(\x27click\x27, function(){ if(isFetching) return; fetchJobs(currentQuery, currentOffset, true); }); } // ═══ Bouton \"Voir plus\" + Recherche live des chips ═══ /** * Slugify simple côté UI pour matching tolérant aux accents * (ex: \"developpeur\" matche \"Développeur\") */ function dashSlug(str){ if(!str) return \x27\x27; var t = String(str); t = t.normalize ? t.normalize(\x27NFD\x27).replace(/[\\u0300-\\u036f]/g, \x27\x27) : t; return t.toLowerCase().trim(); } document.querySelectorAll(\x27.dash-filter-more-btn\x27).forEach(function(btn){ var targetId = btn.getAttribute(\x27data-target\x27); var sectionId = btn.getAttribute(\x27data-section\x27); var container = document.getElementById(targetId); var section = sectionId ? document.getElementById(sectionId) : null; if(!container) return; var label = btn.querySelector(\x27.dash-filter-more-label\x27); if(!label) return; var initial = parseInt(container.getAttribute(\x27data-initial\x27), 10) || 14; var items = container.querySelectorAll(\x27.dash-filter-item\x27); var searchInput = section ? section.querySelector(\x27.dash-filter-search-input\x27) : null; // 2 états indépendants : // - userExpanded : l\x27utilisateur a cliqué sur \"Voir plus\" // - searchActive : l\x27input contient du texte (auto-expand temporaire) // Mode développé = userExpanded || searchActive var userExpanded = false; function isEffectivelyExpanded(){ var hasSearch = searchInput && searchInput.value.trim().length > 0; return userExpanded || hasSearch; } function applyDisplay(){ var filterText = searchInput ? searchInput.value : \x27\x27; var query = dashSlug(filterText || \x27\x27); var expanded = isEffectivelyExpanded(); var visibleCount = 0; items.forEach(function(it, i){ var label = it.getAttribute(\x27data-filter-label\x27) || \x27\x27; var matches = !query || dashSlug(label).indexOf(query) !== -1; if(expanded){ // Mode développé : on affiche tous les items qui matchent la recherche it.style.display = matches ? \x27\x27 : \x27none\x27; if(matches) visibleCount++; } else { // Mode collapsé : on affiche les N premiers (pas de filtrage) it.style.display = (i < initial) ? \x27\x27 : \x27none\x27; if(i < initial) visibleCount++; } }); // Toggle \"aucun résultat\" (uniquement quand recherche active) if(query && visibleCount === 0){ container.classList.add(\x27is-no-results\x27); } else { container.classList.remove(\x27is-no-results\x27); } // Synchroniser le bouton \"Voir plus/moins\" avec l\x27état effectif if(expanded){ btn.classList.add(\x27is-expanded\x27); label.textContent = label.getAttribute(\x27data-less\x27); } else { btn.classList.remove(\x27is-expanded\x27); label.textContent = label.getAttribute(\x27data-more\x27); } } btn.addEventListener(\x27click\x27, function(){ userExpanded = !userExpanded; if(!userExpanded){ // Reset input quand l\x27utilisateur collapse manuellement if(searchInput){ searchInput.value = \x27\x27; } // Scroll vers le bouton btn.scrollIntoView({behavior:\x27smooth\x27, block:\x27nearest\x27}); } applyDisplay(); }); // Recherche live dans les chips quand on tape dans l\x27input // → auto-expand pendant la recherche, retour à l\x27état userExpanded quand on vide if(searchInput){ searchInput.addEventListener(\x27input\x27, function(){ applyDisplay(); }); } }); // Premier chargement (vide ou avec query initiale) fetchJobs(currentQuery, 0, false); } catch(err){ console.error(\x27[whr-dash] init error\x27, err); } })(); </script>"; $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof); $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof); yield from []; } /** * @codeCoverageIgnore */ public function getTemplateName(): string { return "application/whileresume/application/jobs/dashboard.html.twig"; } /** * @codeCoverageIgnore */ public function isTraitable(): bool { return false; } /** * @codeCoverageIgnore */ public function getDebugInfo(): array { return array ( 1256 => 621, 1232 => 600, 1202 => 573, 1183 => 557, 1176 => 553, 1164 => 544, 1160 => 543, 1085 => 470, 1070 => 469, 1059 => 468, 1056 => 446, 1039 => 445, 1033 => 441, 1031 => 440, 1030 => 439, 1029 => 438, 1028 => 437, 1025 => 436, 1023 => 435, 1022 => 434, 1021 => 433, 1020 => 432, 1014 => 429, 1008 => 426, 1002 => 423, 993 => 417, 987 => 414, 983 => 413, 978 => 411, 974 => 410, 967 => 405, 954 => 404, 941 => 400, 937 => 398, 935 => 397, 934 => 395, 932 => 393, 929 => 392, 923 => 386, 919 => 384, 914 => 380, 900 => 372, 896 => 371, 892 => 369, 886 => 365, 883 => 364, 880 => 362, 876 => 360, 865 => 356, 858 => 351, 856 => 350, 850 => 348, 828 => 342, 822 => 341, 814 => 340, 810 => 339, 806 => 338, 800 => 337, 791 => 336, 774 => 335, 770 => 334, 767 => 333, 760 => 329, 751 => 322, 748 => 321, 743 => 318, 735 => 312, 732 => 311, 729 => 310, 726 => 308, 722 => 306, 711 => 302, 704 => 297, 702 => 296, 696 => 294, 674 => 288, 668 => 287, 660 => 286, 656 => 285, 652 => 284, 646 => 283, 637 => 282, 620 => 281, 616 => 280, 613 => 279, 606 => 275, 597 => 268, 594 => 267, 589 => 264, 581 => 258, 578 => 257, 575 => 256, 572 => 254, 568 => 252, 561 => 251, 554 => 248, 548 => 247, 544 => 246, 540 => 244, 538 => 243, 531 => 240, 525 => 239, 519 => 238, 510 => 237, 508 => 236, 506 => 235, 503 => 234, 500 => 211, 498 => 210, 494 => 209, 490 => 208, 487 => 207, 484 => 206, 474 => 198, 469 => 196, 461 => 195, 453 => 189, 449 => 186, 442 => 182, 437 => 180, 428 => 178, 422 => 176, 416 => 175, 411 => 173, 408 => 172, 405 => 171, 402 => 169, 397 => 167, 392 => 166, 389 => 165, 383 => 163, 377 => 161, 375 => 160, 366 => 158, 363 => 157, 361 => 156, 357 => 155, 344 => 153, 341 => 152, 339 => 151, 337 => 150, 332 => 147, 319 => 146, 305 => 143, 173 => 12, 160 => 11, 137 => 9, 104 => 8, 72 => 7, 61 => 1, 59 => 5, 46 => 1,); } public function getSourceContext(): Source { return new Source("{% extends \x27application/whileresume/application/jobs/layout-social.html.twig\x27 %}{% trans_default_domain \x27whr-public\x27 %}{% import \x27application/whileresume/_macros/promo_card.html.twig\x27 as promo %}{% block title %}{% if currentSubKeyword is defined and currentSubKeyword is not null and currentCityFilter is defined and currentCityFilter is not null %}{{ currentSubKeyword }} {{ currentCityFilter.label }}{% elseif currentFilter is defined and currentFilter is not null %}{{ currentFilter.shortTitle|default(currentFilter.label) }} — WhileResume{% else %}{{ \x27job.dashboard.title\x27|trans }}{% endif %}{% endblock title %}{% block description %}{% if currentSubKeyword is defined and currentSubKeyword is not null and currentCityFilter is defined and currentCityFilter is not null %}Découvrez les offres \"{{ currentSubKeyword }}\" à {{ currentCityFilter.label }}.{% elseif currentFilter is defined and currentFilter is not null and currentFilter.shortDescription is not empty %}{{ currentFilter.shortDescription }}{% else %}{{ \x27job.dashboard.description\x27|trans }}{% endif %}{% endblock description %}{% block robots %}index,follow{% endblock robots %}{% block css %} <style> /* ─── Page dashboard /jobs ─── */ .jobs-dash{max-width:880px;margin:0 auto} .jobs-dash-header{margin-bottom:18px} .jobs-dash-title{font-size:24px;font-weight:800;color:#1E1B2E;line-height:1.2;letter-spacing:-0.02em;margin:0 0 6px} @media(min-width:768px){.jobs-dash-title{font-size:28px}} .jobs-dash-subtitle{font-size:14px;color:#6B7280;margin:0 0 18px} /* ─── Bandeau contexte ville (badge + bouton ALL) ─── */ .city-context-bar{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0 0 16px;padding:10px 14px;background:#F5F3FF;border:1px solid rgba(108,58,237,.15);border-radius:12px} .city-context-label{font-size:11px;font-weight:600;color:#6B7280;text-transform:uppercase;letter-spacing:.06em} .city-context-badge{display:inline-flex;align-items:center;gap:6px;padding:4px 12px;border-radius:100px;background:#fff;color:var(--theme-color,#6C3AED);font-size:13px;font-weight:600;border:1px solid rgba(108,58,237,.2)} .city-context-badge-icon{font-size:14px;line-height:1} .city-context-clear-btn{margin-left:auto;display:inline-flex;align-items:center;gap:4px;padding:5px 12px;border-radius:100px;background:transparent;color:var(--theme-color,#6C3AED);font-size:12px;font-weight:600;border:1px dashed rgba(108,58,237,.4);cursor:pointer;text-decoration:none;font-family:inherit;transition:background .15s,border-style .15s,border-color .15s} .city-context-clear-btn:hover{background:#fff;border-style:solid;border-color:var(--theme-color,#6C3AED);color:var(--theme-color,#6C3AED)} .city-context-clear-btn svg{width:11px;height:11px} /* Widget recherche */ .wr-search-widget{background:#fff;border-radius:14px;box-shadow:0 0 20px 0 rgba(0,0,0,0.05);padding:10px;margin-bottom:14px;position:relative;z-index:50} .wr-search-input-wrap{display:flex;align-items:center;gap:10px;padding:8px 14px;border-radius:10px;background:#F9FAFB;border:1px solid #E5E7EB;transition:border-color .2s,background .2s} .wr-search-input-wrap:focus-within{border-color:rgba(108,58,237,.3);background:#fff} .wr-search-icon{color:#9CA3AF;display:flex;flex-shrink:0} .wr-search-input{flex:1;border:none;outline:none;background:transparent;font-size:14px;color:#1E1B2E;padding:4px 0;font-family:inherit;min-width:0} .wr-search-input::placeholder{color:#9CA3AF} .wr-search-clear{background:none;border:none;color:#9CA3AF;cursor:pointer;padding:4px;display:none;font-family:inherit} .wr-search-clear.visible{display:flex;align-items:center} .wr-search-clear:hover{color:#6B7280} .wr-search-clear svg{width:14px;height:14px} .wr-search-kbd-hint{display:none;align-items:center;padding:3px 8px;background:#fff;border:1px solid #E5E7EB;border-radius:6px;font-size:10.5px;font-weight:600;color:#6B7280;font-family:inherit;letter-spacing:.02em;white-space:nowrap;flex-shrink:0} .wr-search-input-wrap:focus-within .wr-search-kbd-hint{display:inline-flex} /* Chips keywords */ .search-keywords{display:flex;flex-wrap:wrap;gap:6px;margin:0 4px 18px} .search-keyword-chip{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:100px;background:#F5F3FF;color:var(--theme-color,#6C3AED);font-size:12.5px;font-weight:500;cursor:pointer;border:1px solid transparent;transition:background .15s,border-color .15s,transform .15s;font-family:inherit} .search-keyword-chip:hover{background:#EDE9FE;border-color:rgba(108,58,237,.2);transform:translateY(-1px);color:var(--theme-color,#6C3AED)} .search-keyword-chip.active{background:var(--theme-color,#6C3AED);color:#fff;border-color:var(--theme-color,#6C3AED)} .search-keyword-chip-icon{font-size:13px;line-height:1} .search-keywords-label{font-size:11px;font-weight:600;color:#9CA3AF;text-transform:uppercase;letter-spacing:.06em;margin-right:4px;align-self:center} /* ─── Sections de filtres SEO (chips → liens directs vers /jobs/{slug}) ─── */ .filter-section{margin:0 0 14px} .filter-section-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;padding:0 4px;flex-wrap:wrap} @media(max-width:540px){ .dash-filter-search{max-width:100%;width:100%} } .filter-section-title{display:flex;align-items:center;gap:7px;font-size:11.5px;font-weight:700;color:#6B7280;text-transform:uppercase;letter-spacing:.06em;margin:0} .filter-section-title-icon{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:6px;background:#F5F3FF;color:var(--theme-color,#6C3AED)} .filter-section-title-icon svg{width:11px;height:11px} .filter-section-toggle{background:none;border:none;font-size:11px;color:var(--theme-color,#6C3AED);font-weight:600;cursor:pointer;font-family:inherit;padding:4px 8px;border-radius:6px;transition:background .15s} .filter-section-toggle:hover{background:#F5F3FF} .filter-chips{display:flex;flex-wrap:wrap;gap:6px;padding:0 4px} .filter-chip{display:inline-flex;align-items:center;gap:5px;padding:7px 13px;border-radius:100px;background:#fff;color:#374151;font-size:12.5px;font-weight:500;cursor:pointer;border:1px solid #E5E7EB;text-decoration:none;transition:background .15s,border-color .15s,transform .15s,color .15s;font-family:inherit;white-space:nowrap} .filter-chip:hover{background:#F5F3FF;border-color:rgba(108,58,237,.3);color:var(--theme-color,#6C3AED);transform:translateY(-1px)} .filter-chip.active{background:var(--theme-color,#6C3AED);border-color:var(--theme-color,#6C3AED);color:#fff} .filter-chip.active:hover{background:#5B21B6;color:#fff} .filter-chip-icon{font-size:14px;line-height:1} .filter-chip-arrow{display:inline-flex;color:currentColor;opacity:.5;margin-left:2px} .filter-chip-arrow svg{width:10px;height:10px} /* Mode \"compact\" : sections initialement collapsées si > 6 items */ .filter-chips.collapsed{max-height:80px;overflow:hidden;position:relative} .filter-chips.collapsed::after{content:\"\";position:absolute;left:0;right:0;bottom:0;height:30px;background:linear-gradient(to bottom,transparent,#FAFAFA);pointer-events:none} /* ─── Bouton \"Voir plus\" sous les chips villes/métiers ─── */ .dash-filter-more-wrap{display:flex;justify-content:center;margin-top:10px;padding:0 4px} .dash-filter-more-btn{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;background:transparent;color:var(--theme-color,#6C3AED);border:1px dashed rgba(108,58,237,.35);border-radius:100px;font-size:12px;font-weight:600;font-family:inherit;cursor:pointer;transition:background .15s,border-style .15s,border-color .15s} .dash-filter-more-btn:hover{background:#F5F3FF;border-style:solid;border-color:var(--theme-color,#6C3AED)} .dash-filter-more-icon{display:inline-flex;align-items:center;color:currentColor;transition:transform .2s} .dash-filter-more-icon svg{width:12px;height:12px} .dash-filter-more-btn.is-expanded .dash-filter-more-icon{transform:rotate(180deg)} /* ─── Input de recherche dans le header (toujours visible) ─── */ .dash-filter-search{display:block;position:relative;flex:1;max-width:240px} @keyframes dashFilterFadeIn{from{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:translateY(0)}} .dash-filter-search-input{width:100%;padding:5px 10px 5px 28px;border:1px solid #E5E7EB;border-radius:100px;font-size:12px;color:#1E1B2E;background:#FAFAFA;font-family:inherit;outline:none;box-sizing:border-box;transition:border-color .15s,background .15s} .dash-filter-search-input:focus{border-color:rgba(108,58,237,.4);background:#fff} .dash-filter-search-input::placeholder{color:#9CA3AF} .dash-filter-search-icon{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:#9CA3AF;pointer-events:none;display:flex} .dash-filter-search-icon svg{width:11px;height:11px} /* État \"aucun résultat\" sous le filtre live */ .dash-filter-empty{display:none;padding:14px 12px;font-size:12.5px;color:#9CA3AF;font-style:italic;text-align:center;width:100%} .filter-chips.is-no-results .dash-filter-empty{display:block} /* Bandeau résultats */ .jobs-results-info{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 4px 14px;font-size:12px;color:#6B7280} .jobs-results-info strong{color:#1E1B2E;font-weight:700} /* Liste cards (style \"similar-card\" comme dans show.html.twig) */ .jobs-list{display:flex;flex-direction:column;gap:10px} .jobs-card{background:#fff;border-radius:14px;padding:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04);display:flex;align-items:center;gap:14px;text-decoration:none;color:inherit;transition:transform .15s,box-shadow .2s} .jobs-card:hover{transform:translateY(-1px);box-shadow:0 4px 20px rgba(108,58,237,.1);color:inherit} .jobs-card-logo{width:50px;height:50px;border-radius:12px;background:linear-gradient(135deg,#EDE9FE,#DDD6FE);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:20px;color:var(--theme-color,#6C3AED);flex-shrink:0;overflow:hidden} .jobs-card-logo img{width:100%;height:100%;object-fit:cover;border-radius:8px} .jobs-card-logo svg{width:24px;height:24px;opacity:.85} .jobs-card-info{flex:1;min-width:0} .jobs-card-title{font-size:14px;font-weight:700;color:#1E1B2E;line-height:1.3;margin:0 0 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .jobs-card-meta{font-size:12px;color:#6B7280;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .jobs-card-salary{font-size:11px;font-weight:600;color:var(--theme-color,#6C3AED);background:#F5F3FF;padding:3px 9px;border-radius:100px;white-space:nowrap;flex-shrink:0} .jobs-card-arrow{flex-shrink:0;color:#9CA3AF;transition:color .15s,transform .15s} .jobs-card:hover .jobs-card-arrow{color:var(--theme-color,#6C3AED);transform:translateX(2px)} .jobs-card-arrow svg{width:18px;height:18px} /* Skeleton (pendant chargement) */ .jobs-skeleton{display:flex;flex-direction:column;gap:10px} .jobs-skel-card{background:#fff;border-radius:14px;padding:14px;display:flex;align-items:center;gap:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04)} .jobs-skel-logo{width:50px;height:50px;border-radius:12px;background:linear-gradient(90deg,#F3F4F6 0%,#E5E7EB 50%,#F3F4F6 100%);background-size:200% 100%;animation:jobsSkelShim 1.4s ease-in-out infinite;flex-shrink:0} .jobs-skel-info{flex:1} .jobs-skel-line{height:14px;background:linear-gradient(90deg,#F3F4F6 0%,#E5E7EB 50%,#F3F4F6 100%);background-size:200% 100%;animation:jobsSkelShim 1.4s ease-in-out infinite;border-radius:4px;margin-bottom:6px} .jobs-skel-line.s1{width:60%} .jobs-skel-line.s2{width:40%;height:12px;margin-bottom:0} @keyframes jobsSkelShim{0%{background-position:200% 0}100%{background-position:-200% 0}} /* Bouton charger plus */ .jobs-load-more{display:flex;width:100%;padding:14px;margin-top:16px;background:#fff;color:var(--theme-color,#6C3AED);border:1.5px dashed rgba(108,58,237,.35);border-radius:12px;font-size:13.5px;font-weight:700;cursor:pointer;font-family:inherit;align-items:center;justify-content:center;gap:8px;transition:background .15s,border-color .15s} .jobs-load-more:hover{background:#F5F3FF;border-color:var(--theme-color,#6C3AED);border-style:solid;color:var(--theme-color,#6C3AED)} .jobs-load-more svg{width:14px;height:14px} .jobs-load-more:disabled{opacity:.6;cursor:not-allowed} .jobs-load-more.loading{cursor:wait} .jobs-load-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(108,58,237,.2);border-top-color:var(--theme-color,#6C3AED);border-radius:50%;animation:jobsLoadSpin .7s linear infinite} @keyframes jobsLoadSpin{to{transform:rotate(360deg)}} /* État vide */ .jobs-empty{text-align:center;padding:40px 20px;background:#fff;border-radius:14px;box-shadow:0 0 16px 0 rgba(0,0,0,0.04)} .jobs-empty-icon{display:inline-flex;align-items:center;justify-content:center;width:56px;height:56px;border-radius:16px;background:#F5F3FF;color:var(--theme-color,#6C3AED);margin-bottom:14px} .jobs-empty-icon svg{width:24px;height:24px} .jobs-empty-title{font-size:16px;font-weight:700;color:#1E1B2E;margin:0 0 6px} .jobs-empty-text{font-size:13px;color:#6B7280;margin:0} </style> {# Styles partagés de la promo card (définis dans la macro) #} {{ promo.styles() }}{% endblock css %}{% block body %} <div class=\"jobs-dash\"> <div class=\"jobs-dash-header\"> {% if currentSubKeyword is defined and currentSubKeyword is not null and currentCityFilter is defined and currentCityFilter is not null %} {# Cas combiné : ville + keyword #} <h1 class=\"jobs-dash-title\"> {% if currentCityFilter.icon is not empty %}{{ currentCityFilter.icon }} {% endif %}{{ currentSubKeyword }} {{ \x27job.dashboard.cityHeadingIn\x27|trans }} {{ currentCityFilter.label }} </h1> <p class=\"jobs-dash-subtitle\">{{ \x27job.dashboard.cityKeywordSubtitle\x27|trans({\x27%keyword%\x27: currentSubKeyword, \x27%city%\x27: currentCityFilter.label}) }}</p> {% elseif currentFilter is defined and currentFilter is not null %} <h1 class=\"jobs-dash-title\"> {% if currentFilter.icon is not empty %}{{ currentFilter.icon }} {% endif %}{{ currentFilter.shortTitle|default(currentFilter.label) }} </h1> {% if currentFilter.shortDescription is not empty %} <p class=\"jobs-dash-subtitle\">{{ currentFilter.shortDescription }}</p> {% else %} <p class=\"jobs-dash-subtitle\">{{ \x27job.dashboard.subtitle\x27|trans }}</p> {% endif %} {% else %} <h1 class=\"jobs-dash-title\">{{ \x27job.dashboard.heading\x27|trans }}</h1> <p class=\"jobs-dash-subtitle\">{{ \x27job.dashboard.subtitle\x27|trans }}</p> {% endif %} {# Badge \"Ville active\" + bouton \"Tout voir\" / ALL pour reset #} {% if currentCityFilter is defined and currentCityFilter is not null %} <div class=\"city-context-bar\"> <span class=\"city-context-label\">{{ \x27job.dashboard.contextLabel\x27|trans }}</span> <span class=\"city-context-badge\"> {% if currentCityFilter.icon is not empty %}<span class=\"city-context-badge-icon\">{{ currentCityFilter.icon }}</span>{% endif %} <span>{{ currentCityFilter.label }}</span> </span> <a href=\"{% if app.request.locale == \x27en\x27 %}{{ path(\x27whileresume_jobs_list\x27) }}{% else %}{{ path(\x27locale_whileresume_jobs_list\x27,{\x27_locale\x27:app.request.locale}) }}{% endif %}\" class=\"city-context-clear-btn\" title=\"{{ \x27job.dashboard.clearCity\x27|trans }}\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\" transform=\"rotate(180 12 12)\"/></svg> {{ \x27job.dashboard.allCities\x27|trans }} </a> </div> {% endif %} </div> {# ═══ Widget recherche ═══ #} <div class=\"wr-search-widget\"> <div class=\"wr-search-input-wrap\"> <span class=\"wr-search-icon\"> <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg> </span> <input type=\"text\" id=\"dashSearchInput\" class=\"wr-search-input\" placeholder=\"{% if currentCityFilter is defined and currentCityFilter is not null %}{{ \x27job.dashboard.searchInCity\x27|trans({\x27%city%\x27: currentCityFilter.label}) }}{% else %}{{ \x27job.show.searchPlaceholder\x27|trans }}{% endif %}\" value=\"{{ initialQuery|default(\x27\x27) }}\" autocomplete=\"off\"> <span class=\"wr-search-kbd-hint\" id=\"dashSearchKbdHint\">{{ \x27job.dashboard.pressEnter\x27|trans }}</span> <button type=\"button\" id=\"dashSearchClear\" class=\"wr-search-clear\" aria-label=\"Clear\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg> </button> </div> </div> {# Chips keywords cliquables #} {% if searchKeywords is defined and searchKeywords|length > 0 %} <div class=\"search-keywords\"> <span class=\"search-keywords-label\">{{ \x27job.show.keywordsLabel\x27|trans }}</span> {% for kw in searchKeywords %} {# Slug pour l\x27URL : translitération des accents FR + lowercase + remplacement caractères spéciaux #} {% set kwSlug = kw.label |replace({ \x27à\x27:\x27a\x27,\x27â\x27:\x27a\x27,\x27ä\x27:\x27a\x27,\x27á\x27:\x27a\x27,\x27ã\x27:\x27a\x27,\x27å\x27:\x27a\x27, \x27À\x27:\x27a\x27,\x27Â\x27:\x27a\x27,\x27Ä\x27:\x27a\x27,\x27Á\x27:\x27a\x27,\x27Ã\x27:\x27a\x27,\x27Å\x27:\x27a\x27, \x27é\x27:\x27e\x27,\x27è\x27:\x27e\x27,\x27ê\x27:\x27e\x27,\x27ë\x27:\x27e\x27,\x27ẽ\x27:\x27e\x27, \x27É\x27:\x27e\x27,\x27È\x27:\x27e\x27,\x27Ê\x27:\x27e\x27,\x27Ë\x27:\x27e\x27, \x27î\x27:\x27i\x27,\x27ï\x27:\x27i\x27,\x27ì\x27:\x27i\x27,\x27í\x27:\x27i\x27, \x27Î\x27:\x27i\x27,\x27Ï\x27:\x27i\x27,\x27Ì\x27:\x27i\x27,\x27Í\x27:\x27i\x27, \x27ô\x27:\x27o\x27,\x27ö\x27:\x27o\x27,\x27ò\x27:\x27o\x27,\x27ó\x27:\x27o\x27,\x27õ\x27:\x27o\x27,\x27ø\x27:\x27o\x27, \x27Ô\x27:\x27o\x27,\x27Ö\x27:\x27o\x27,\x27Ò\x27:\x27o\x27,\x27Ó\x27:\x27o\x27,\x27Õ\x27:\x27o\x27,\x27Ø\x27:\x27o\x27, \x27û\x27:\x27u\x27,\x27ü\x27:\x27u\x27,\x27ù\x27:\x27u\x27,\x27ú\x27:\x27u\x27, \x27Û\x27:\x27u\x27,\x27Ü\x27:\x27u\x27,\x27Ù\x27:\x27u\x27,\x27Ú\x27:\x27u\x27, \x27ÿ\x27:\x27y\x27,\x27ý\x27:\x27y\x27,\x27Ÿ\x27:\x27y\x27,\x27Ý\x27:\x27y\x27, \x27ç\x27:\x27c\x27,\x27Ç\x27:\x27c\x27, \x27ñ\x27:\x27n\x27,\x27Ñ\x27:\x27n\x27, \x27œ\x27:\x27oe\x27,\x27Œ\x27:\x27oe\x27,\x27æ\x27:\x27ae\x27,\x27Æ\x27:\x27ae\x27, \"\x27\":\x27-\x27,\x27 \x27:\x27-\x27,\x27/\x27:\x27-\x27,\x27_\x27:\x27-\x27,\x27.\x27:\x27-\x27,\x27,\x27:\x27-\x27, \x27(\x27:\x27\x27,\x27*\x27:\x27\x27,\x27)\x27:\x27\x27,\x27&\x27:\x27-and-\x27,\x27+\x27:\x27-plus-\x27, \x27#\x27:\x27\x27,\x27?\x27:\x27\x27,\x27!\x27:\x27\x27,\x27\"\x27:\x27\x27,\x27’\x27:\x27-\x27,\x27`\x27:\x27-\x27 }) |lower |replace({\x27--\x27:\x27-\x27,\x27---\x27:\x27-\x27}) |trim(\x27-\x27) %} {% if currentCityFilter is defined and currentCityFilter is not null %} {# Contexte ville : chip = lien vers /jobs/ville/keyword #} <a href=\"{% if app.request.locale == \x27en\x27 %}{{ path(\x27cvs_application_jobs_filter_keyword\x27,{\x27slug\x27:currentCityFilter.slug,\x27keyword\x27:kwSlug}) }}{% else %}{{ path(\x27locale_cvs_application_jobs_filter_keyword\x27,{\x27_locale\x27:app.request.locale,\x27slug\x27:currentCityFilter.slug,\x27keyword\x27:kwSlug}) }}{% endif %}\" class=\"search-keyword-chip{% if currentSubKeywordSlug is defined and currentSubKeywordSlug == kwSlug %} active{% endif %}\"> {% if kw.icon is not empty %}<span class=\"search-keyword-chip-icon\">{{ kw.icon }}</span>{% endif %} <span>{{ kw.label }}</span> </a> {% else %} {# Pas de contexte ville : chip pré-remplit la search (comportement existant) #} <button type=\"button\" class=\"search-keyword-chip\" data-keyword=\"{{ kw.searchKeyword|default(kw.label) }}\"> {% if kw.icon is not empty %}<span class=\"search-keyword-chip-icon\">{{ kw.icon }}</span>{% endif %} <span>{{ kw.label }}</span> </button> {% endif %} {% endfor %} </div> {% endif %} {# ═══ Filtres SEO : Villes (chips → /jobs/{slug}) — 14 visibles + reste cliqué pour révéler ═══ #} {% if sidebarFiltersCities is defined and sidebarFiltersCities|length > 0 %} {% set citiesInitial = 14 %} <div class=\"filter-section\" id=\"filterSectionCities\"> <div class=\"filter-section-head\"> <h3 class=\"filter-section-title\"> <span class=\"filter-section-title-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/></svg> </span> {{ \x27job.dashboard.popularCities\x27|trans }} </h3> {# Input de recherche (visible uniquement quand expanded) #} {% if sidebarFiltersCities|length > citiesInitial %} <div class=\"dash-filter-search\"> <span class=\"dash-filter-search-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg> </span> <input type=\"text\" class=\"dash-filter-search-input\" data-search-target=\"filterChipsCities\" placeholder=\"{{ \x27job.dashboard.filterSearchCity\x27|trans }}\" autocomplete=\"off\"> </div> {% endif %} </div> <div class=\"filter-chips dash-filter-chips\" id=\"filterChipsCities\" data-initial=\"{{ citiesInitial }}\"> {% for f in sidebarFiltersCities %} <a href=\"{% if app.request.locale == \x27en\x27 %}{{ path(\x27cvs_application_jobs_filter\x27,{\x27slug\x27:f.slug}) }}{% else %}{{ path(\x27locale_cvs_application_jobs_filter\x27,{\x27_locale\x27:app.request.locale,\x27slug\x27:f.slug}) }}{% endif %}\" class=\"filter-chip dash-filter-item{% if currentFilter is defined and currentFilter is not null and currentFilter.slug == f.slug %} active{% endif %}\" data-filter-slug=\"{{ f.slug }}\" data-filter-label=\"{{ f.label }}\" data-index=\"{{ loop.index0 }}\"{% if loop.index0 >= citiesInitial %} style=\"display:none\"{% endif %}> {% if f.icon is not empty %}<span class=\"filter-chip-icon\">{{ f.icon }}</span>{% endif %} <span>{{ f.label }}</span> <span class=\"filter-chip-arrow\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\"/></svg> </span> </a> {% endfor %} <div class=\"dash-filter-empty\">{{ \x27job.dashboard.filterNoResults\x27|trans }}</div> </div> {% if sidebarFiltersCities|length > citiesInitial %} <div class=\"dash-filter-more-wrap\"> <button type=\"button\" class=\"dash-filter-more-btn\" data-target=\"filterChipsCities\" data-section=\"filterSectionCities\"> <span class=\"dash-filter-more-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg> </span> <span class=\"dash-filter-more-label\" data-more=\"{{ \x27job.dashboard.showMoreCities\x27|trans({\x27%n%\x27: sidebarFiltersCities|length - citiesInitial}) }}\" data-less=\"{{ \x27job.dashboard.showLessCities\x27|trans }}\">{{ \x27job.dashboard.showMoreCities\x27|trans({\x27%n%\x27: sidebarFiltersCities|length - citiesInitial}) }}</span> </button> </div> {% endif %} </div> {% endif %} {# ═══ Filtres SEO : Métiers (chips → /jobs/{slug}) — 8 visibles + reste cliqué pour révéler ═══ #} {% if sidebarFiltersCategories is defined and sidebarFiltersCategories|length > 0 %} {% set categoriesInitial = 8 %} <div class=\"filter-section\" id=\"filterSectionCategories\"> <div class=\"filter-section-head\"> <h3 class=\"filter-section-title\"> <span class=\"filter-section-title-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><rect x=\"2\" y=\"7\" width=\"20\" height=\"14\" rx=\"2\"/><path d=\"M16 7V5a4 4 0 00-8 0v2\"/></svg> </span> {{ \x27job.dashboard.popularCategories\x27|trans }} </h3> {# Input de recherche (visible uniquement quand expanded) #} {% if sidebarFiltersCategories|length > categoriesInitial %} <div class=\"dash-filter-search\"> <span class=\"dash-filter-search-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg> </span> <input type=\"text\" class=\"dash-filter-search-input\" data-search-target=\"filterChipsCategories\" placeholder=\"{{ \x27job.dashboard.filterSearchCategory\x27|trans }}\" autocomplete=\"off\"> </div> {% endif %} </div> <div class=\"filter-chips dash-filter-chips\" id=\"filterChipsCategories\" data-initial=\"{{ categoriesInitial }}\"> {% for f in sidebarFiltersCategories %} <a href=\"{% if app.request.locale == \x27en\x27 %}{{ path(\x27cvs_application_jobs_filter\x27,{\x27slug\x27:f.slug}) }}{% else %}{{ path(\x27locale_cvs_application_jobs_filter\x27,{\x27_locale\x27:app.request.locale,\x27slug\x27:f.slug}) }}{% endif %}\" class=\"filter-chip dash-filter-item{% if currentFilter is defined and currentFilter is not null and currentFilter.slug == f.slug %} active{% endif %}\" data-filter-slug=\"{{ f.slug }}\" data-filter-label=\"{{ f.label }}\" data-index=\"{{ loop.index0 }}\"{% if loop.index0 >= categoriesInitial %} style=\"display:none\"{% endif %}> {% if f.icon is not empty %}<span class=\"filter-chip-icon\">{{ f.icon }}</span>{% endif %} <span>{{ f.label }}</span> <span class=\"filter-chip-arrow\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"9 18 15 12 9 6\"/></svg> </span> </a> {% endfor %} <div class=\"dash-filter-empty\">{{ \x27job.dashboard.filterNoResults\x27|trans }}</div> </div> {% if sidebarFiltersCategories|length > categoriesInitial %} <div class=\"dash-filter-more-wrap\"> <button type=\"button\" class=\"dash-filter-more-btn\" data-target=\"filterChipsCategories\" data-section=\"filterSectionCategories\"> <span class=\"dash-filter-more-icon\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg> </span> <span class=\"dash-filter-more-label\" data-more=\"{{ \x27job.dashboard.showMoreCategories\x27|trans({\x27%n%\x27: sidebarFiltersCategories|length - categoriesInitial}) }}\" data-less=\"{{ \x27job.dashboard.showLessCategories\x27|trans }}\">{{ \x27job.dashboard.showMoreCategories\x27|trans({\x27%n%\x27: sidebarFiltersCategories|length - categoriesInitial}) }}</span> </button> </div> {% endif %} </div> {% endif %} {# Bandeau d\x27info (compteur de résultats) #} <div class=\"jobs-results-info\" id=\"jobsResultsInfo\"> <span id=\"jobsResultsCount\">{{ \x27job.dashboard.loading\x27|trans }}</span> </div> {# Liste des offres (peuplée en JS) #} <div class=\"jobs-list\" id=\"jobsList\"> <div class=\"jobs-skeleton\"> {% for i in 1..5 %} <div class=\"jobs-skel-card\"> <div class=\"jobs-skel-logo\"></div> <div class=\"jobs-skel-info\"> <div class=\"jobs-skel-line s1\"></div> <div class=\"jobs-skel-line s2\"></div> </div> </div> {% endfor %} </div> </div> {# Bouton \"Charger plus\" #} <button type=\"button\" class=\"jobs-load-more\" id=\"jobsLoadMore\" style=\"display:none;\"> <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"><polyline points=\"6 9 12 15 18 9\"/></svg> <span id=\"jobsLoadMoreLabel\">{{ \x27job.dashboard.loadMore\x27|trans }}</span> </button> {# Template HTML invisible cloné par le JS pour intercaler la promo card. Affiché uniquement aux utilisateurs non connectés via la logique JS. Les textes/bullets viennent automatiquement des clés job.show.promo* du YAML. #} {% if app.user is null %} {{ promo.card_template({ template_id: \x27jobs-promo-card-template\x27, login_url: app.request.locale == \x27en\x27 ? path(\x27cvs_gestion_candidates_dashboard\x27) : path(\x27locale_cvs_gestion_candidates_dashboard\x27,{\x27_locale\x27:app.request.locale}) }) }} {% endif %} </div>{% endblock body %}{% block footerjs %} <script> (function(){ \x27use strict\x27; try { var LOCALE = \x27{{ app.request.locale }}\x27; var IS_AUTHENTICATED = {{ app.user ? \x27true\x27 : \x27false\x27 }}; var SEARCH_API_URL = \x27{{ app.request.locale == \"en\" ? path(\"cvs_application_jobs_api_search\") : path(\"locale_cvs_application_jobs_api_search\",{\"_locale\":app.request.locale}) }}\x27; var JOB_SHOW_URL_TEMPLATE = \x27{{ app.request.locale == \"en\" ? path(\"cvs_application_jobs_api_search\",{\"slug\":\"__SLUG__\"}) : path(\"locale_cvs_application_job_show\",{\"_locale\":app.request.locale,\"slug\":\"__SLUG__\"}) }}\x27; var PAGE_SIZE = 10; var currentQuery = {{ initialQuery|default(\x27\x27)|json_encode|raw }}; var currentOffset = 0; var currentTotal = 0; var isFetching = false; // Contexte ville (vient du serveur si on est sur /jobs/paris/... sinon vide) var CITY_KEYWORD = {{ currentCityKeyword|default(\x27\x27)|json_encode|raw }}; // Slug ville pour générer les URLs de redirection au submit var CITY_SLUG = {{ currentCityFilter is defined and currentCityFilter is not null ? currentCityFilter.slug|json_encode|raw : \x27null\x27 }}; // URL pour le dashboard global (sans ville) var DASHBOARD_URL = \x27{{ app.request.locale == \"en\" ? path(\"whileresume_jobs_list\") : path(\"locale_whileresume_jobs_list\",{\"_locale\":app.request.locale}) }}\x27; // Templates URL pour /jobs/{citySlug} et /jobs/{citySlug}/{keyword} var CITY_LANDING_URL_TEMPLATE = {{ currentCityFilter is defined and currentCityFilter is not null ? (app.request.locale == \x27en\x27 ? path(\x27cvs_application_jobs_filter\x27,{\x27slug\x27:currentCityFilter.slug}) : path(\x27locale_cvs_application_jobs_filter\x27,{\x27_locale\x27:app.request.locale,\x27slug\x27:currentCityFilter.slug}))|json_encode|raw : \x27null\x27 }}; var CITY_KEYWORD_URL_TEMPLATE = {{ currentCityFilter is defined and currentCityFilter is not null ? (app.request.locale == \x27en\x27 ? path(\x27cvs_application_jobs_filter_keyword\x27,{\x27slug\x27:currentCityFilter.slug,\x27keyword\x27:\x27kwplaceholder\x27}) : path(\x27locale_cvs_application_jobs_filter_keyword\x27,{\x27_locale\x27:app.request.locale,\x27slug\x27:currentCityFilter.slug,\x27keyword\x27:\x27kwplaceholder\x27}))|json_encode|raw : \x27null\x27 }}; // Liste des keywords BDD avec leur slug (pour le matching côté client au submit) var KEYWORDS_DATA = [ {% for kw in searchKeywords|default([]) %} {% set kwSlugForJs = kw.label |replace({ \x27à\x27:\x27a\x27,\x27â\x27:\x27a\x27,\x27ä\x27:\x27a\x27,\x27á\x27:\x27a\x27,\x27ã\x27:\x27a\x27,\x27å\x27:\x27a\x27, \x27À\x27:\x27a\x27,\x27Â\x27:\x27a\x27,\x27Ä\x27:\x27a\x27,\x27Á\x27:\x27a\x27,\x27Ã\x27:\x27a\x27,\x27Å\x27:\x27a\x27, \x27é\x27:\x27e\x27,\x27è\x27:\x27e\x27,\x27ê\x27:\x27e\x27,\x27ë\x27:\x27e\x27,\x27ẽ\x27:\x27e\x27, \x27É\x27:\x27e\x27,\x27È\x27:\x27e\x27,\x27Ê\x27:\x27e\x27,\x27Ë\x27:\x27e\x27, \x27î\x27:\x27i\x27,\x27ï\x27:\x27i\x27,\x27ì\x27:\x27i\x27,\x27í\x27:\x27i\x27, \x27Î\x27:\x27i\x27,\x27Ï\x27:\x27i\x27,\x27Ì\x27:\x27i\x27,\x27Í\x27:\x27i\x27, \x27ô\x27:\x27o\x27,\x27ö\x27:\x27o\x27,\x27ò\x27:\x27o\x27,\x27ó\x27:\x27o\x27,\x27õ\x27:\x27o\x27,\x27ø\x27:\x27o\x27, \x27Ô\x27:\x27o\x27,\x27Ö\x27:\x27o\x27,\x27Ò\x27:\x27o\x27,\x27Ó\x27:\x27o\x27,\x27Õ\x27:\x27o\x27,\x27Ø\x27:\x27o\x27, \x27û\x27:\x27u\x27,\x27ü\x27:\x27u\x27,\x27ù\x27:\x27u\x27,\x27ú\x27:\x27u\x27, \x27Û\x27:\x27u\x27,\x27Ü\x27:\x27u\x27,\x27Ù\x27:\x27u\x27,\x27Ú\x27:\x27u\x27, \x27ÿ\x27:\x27y\x27,\x27ý\x27:\x27y\x27,\x27Ÿ\x27:\x27y\x27,\x27Ý\x27:\x27y\x27, \x27ç\x27:\x27c\x27,\x27Ç\x27:\x27c\x27,\x27ñ\x27:\x27n\x27,\x27Ñ\x27:\x27n\x27, \x27œ\x27:\x27oe\x27,\x27Œ\x27:\x27oe\x27,\x27æ\x27:\x27ae\x27,\x27Æ\x27:\x27ae\x27, \"\x27\":\x27-\x27,\x27 \x27:\x27-\x27,\x27/\x27:\x27-\x27,\x27_\x27:\x27-\x27,\x27.\x27:\x27-\x27,\x27,\x27:\x27-\x27, \x27(\x27:\x27\x27,\x27*\x27:\x27\x27,\x27)\x27:\x27\x27,\x27&\x27:\x27-and-\x27,\x27+\x27:\x27-plus-\x27, \x27#\x27:\x27\x27,\x27?\x27:\x27\x27,\x27!\x27:\x27\x27,\x27\"\x27:\x27\x27,\x27’\x27:\x27-\x27,\x27`\x27:\x27-\x27 }) |lower |replace({\x27--\x27:\x27-\x27,\x27---\x27:\x27-\x27}) |trim(\x27-\x27) %} { label: {{ kw.label|json_encode|raw }}, searchKeyword: {{ (kw.searchKeyword ?: kw.label)|json_encode|raw }}, slug: {{ kwSlugForJs|json_encode|raw }} }{% if not loop.last %},{% endif %} {% endfor %} ]; var input = document.getElementById(\x27dashSearchInput\x27); var clearBtn = document.getElementById(\x27dashSearchClear\x27); var listEl = document.getElementById(\x27jobsList\x27); var infoEl = document.getElementById(\x27jobsResultsCount\x27); var loadMoreBtn = document.getElementById(\x27jobsLoadMore\x27); var loadMoreLabel = document.getElementById(\x27jobsLoadMoreLabel\x27); function escapeHtml(s){ if(s == null) return \x27\x27; return String(s).replace(/[&<>\"\x27]/g, function(c){ return {\x27&\x27:\x27&\x27,\x27<\x27:\x27<\x27,\x27>\x27:\x27>\x27,\x27\"\x27:\x27"\x27,\"\x27\":\x27'\x27}[c]; }); } function buildJobCard(item){ // Fallback logo : icône \"immeuble\" stylisée si pas de logo entreprise var fallbackLogo = \x27<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\x27 + \x27<path d=\"M3 21h18\"/>\x27 + \x27<path d=\"M5 21V7l8-4v18\"/>\x27 + \x27<path d=\"M19 21V11l-6-4\"/>\x27 + \x27<path d=\"M9 9h.01\"/>\x27 + \x27<path d=\"M9 13h.01\"/>\x27 + \x27<path d=\"M9 17h.01\"/>\x27 + \x27</svg>\x27; var logoHtml = item.logo ? \x27<img src=\"\x27 + escapeHtml(item.logo) + \x27\" alt=\"\" onerror=\"this.parentNode.innerHTML=\\\x27\x27 + fallbackLogo.replace(/\x27/g, \"\\\\\x27\") + \x27\\\x27;\">\x27 : fallbackLogo; var meta = []; if(item.companyName) meta.push(escapeHtml(item.companyName)); if(item.city) meta.push(escapeHtml(item.city)); if(item.employmentType) meta.push(escapeHtml(item.employmentType)); var salaryHtml = (item.salaryMin && item.salaryMax) ? \x27<span class=\"jobs-card-salary\">\x27 + item.salaryMin + \x27–\x27 + item.salaryMax + \x27 \x27 + escapeHtml(item.devise || \x27\x27) + \x27</span>\x27 : \x27\x27; var url = item.url || JOB_SHOW_URL_TEMPLATE.replace(\x27__SLUG__\x27, encodeURIComponent(item.slug)); var a = document.createElement(\x27a\x27); a.href = url; a.className = \x27jobs-card\x27; a.innerHTML = \x27<div class=\"jobs-card-logo\">\x27 + logoHtml + \x27</div>\x27 + \x27<div class=\"jobs-card-info\">\x27 + \x27<div class=\"jobs-card-title\">\x27 + escapeHtml(item.title || \x27\x27) + \x27</div>\x27 + \x27<div class=\"jobs-card-meta\">\x27 + meta.join(\x27 · \x27) + \x27</div>\x27 + \x27</div>\x27 + salaryHtml + \x27<span class=\"jobs-card-arrow\"><svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><polyline points=\"9 18 15 12 9 6\"/></svg></span>\x27; return a; } /** * Clone la promo card depuis le <template> rendu par la macro Twig. * Le HTML est défini une seule fois dans _macros/promo_card.html.twig. * Retourne null si le template n\x27est pas présent (ex: user connecté). */ function buildPromoCard(){ var tpl = document.getElementById(\x27jobs-promo-card-template\x27); if(!tpl || !tpl.content) return null; var node = tpl.content.firstElementChild; return node ? node.cloneNode(true) : null; } function renderEmpty(){ listEl.innerHTML = \x27<div class=\"jobs-empty\">\x27 + \x27<div class=\"jobs-empty-icon\">\x27 + \x27<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"11\" cy=\"11\" r=\"8\"/><path d=\"M21 21l-4.35-4.35\"/></svg>\x27 + \x27</div>\x27 + \x27<div class=\"jobs-empty-title\">{{ \x27job.dashboard.emptyTitle\x27|trans|escape(\x27js\x27) }}</div>\x27 + \x27<div class=\"jobs-empty-text\">{{ \x27job.dashboard.emptyText\x27|trans|escape(\x27js\x27) }}</div>\x27 + \x27</div>\x27; } function setLoadMoreState(state){ if(!loadMoreBtn) return; if(state === \x27loading\x27){ loadMoreBtn.classList.add(\x27loading\x27); loadMoreBtn.disabled = true; loadMoreLabel.innerHTML = \x27<span class=\"jobs-load-spinner\"></span> {{ \x27job.dashboard.loadingMore\x27|trans|escape(\x27js\x27) }}\x27; } else { loadMoreBtn.classList.remove(\x27loading\x27); loadMoreBtn.disabled = false; loadMoreLabel.textContent = \x27{{ \x27job.dashboard.loadMore\x27|trans|escape(\x27js\x27) }}\x27; } } function fetchJobs(query, offset, append){ if(isFetching) return; isFetching = true; if(!append){ // Nouvelle recherche : on remet à zéro et affiche skeleton listEl.innerHTML = \x27<div class=\"jobs-skeleton\">\x27 + Array(5).fill(0).map(function(){ return \x27<div class=\"jobs-skel-card\"><div class=\"jobs-skel-logo\"></div><div class=\"jobs-skel-info\"><div class=\"jobs-skel-line s1\"></div><div class=\"jobs-skel-line s2\"></div></div></div>\x27; }).join(\x27\x27) + \x27</div>\x27; if(infoEl) infoEl.textContent = \x27{{ \x27job.dashboard.loading\x27|trans|escape(\x27js\x27) }}\x27; if(loadMoreBtn) loadMoreBtn.style.display = \x27none\x27; } else { setLoadMoreState(\x27loading\x27); } var url = SEARCH_API_URL + \x27?q=\x27 + encodeURIComponent(query || \x27\x27) + \x27&locale=\x27 + LOCALE + \x27&limit=\x27 + PAGE_SIZE + \x27&offset=\x27 + offset; if(CITY_KEYWORD){ url += \x27&city=\x27 + encodeURIComponent(CITY_KEYWORD); } // Dashboard sans filtre : on demande explicitement les dernières offres if(!query && !CITY_KEYWORD){ url += \x27&all=1\x27; } fetch(url, {headers:{\x27Accept\x27:\x27application/json\x27}}) .then(function(r){ return r.ok ? r.json() : null; }) .then(function(data){ isFetching = false; if(!data){ if(!append) renderEmpty(); setLoadMoreState(\x27idle\x27); return; } var items = data.items || []; currentTotal = data.total || 0; if(!append){ listEl.innerHTML = \x27\x27; if(items.length === 0){ renderEmpty(); if(infoEl) infoEl.innerHTML = \x27<strong>0</strong> {{ \x27job.dashboard.resultsCount\x27|trans|escape(\x27js\x27) }}\x27; if(loadMoreBtn) loadMoreBtn.style.display = \x27none\x27; return; } } // Insérer la promo card après la 5ème offre (uniquement au 1er chargement, // si user non connecté et qu\x27on a au moins 5 offres) var insertPromoAt = (!append && !IS_AUTHENTICATED && items.length >= 5) ? 5 : -1; items.forEach(function(item, idx){ listEl.appendChild(buildJobCard(item)); if(idx === insertPromoAt - 1){ var promoNode = buildPromoCard(); if(promoNode) listEl.appendChild(promoNode); } }); currentOffset = offset + items.length; if(infoEl){ infoEl.innerHTML = \x27<strong>\x27 + currentTotal + \x27</strong> {{ \x27job.dashboard.resultsCount\x27|trans|escape(\x27js\x27) }}\x27; } // Afficher / cacher \"Charger plus\" if(loadMoreBtn){ if(currentOffset < currentTotal){ loadMoreBtn.style.display = \x27flex\x27; } else { loadMoreBtn.style.display = \x27none\x27; } setLoadMoreState(\x27idle\x27); } }) .catch(function(err){ isFetching = false; console.error(\x27[whr-dash] fetch error\x27, err); setLoadMoreState(\x27idle\x27); }); } /** * Slugifie un texte côté client. DOIT produire EXACTEMENT le même slug * que la méthode PHP slugify() du JobsController et que le filtre Twig * utilisé pour rendre les chips. */ function slugify(text){ if(!text) return \x27\x27; var t = String(text); // Pré-remplacements sémantiques t = t.replace(/&/g, \x27-and-\x27).replace(/\\+/g, \x27-plus-\x27) .replace(/[œŒ]/g, \x27oe\x27).replace(/[æÆ]/g, \x27ae\x27); // Translitération accents → ASCII via NFD + strip diacritics t = t.normalize ? t.normalize(\x27NFD\x27).replace(/[\\u0300-\\u036f]/g, \x27\x27) : t; t = t.toLowerCase(); // Tout ce qui n\x27est pas a-z 0-9 → tiret t = t.replace(/[^a-z0-9]+/g, \x27-\x27); return t.replace(/^-+|-+\$/g, \x27\x27); } /** * Tente de matcher un texte tapé avec un keyword en BDD (par slug ou label). * Retourne l\x27objet keyword si trouvé, null sinon. */ function findMatchingKeyword(text){ if(!text || !KEYWORDS_DATA || !KEYWORDS_DATA.length) return null; var slug = slugify(text); if(!slug) return null; for(var i = 0; i < KEYWORDS_DATA.length; i++){ var kw = KEYWORDS_DATA[i]; // Match sur slug exact OU label/searchKeyword exact (case insensitive) if(kw.slug === slug) return kw; if(slugify(kw.searchKeyword) === slug) return kw; } return null; } /** * Au submit : décide où rediriger l\x27utilisateur en fonction du contexte. * - Si on est sur une ville et le texte matche un keyword BDD → /jobs/{ville}/{slug-kw} * - Sinon si on est sur une ville → /jobs/{ville}?search={texte} * - Sinon (pas de ville) → /jobs?q={texte} * - Si texte vide ET ville définie → /jobs/{ville} (reset) * - Si texte vide ET pas de ville → /jobs (reset) */ function submitSearch(query){ query = (query || \x27\x27).trim(); // Reset (recherche vide) if(!query){ if(CITY_SLUG && CITY_LANDING_URL_TEMPLATE){ window.location.href = CITY_LANDING_URL_TEMPLATE; } else { window.location.href = DASHBOARD_URL; } return; } // Cas 1 : on est sur une ville if(CITY_SLUG && CITY_KEYWORD_URL_TEMPLATE){ var matched = findMatchingKeyword(query); if(matched && matched.slug){ // Match BDD → URL slug propre /jobs/paris/developpeur window.location.href = CITY_KEYWORD_URL_TEMPLATE.replace(\x27kwplaceholder\x27, encodeURIComponent(matched.slug)); return; } // Pas de match → fallback ?search=texte window.location.href = CITY_LANDING_URL_TEMPLATE + \x27?search=\x27 + encodeURIComponent(query); return; } // Cas 2 : pas de ville → dashboard global avec ?q= window.location.href = DASHBOARD_URL + \x27?q=\x27 + encodeURIComponent(query); } /** * Lance la search côté UI (sans redirection — utilisée pour les chips et * pour la \"Charger plus\"). */ function startSearch(query){ currentQuery = query; currentOffset = 0; currentTotal = 0; fetchJobs(query, 0, false); // Update clear button if(clearBtn){ if(query) clearBtn.classList.add(\x27visible\x27); else clearBtn.classList.remove(\x27visible\x27); } // Update active chip (uniquement les chips qui sont des <button>, pas les <a>) document.querySelectorAll(\x27button.search-keyword-chip\x27).forEach(function(c){ if(c.getAttribute(\x27data-keyword\x27) === query) c.classList.add(\x27active\x27); else c.classList.remove(\x27active\x27); }); } // ═══ Submit-only : Entrée déclenche la search ET change l\x27URL ═══ if(input){ input.addEventListener(\x27keydown\x27, function(e){ if(e.key === \x27Enter\x27 || e.keyCode === 13){ e.preventDefault(); submitSearch(input.value); } }); // Affiche bouton clear si query initiale if(input.value.trim()){ if(clearBtn) clearBtn.classList.add(\x27visible\x27); } } // Bouton clear : reset complet → redirection vers /jobs ou /jobs/{ville} if(clearBtn){ clearBtn.addEventListener(\x27click\x27, function(){ submitSearch(\x27\x27); }); } // Chips keywords (cas dashboard global, sans contexte ville → comportement local) // En contexte ville, les chips sont des <a href> directs gérés par le navigateur. document.querySelectorAll(\x27button.search-keyword-chip\x27).forEach(function(chip){ chip.addEventListener(\x27click\x27, function(){ var kw = chip.getAttribute(\x27data-keyword\x27); if(!kw) return; // Sur dashboard global : on submit (redirige vers /jobs?q=kw) submitSearch(kw); }); }); // Bouton \"Charger plus\" if(loadMoreBtn){ loadMoreBtn.addEventListener(\x27click\x27, function(){ if(isFetching) return; fetchJobs(currentQuery, currentOffset, true); }); } // ═══ Bouton \"Voir plus\" + Recherche live des chips ═══ /** * Slugify simple côté UI pour matching tolérant aux accents * (ex: \"developpeur\" matche \"Développeur\") */ function dashSlug(str){ if(!str) return \x27\x27; var t = String(str); t = t.normalize ? t.normalize(\x27NFD\x27).replace(/[\\u0300-\\u036f]/g, \x27\x27) : t; return t.toLowerCase().trim(); } document.querySelectorAll(\x27.dash-filter-more-btn\x27).forEach(function(btn){ var targetId = btn.getAttribute(\x27data-target\x27); var sectionId = btn.getAttribute(\x27data-section\x27); var container = document.getElementById(targetId); var section = sectionId ? document.getElementById(sectionId) : null; if(!container) return; var label = btn.querySelector(\x27.dash-filter-more-label\x27); if(!label) return; var initial = parseInt(container.getAttribute(\x27data-initial\x27), 10) || 14; var items = container.querySelectorAll(\x27.dash-filter-item\x27); var searchInput = section ? section.querySelector(\x27.dash-filter-search-input\x27) : null; // 2 états indépendants : // - userExpanded : l\x27utilisateur a cliqué sur \"Voir plus\" // - searchActive : l\x27input contient du texte (auto-expand temporaire) // Mode développé = userExpanded || searchActive var userExpanded = false; function isEffectivelyExpanded(){ var hasSearch = searchInput && searchInput.value.trim().length > 0; return userExpanded || hasSearch; } function applyDisplay(){ var filterText = searchInput ? searchInput.value : \x27\x27; var query = dashSlug(filterText || \x27\x27); var expanded = isEffectivelyExpanded(); var visibleCount = 0; items.forEach(function(it, i){ var label = it.getAttribute(\x27data-filter-label\x27) || \x27\x27; var matches = !query || dashSlug(label).indexOf(query) !== -1; if(expanded){ // Mode développé : on affiche tous les items qui matchent la recherche it.style.display = matches ? \x27\x27 : \x27none\x27; if(matches) visibleCount++; } else { // Mode collapsé : on affiche les N premiers (pas de filtrage) it.style.display = (i < initial) ? \x27\x27 : \x27none\x27; if(i < initial) visibleCount++; } }); // Toggle \"aucun résultat\" (uniquement quand recherche active) if(query && visibleCount === 0){ container.classList.add(\x27is-no-results\x27); } else { container.classList.remove(\x27is-no-results\x27); } // Synchroniser le bouton \"Voir plus/moins\" avec l\x27état effectif if(expanded){ btn.classList.add(\x27is-expanded\x27); label.textContent = label.getAttribute(\x27data-less\x27); } else { btn.classList.remove(\x27is-expanded\x27); label.textContent = label.getAttribute(\x27data-more\x27); } } btn.addEventListener(\x27click\x27, function(){ userExpanded = !userExpanded; if(!userExpanded){ // Reset input quand l\x27utilisateur collapse manuellement if(searchInput){ searchInput.value = \x27\x27; } // Scroll vers le bouton btn.scrollIntoView({behavior:\x27smooth\x27, block:\x27nearest\x27}); } applyDisplay(); }); // Recherche live dans les chips quand on tape dans l\x27input // → auto-expand pendant la recherche, retour à l\x27état userExpanded quand on vide if(searchInput){ searchInput.addEventListener(\x27input\x27, function(){ applyDisplay(); }); } }); // Premier chargement (vide ou avec query initiale) fetchJobs(currentQuery, 0, false); } catch(err){ console.error(\x27[whr-dash] init error\x27, err); } })(); </script>{% endblock footerjs %}", "application/whileresume/application/jobs/dashboard.html.twig", "/var/www/vhosts/whileresume.com/b.whileresume.app/templates/application/whileresume/application/jobs/dashboard.html.twig"); }}