diff --git a/extensions/extension/README.md b/extensions/extension/README.md index 2abc6b3..61215a5 100644 --- a/extensions/extension/README.md +++ b/extensions/extension/README.md @@ -8,6 +8,13 @@ - **Сохранение кредов** — перехватывает введённые данные и предлагает сохранить их как секрет. - **Popup** — быстрый доступ к списку секретов, поиск, reveal и копирование полей. +Карточка автозаполнения рендерится в закрытом Shadow DOM на пустом host-элементе: +страница не может стилизовать её своим CSS, прочитать её содержимое (названия +секретов) через DOM или добраться до её кнопок через `querySelector`. Стили +карточки (`src/content.css`) отдаются как web_accessible_resource и +инжектируются текстом внутрь shadow root, а не в стилевые листы страницы; +вид повторяет gnexus-ui-kit 1.0. + ## Установка ### Chrome diff --git a/extensions/extension/manifest.json b/extensions/extension/manifest.json index 6c8f496..ff964ce 100644 --- a/extensions/extension/manifest.json +++ b/extensions/extension/manifest.json @@ -13,7 +13,6 @@ { "matches": [""], "js": ["src/content.js"], - "css": ["src/content.css"], "run_at": "document_idle" } ], @@ -34,6 +33,10 @@ }, "web_accessible_resources": [ { + "resources": ["src/content.css"], + "matches": [""] + }, + { "resources": ["lib/assets/fonts/*/*", "lib/assets/fonts/*/*/*"], "matches": [""] } diff --git a/extensions/extension/src/content.css b/extensions/extension/src/content.css index 5e28d67..e508290 100644 --- a/extensions/extension/src/content.css +++ b/extensions/extension/src/content.css @@ -1,3 +1,8 @@ +/* Card styles for the closed Shadow DOM root (content.js injects this file's + text into the shadow root; it is never added to the page stylesheet, so the + host page can neither restyle the card nor see our class names). + Palette and geometry mirror gnexus-ui-kit 1.0 — keep in sync with lib/. */ + .gnexus-creds-autofill-container { position: fixed; top: 16px; @@ -14,21 +19,21 @@ .gnexus-creds-autofill-card { pointer-events: auto; - background: #161b22; - border: 1px solid #30363d; - border-top: 2px solid #58a6ff; - color: #c9d1d9; + background: #16161e; + border: 2px solid rgba(192, 202, 245, 0.24); + border-left: 6px solid #7aa2f7; + color: #c0caf5; font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 14px; - border-radius: 0; - box-shadow: 0 6px 16px rgba(0,0,0,0.5); - padding: 16px 20px; + border-radius: 6px; + box-shadow: 0 14px 36px rgba(22, 22, 30, 0.36); + padding: 15px 18px; min-width: 300px; max-width: 460px; width: 100%; opacity: 0; transform: translateY(-12px); - transition: opacity 0.3s ease-out, transform 0.3s ease-out; + transition: opacity 0.28s ease, transform 0.28s ease; } .gnexus-creds-autofill-card-visible { @@ -43,17 +48,20 @@ } .gnexus-creds-autofill-title { - font-weight: 600; - color: #58a6ff; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.04em; + color: #7aa2f7; + line-height: 1.25; word-break: break-word; - margin-bottom: 14px; - font-size: 15px; + margin: 0 0 12px; + font-size: 14px; } .gnexus-creds-autofill-list { max-height: 200px; overflow-y: auto; - margin-bottom: 14px; + margin-bottom: 12px; } .gnexus-creds-autofill-row { @@ -61,8 +69,8 @@ align-items: center; justify-content: space-between; gap: 10px; - padding: 8px 0; - border-bottom: 1px solid #30363d; + padding: 10px 0; + border-bottom: 2px solid rgba(192, 202, 245, 0.08); } .gnexus-creds-autofill-row:last-child { @@ -71,7 +79,7 @@ .gnexus-creds-autofill-row-title { font-size: 13px; - color: #c9d1d9; + color: #c0caf5; word-break: break-word; } @@ -82,24 +90,27 @@ } .gnexus-creds-autofill-btn { - background: #238636; - border: none; - color: #fff; - padding: 7px 16px; - border-radius: 0; + background: #16161e; + border: 2px solid rgba(192, 202, 245, 0.24); + border-left: 6px solid #7aa2f7; + color: #7aa2f7; + padding: 8px 16px; + border-radius: 6px; font-family: inherit; font-size: 13px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; cursor: pointer; line-height: 1; flex-shrink: 0; } .gnexus-creds-autofill-btn-secondary { - background: transparent; - border: 1px solid #30363d; - color: #7d8590; + border-left-width: 2px; + color: #a9b1d6; } .gnexus-creds-autofill-btn:hover { opacity: 0.85; -} +} \ No newline at end of file diff --git a/extensions/extension/src/content.js b/extensions/extension/src/content.js index 9f428e7..b13c4d6 100644 --- a/extensions/extension/src/content.js +++ b/extensions/extension/src/content.js @@ -4,7 +4,9 @@ let secretsForDomain = []; let shownCards = new WeakSet(); -let autofillContainer = null; +let autofillHost = null; +let autofillShadow = null; +let cardStylesPromise = null; // --- Messaging helper --- @@ -110,13 +112,31 @@ } // --- Autofill card --- +// The card lives in a CLOSED shadow root on a bare host element, so the host +// page cannot restyle it (CSS does not cross the shadow boundary), read its +// content (secret titles) via the DOM, or reach its buttons through +// querySelector. Styles are fetched from our own web-accessible content.css +// and injected as a