diff --git a/src/components/BarraEstado/BarraEstadoStandalone.js b/src/components/BarraEstado/BarraEstadoStandalone.js index f1afd4d..d403e55 100644 --- a/src/components/BarraEstado/BarraEstadoStandalone.js +++ b/src/components/BarraEstado/BarraEstadoStandalone.js @@ -1,463 +1,636 @@ -(function () { - 'use strict' +// barra-estado.js +// Web Component da barra de estado do Governo do RS + +const COMPONENT_TAG = 'barra-estado'; + +const DEFAULT_BLOCKED_HOSTS = [ + "sitedpers.des.intra.rs.gov.br", + "sitedpers.hml.rs.gov.br", + "www.defensoria.rs.def.br", + "www.defensoria.rs.gov.br", + "www.dpe.rs.gov.br", + "matriz2-hotsite.des.procergs.localhost", + "servicos.detran.rs.gov.br", + "siteexp.des.procergs.localhost", + "siteexp.des.intra.rs.gov.br", + "siteexp.hml.rs.gov.br", + "expointer.rs.gov.br", + "www.expointer.rs.gov.br", + "sitedigx.des.intra.rs.gov.br", + "sitedigx01.hml.rs.gov.br", + "sitedigx03.rs.gov.br", + "conversasdigitais.rs.gov.br", + "www.conversasdigitais.rs.gov.br"]; + +function normalizeEscapedHtml(input = '') { + if (typeof input !== 'string') return input; + + const entityMap = { + '<': '<', + '>': '>', + '&': '&', + '"': '"', + ''': "'", + ''': "'", + '/': '/', + '/': '/', + ' ': ' ', + }; + + const entityRegex = /&(lt|gt|amp|quot|#39|apos|#x2F|#47|nbsp);/g; + + let output = input; + let previous; + + // Reaplica até estabilizar, para corrigir casos duplamente escapados. + do { + previous = output; + output = output.replace(entityRegex, (match) => entityMap[match] ?? match); + } while (output !== previous && entityRegex.test(output)); + + return output; +} + +function escapeHtml(value = '') { + return String(value) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} + +function sanitizeUrl(url = '') { + const value = normalizeEscapedHtml(String(url).trim()); + + try { + const parsed = new URL(value, window.location.href); + const allowedProtocols = ['http:', 'https:', 'mailto:', 'tel:']; + return allowedProtocols.includes(parsed.protocol) ? parsed.href : '#'; + } catch { + return '#'; + } +} + +const LOGO_SVG = normalizeEscapedHtml(` + +`); + +const GURIA_SVG = normalizeEscapedHtml(` + +`); - var STYLE_ID = 'barra-estado-standalone-style' - var MOUNT_ATTR = 'data-barra-estado-mounted' - var HOST_ATTR = 'data-barra-estado-host' - var toggleSequence = 0 +const DEFAULT_LINKS = [ + { href: 'https://estado.rs.gov.br/agencia-de-noticias', label: 'Notícias', srPrefix: 'Estado ' }, + { href: 'https://www.rs.gov.br/', label: 'Serviços', srPrefix: 'Estado ' }, + { href: 'https://www.centraldocidadao.rs.gov.br/', label: 'Central do Cidadão', srPrefix: 'Estado ' }, + { href: 'http://www.transparencia.rs.gov.br/', label: 'Transparência', srPrefix: 'Estado ' }, + { href: 'https://estado.rs.gov.br/institucional', label: 'Secretarias e Órgãos', srPrefix: 'Estado ' }, + { href: 'https://www.diariooficial.rs.gov.br/', label: 'Diário Oficial', srPrefix: 'Estado ' }, + { href: 'https://www.rs.gov.br/guria', label: 'GurIA', srPrefix: 'Estado ', svgHtml: GURIA_SVG }, +]; + +const CSS_TEXT = normalizeEscapedHtml(` +@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); - var STYLE_TEXT = ` :host { - display: block; - width: 100%; - - // --barra-estado-background: transparent; - --barra-estado-background: #4f4f4f; - --barra-estado-menu-background: #f8f8f8; - --barra-estado-hover-color: #000000; - --barra-estado-active-color: #e4e4e4; - --barra-estado-font-size: 12px; - --barra-estado-font-size-desktop: var(--barra-estado-font-size, 12px); --barra-estado-height: 32px; - --barra-estado-link-padding: 13px 40px; - --barra-estado-link-padding-desktop: 9px 13px; - --barra-estado-guria-link-padding: 7px 13px; - --barra-estado-highlight-color: var(--green-matriz-link-activated, #135428); - --barra-estado-toggle-color: #bcbcbb; - --barra-estado-toggle-hover-color: #fff; + --barra-estado-bg: #4f4f4f; + --barra-estado-menu-bg: #737474; + --barra-estado-text: #e4e4e4; + --barra-estado-text-hover: #ffffff; + --barra-estado-alt-text: #bcbcbb; + --barra-estado-logo-fill: #f4f4f1; + --barra-estado-container-max-768: 750px; + --barra-estado-container-max-992: 970px; + --barra-estado-container-max-1200: 1170px; + display: block; + font-family: Roboto, Arial, sans-serif; + -webkit-animation: bugfix infinite 1s; + animation: bugfix infinite 1s; } -#rs-gov { - color: var(--green-matriz-link, #1a7235); - vertical-align: initial; +*, *::before, *::after { + box-sizing: border-box; } -input.barra-estado__checkbox, -.barra-estado__toggle { - display: none; +@keyframes bugfix { + from, to { padding: 0; } +} + +.sr-only { + position: absolute; + inline-size: 1px; + block-size: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; } .barra-estado { - background: var(--barra-estado-background); - min-height: var(--barra-estado-height); + block-size: var(--barra-estado-height); + background-color: var(--barra-estado-bg); } .barra-estado__container { - min-height: var(--barra-estado-height); + position: relative; + inline-size: 100%; + block-size: 100%; + margin-inline: auto; + padding-inline: 15px; } -.barra-estado__menu { - background: var(--barra-estado-menu-background); +.barra-estado__container a { + text-decoration: none; } -.barra-estado__menu > li { - float: left; - list-style: none; +.barra-estado__logo { + position: absolute; + inset-inline-start: 15px; + inset-block-start: 8px; + inline-size: 77px; + block-size: 16px; + display: inline-flex; + align-items: center; } -.barra-estado__nav { + +.barra-estado__logo svg { display: block; - float: right; + inline-size: 77px; + block-size: 16px; +} + +.barra-estado__logo svg path { + fill: var(--barra-estado-logo-fill); } -.barra-estado__menu, -.barra-estado__menu > li, -.barra-estado__menu > li > a, .barra-estado__nav { - height: 100%; + display: block; + float: right; + block-size: 100%; } .barra-estado__nav__form { - display: inline-block; + margin: 0; padding: 0; + display: inline-flex; + align-items: stretch; + block-size: 100%; +} + +#barra-estado__toggle, +.barra-estado__toggle { + display: none; +} + +.barra-estado__menu { margin: 0; - min-height: var(--barra-estado-height); + padding: 0; + block-size: 100%; + display: flex; + align-items: stretch; + background: var(--barra-estado-menu-bg); + border-block-start: 1px solid #fff; + text-transform: uppercase; + list-style: none; +} + +.barra-estado__menu > li { + display: flex; + align-items: stretch; } .barra-estado__menu > li > a { - display: block; - box-sizing: border-box; - padding: var(--barra-estado-link-padding); - color: var(--green-matriz-link, #1a7235); - font-size: var(--barra-estado-font-size); + display: flex; + align-items: center; + padding: 0 13px; + color: var(--barra-estado-text); + font-size: 12px; font-weight: 700; line-height: 1; - transition: box-shadow 0.25s linear, color 0.25s linear; + white-space: nowrap; + transition: box-shadow .25s linear, color .25s linear; } -.barra-estado__menu > li > a:hover > svg > path, -.barra-estado__menu > li > a:focus > svg > path { - fill: var(--barra-estado-hover-color); + +.barra-estado__menu > li > a:visited, +.barra-estado__menu > li > a:active { + color: var(--barra-estado-text) !important; } -.barra-estado__menu > li > a:focus, -.barra-estado__menu > li > a:hover { - box-shadow: inset 5px 0 var(--barra-estado-highlight-color); - color: var(--barra-estado-hover-color); +.barra-estado__menu > li > a:hover, +.barra-estado__menu > li > a:focus-visible { + box-shadow: inset 5px 0 #fff; + color: var(--barra-estado-text-hover); + outline: none; } -.barra-estado__menu > li > a:active { - color: var(--barra-estado-active-color) !important; +.barra-estado__menu > li > a svg { + display: inline-block; + vertical-align: middle; + block-size: auto; + max-block-size: 14px; } -.barra-estado__menu, -.barra-estado__menu > li, -.barra-estado__menu > li > a { - height: auto; +.barra-estado__menu > li > a svg#GurIA { + transform: translateY(-2px); } .barra-estado__toggle { z-index: 2; } -.barra-estado__toggle:after { - color: var(--barra-estado-toggle-color); +.barra-estado__toggle::after { content: attr(data-open); - transition: all 0.5s linear; -} - -.barra-estado__toggle:hover:after { - color: var(--barra-estado-toggle-hover-color); + position: absolute; + inset-inline-end: 0; + inset-block-start: 0; + display: flex; + align-items: center; + justify-content: flex-end; + inline-size: 45px; + block-size: 32px; + padding-inline-end: 4px; + color: var(--barra-estado-alt-text); + font-size: 18px; + line-height: 1; + transition: color .5s linear; } -.barra-estado__toggle:focus-visible { - outline: 2px solid var(--govrs-color-focus, #ffcd07); - outline-offset: 2px; +.barra-estado__toggle:hover::after, +.barra-estado__toggle:focus-visible::after { + color: #fff; } -input.barra-estado__checkbox:checked + label.barra-estado__toggle:after { +#barra-estado__toggle:checked + .barra-estado__toggle::after { content: attr(data-close); } -@media only screen and (min-width: 992px) { +@media only screen and (max-width: 991.98px) { .barra-estado__menu { - padding: 0; - border-top: none; - margin-top: 0; - background: var(--barra-estado-menu-background); + position: absolute; + inset-inline-end: 0; + inset-block-start: 32px; + z-index: 999; + display: none; + flex-direction: column; + align-items: stretch; + inline-size: 280px; + block-size: auto; + padding-block: 4px; + opacity: 0; + background: var(--barra-estado-menu-bg); + border-block-start: 1px solid #fff; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); + } + + .barra-estado__menu > li { + display: block; + inline-size: 100%; + block-size: auto; + margin: 0; } .barra-estado__menu > li > a { - padding: var(--barra-estado-link-padding-desktop); - font-size: var(--barra-estado-font-size-desktop); + inline-size: 100%; + block-size: auto; + padding: 14px 20px; } - .barra-estado__menu > li > a:focus, - .barra-estado__menu > li > a:hover { - box-shadow: inset 0 2px var(--barra-estado-highlight-color); - color: var(--barra-estado-hover-color); + .barra-estado__toggle { + position: relative; + display: block; + inline-size: 45px; + block-size: 32px; + cursor: pointer; + user-select: none; + -webkit-touch-callout: none; } -} -.barra-estado__menu > li > a.barra-estado__guria-link { - padding: var(--barra-estado-guria-link-padding); + #barra-estado__toggle:checked ~ .barra-estado__menu { + display: flex; + opacity: 1; + } } -.visually-hidden { - position: absolute !important; - overflow: hidden !important; - width: 1px !important; - height: 1px !important; - padding: 0 !important; - border: 0 !important; - margin: -1px !important; - clip: rect(0, 0, 0, 0) !important; - white-space: nowrap !important; +@media (min-width: 768px) { + .barra-estado__container { + max-inline-size: var(--barra-estado-container-max-768); + } } -:host-context(.high-contrast) .barra-estado { - border-bottom: 1px solid var(--govrs-color-contrast-foreground, #ffffff) !important; - background-color: var(--govrs-color-contrast-background, #000000) !important; -} +@media (min-width: 992px) { + .barra-estado__container { + max-inline-size: var(--barra-estado-container-max-992); + } -:host-context(.high-contrast) .barra-estado__menu { - background-color: var(--govrs-color-contrast-background, #000000) !important; -} + .barra-estado__menu { + background: transparent; + border-block-start: none; + } -:host-context(.high-contrast) .barra-estado__menu > li > a > #GurIA path { - fill: var(--govrs-color-contrast-foreground, #ffffff) !important; -} + .barra-estado__menu > li > a { + font-size: 11px; + } -:host-context(.high-contrast) .barra-estado__menu > li > a:focus { - box-shadow: inset 0 5px var(--govrs-color-contrast-foreground, #ffffff) !important; - color: var(--govrs-color-contrast-foreground, #ffffff) !important; + .barra-estado__menu > li > a:hover, + .barra-estado__menu > li > a:focus-visible { + box-shadow: inset 0 2px #fff; + color: var(--barra-estado-text-hover); + } } -:host-context(.high-contrast) .barra-estado__menu > li > a:hover { - box-shadow: inset 0 5px var(--govrs-color-contrast-foreground, #ffffff) !important; - color: var(--govrs-color-contrast-foreground, #ffffff) !important; +@media (min-width: 1200px) { + .barra-estado__container { + max-inline-size: var(--barra-estado-container-max-1200); + } } +`); + +function createMenuHtml(links) { + const items = links.map((item) => { + const target = item.target === '_blank' ? '_blank' : '_self'; + const rel = target === '_blank' ? ' rel="noopener noreferrer"' : ''; + + const href = sanitizeUrl(item.href); + const label = escapeHtml(normalizeEscapedHtml(item.label || '')); + const srPrefix = escapeHtml(normalizeEscapedHtml(item.srPrefix || '')); + + + if (typeof item.svgHtml === 'string' && item.svgHtml.trim()) { + const svg = normalizeEscapedHtml(item.svgHtml); + return ` +