Rewrites the options page for first-time users without removing any setting. Customization in a lightweight package is what sets this extension apart. Design: `docs/superpowers/specs/2026-10-18-options-page-for-first-time-users-design.md`. **User-visible changes** - **Layout:** the description stays as the first line, followed by a **Usage instructions** section and the **Settings** section. Each section has a heading and a divider. - **Usage instructions:** one labelled line per way to open ChatGPT, each with a small drawing: - **Address bar:** `<Ctrl>+L`, then `gpt`, a space and the question. The drawing shows a ChatGPT label because the address-bar code shipped in Firefox 157.0.1 enters search mode when an engine keyword is followed by a space. I checked that in its `omni.ja`, but it still needs confirming on screen; see the checks below. - **Right-click:** a drawing of the menu with Ask ChatGPT highlighted. - **Keyboard:** key caps for the user's actual shortcut, held down. The line is hidden when no shortcut is set. - **Toolbar:** the hovered button with the pointer, its tooltip, the puzzle-piece Extensions button, and a selected heading. - **Drawings:** they are HTML/CSS and inline SVG, not screenshots, so they follow light and dark themes, stay sharp, and never go stale. They are centred. The package grows from 52.8 KB to 56.5 KB. - **Settings:** - **Right-click menu** (was "Context menu") and **Open ChatGPT in** stay visible. - Choosing **Advanced** reveals a drawing of the Ask ChatGPT submenu (Ask normally, Explain, Summarize, Debug code). It lives in the block that only shows for Advanced, so it needs no script. - Prompt template, temporary chat and web search move under **More options**, whose heading names them. It opens by itself on load, or when a sync changes one of them, if one of them isn't at its default. - **Restore defaults** is right-aligned and red. - **Bottom of the page:** - The keyword/default-engine and keyboard-shortcut notes become collapsed sections with numbered steps. - The project links are centred, and stack on narrow panels. - **Hotkeys:** written as `<Ctrl>+L` and `<Alt>+<Shift>+G`, including the user's actual shortcut. Mac users see `<Cmd>`, `<Option>` and `<Return>`, detected with `runtime.getPlatformInfo`, which needs no permission. - **Docs:** - Keyword wording is corrected in the options page and README: Firefox adds a custom keyword alongside `gpt` instead of replacing it. - README and AGENTS.md use the new setting names. - AGENTS.md records the keep-every-setting rule, the hotkey format and the "filled in, never sent" copy rule. These still match the original options design spec: the temporary-chat and web-search wording, and the rule that copy never says the question is sent. No permission, search URL, privacy or packaging changes. **Checks** - `npm test`: lint 0 errors / 0 warnings, 61/61 unit tests, build OK. - New tests: - the key formatter, including the Mac names Firefox stores (Command, MacCtrl, Alt) - the page's written hotkeys match the formatter - the keyboard drawing's key caps follow the live shortcut - Rendered in headless Firefox 157 with the extension APIs stubbed: - light and dark themes - 680 px and 360 px wide - Mac key names - More options opening for a customised prompt template - both bottom sections expanded **Manual Firefox checks (`npm run dev` → about:addons → Preferences)** - [x] Typing `gpt` and a space shows a ChatGPT label in the address bar, as drawn. If it doesn't, the drawing drops the label and shows plain `gpt how do magnets work?` - [x] Light and dark themes, and a narrow about:addons width - [x] Expanding More options and the two bottom sections grows the inline panel without clipping or scrolling - [x] The Keyboard line and its key caps disappear when the shortcut is removed, and come back showing the new keys when one is set - [x] More options opens by itself after changing the prompt template and reopening the page - [x] Choosing Advanced shows the submenu drawing; Simple and Off hide it - [x] Settings still save, and Restore defaults still works 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: https://git.zavage.net/Zavage-Software/search-with-chatgpt-powered-by-openai-extension/pulls/23 Co-authored-by: golem <golem@zavage.net>
515 lines
9.2 KiB
CSS
515 lines
9.2 KiB
CSS
:root {
|
|
--fg: #15141a;
|
|
--fg-dim: #38383d;
|
|
--bg: #ffffff;
|
|
--border: #8f8f9d;
|
|
--field-bg: #ffffff;
|
|
--accent: #0060df;
|
|
/* Backdrop for the drawings and inline code. */
|
|
--surface: #f0f0f4;
|
|
--tooltip-bg: #15141a;
|
|
--tooltip-fg: #fbfbfe;
|
|
--danger: #d70022;
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--fg: #fbfbfe;
|
|
--fg-dim: #e0e0e6;
|
|
--bg: #23222b;
|
|
--border: #8f8f9d;
|
|
--field-bg: #2b2a33;
|
|
--accent: #0df;
|
|
--surface: #1c1b22;
|
|
--tooltip-bg: #52525e;
|
|
--tooltip-fg: #fbfbfe;
|
|
--danger: #ff848b;
|
|
}
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
padding: 0.5rem 0;
|
|
color: var(--fg);
|
|
background: var(--bg);
|
|
font: message-box;
|
|
font-size: 1rem;
|
|
line-height: 1.4;
|
|
max-width: 42rem;
|
|
}
|
|
|
|
.intro {
|
|
margin: 0 0 0.75rem;
|
|
}
|
|
|
|
.ways {
|
|
margin: 0 0 0.75rem;
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
|
|
.ways > li {
|
|
margin-bottom: 0.9rem;
|
|
}
|
|
|
|
.inline-icon {
|
|
width: 16px;
|
|
height: 16px;
|
|
vertical-align: -3px;
|
|
}
|
|
|
|
/* Simplified drawings of Firefox's address bar and right-click menu. They are
|
|
not screenshots, so they follow the theme and never go out of date. */
|
|
.drawing {
|
|
max-width: 24rem;
|
|
margin: 0.45rem auto 0;
|
|
padding: 0.75rem;
|
|
border-radius: 8px;
|
|
background: var(--surface);
|
|
font-size: 0.85rem;
|
|
user-select: none;
|
|
}
|
|
|
|
.drawing img {
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
|
|
.drawing-urlbar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.45rem;
|
|
padding: 0.35rem 0.5rem;
|
|
border-radius: 6px;
|
|
background: var(--field-bg);
|
|
outline: 2px solid var(--accent);
|
|
}
|
|
|
|
.drawing-chip {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.3rem;
|
|
padding: 0.1rem 0.45rem;
|
|
border-radius: 4px;
|
|
background: color-mix(in srgb, var(--fg) 10%, var(--field-bg));
|
|
font-weight: 600;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.drawing-typed {
|
|
min-width: 0;
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
/* The text cursor. */
|
|
.drawing-typed::after {
|
|
content: "";
|
|
display: inline-block;
|
|
width: 1px;
|
|
height: 1.1em;
|
|
margin-inline-start: 1px;
|
|
background: currentColor;
|
|
vertical-align: text-bottom;
|
|
}
|
|
|
|
.drawing-page {
|
|
margin: 0 0 0.3rem;
|
|
}
|
|
|
|
.drawing mark {
|
|
color: inherit;
|
|
background: color-mix(in srgb, var(--accent) 30%, transparent);
|
|
}
|
|
|
|
.drawing-toolbar {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.35rem;
|
|
}
|
|
|
|
.drawing-address {
|
|
flex: 1;
|
|
min-width: 0;
|
|
padding: 0.3rem 0.6rem;
|
|
border-radius: 6px;
|
|
background: var(--field-bg);
|
|
color: var(--fg-dim);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.drawing-button {
|
|
position: relative;
|
|
display: inline-flex;
|
|
flex: none;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 28px;
|
|
height: 28px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.drawing-button svg {
|
|
width: 16px;
|
|
height: 16px;
|
|
fill: none;
|
|
stroke: currentColor;
|
|
stroke-width: 1.3;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
}
|
|
|
|
.drawing-button-hover {
|
|
background: color-mix(in srgb, var(--fg) 14%, transparent);
|
|
}
|
|
|
|
/* The mouse pointer resting on the hovered button. */
|
|
.drawing-button svg.drawing-pointer {
|
|
position: absolute;
|
|
top: 16px;
|
|
left: 17px;
|
|
width: 12px;
|
|
height: 18px;
|
|
fill: #fff;
|
|
stroke: #000;
|
|
stroke-width: 1;
|
|
}
|
|
|
|
.drawing-tooltip {
|
|
position: absolute;
|
|
top: calc(100% + 0.65rem);
|
|
right: 0;
|
|
padding: 0.2rem 0.5rem;
|
|
border-radius: 4px;
|
|
background: var(--tooltip-bg);
|
|
color: var(--tooltip-fg);
|
|
white-space: nowrap;
|
|
box-shadow: 0 1px 4px rgb(0 0 0 / 0.3);
|
|
}
|
|
|
|
/* Top padding keeps the heading clear of the tooltip at narrow widths. */
|
|
.drawing-content {
|
|
margin: 0.6rem 0 0;
|
|
padding: 1.9rem 0.75rem 1rem;
|
|
border-radius: 6px;
|
|
background: var(--field-bg);
|
|
font-size: 1.05rem;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.drawing-menu {
|
|
width: 11rem;
|
|
/* Opens at the pointer, just under the selection. */
|
|
margin-inline-start: 3.5rem;
|
|
padding: 0.25rem 0;
|
|
border: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
|
|
border-radius: 6px;
|
|
background: var(--field-bg);
|
|
box-shadow: 0 2px 8px rgb(0 0 0 / 0.2);
|
|
}
|
|
|
|
.drawing-menu > div {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.45rem;
|
|
/* Line the plain items up with the text of the item that has an icon. */
|
|
padding: 0.2rem 0.75rem 0.2rem calc(0.75rem + 16px + 0.45rem);
|
|
}
|
|
|
|
.drawing-menu > .drawing-menu-active {
|
|
padding-inline-start: 0.75rem;
|
|
background: color-mix(in srgb, var(--accent) 20%, var(--field-bg));
|
|
}
|
|
|
|
.drawing-menu hr {
|
|
margin: 0.25rem 0;
|
|
border: 0;
|
|
border-top: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
|
|
}
|
|
|
|
/* The Advanced submenu, open beside the highlighted Ask ChatGPT item. */
|
|
.drawing-advanced {
|
|
margin-bottom: 1.15rem;
|
|
}
|
|
|
|
.drawing-menus {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: center;
|
|
}
|
|
|
|
.drawing-menus > .drawing-menu {
|
|
flex: none;
|
|
width: 10rem;
|
|
margin-inline-start: 0;
|
|
}
|
|
|
|
.drawing-menus > .drawing-submenu {
|
|
width: 8.5rem;
|
|
/* Lines its first item up with Ask ChatGPT, overlapping the menu edge. */
|
|
margin-top: 3.75rem;
|
|
margin-inline-start: -0.3rem;
|
|
}
|
|
|
|
/* Submenu items have no icon, so the highlighted one keeps the icon gap. */
|
|
.drawing-submenu > .drawing-menu-active {
|
|
padding-inline-start: calc(0.75rem + 16px + 0.45rem);
|
|
}
|
|
|
|
.drawing-submenu-arrow {
|
|
margin-inline-start: auto;
|
|
font-size: 1.2em;
|
|
line-height: 1;
|
|
}
|
|
|
|
/* The shortcut's keys, held down. shortcut.js fills these in. */
|
|
.drawing-keycaps {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
padding: 0.3rem 0;
|
|
color: var(--fg-dim);
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.drawing-key {
|
|
min-width: 1.4rem;
|
|
padding: 0.35rem 0.65rem;
|
|
border: 1px solid color-mix(in srgb, var(--accent) 55%, var(--border));
|
|
border-bottom-width: 3px;
|
|
border-radius: 6px;
|
|
background: color-mix(in srgb, var(--accent) 12%, var(--field-bg));
|
|
color: var(--fg);
|
|
text-align: center;
|
|
transform: translateY(1px);
|
|
}
|
|
|
|
.hint.intro-hint {
|
|
margin: 0;
|
|
}
|
|
|
|
.usage,
|
|
.settings {
|
|
margin-top: 1.5rem;
|
|
padding-top: 1rem;
|
|
border-top: 1px solid var(--border);
|
|
}
|
|
|
|
.hint.settings-scope {
|
|
margin: 0 0 1rem;
|
|
}
|
|
|
|
.field {
|
|
margin-bottom: 1.15rem;
|
|
}
|
|
|
|
label {
|
|
display: block;
|
|
font-weight: 600;
|
|
margin-bottom: 0.3rem;
|
|
}
|
|
|
|
.checkbox label {
|
|
font-weight: 400;
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 0.45rem;
|
|
}
|
|
|
|
input[type="text"],
|
|
select {
|
|
width: 100%;
|
|
max-width: 100%;
|
|
box-sizing: border-box;
|
|
padding: 0.4rem 0.5rem;
|
|
color: var(--fg);
|
|
background: var(--field-bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 4px;
|
|
font: inherit;
|
|
}
|
|
|
|
input[type="text"]:focus-visible,
|
|
select:focus-visible,
|
|
button:focus-visible,
|
|
summary:focus-visible {
|
|
outline: 2px solid var(--accent);
|
|
outline-offset: 1px;
|
|
}
|
|
|
|
.hint {
|
|
margin: 0.3rem 0 0;
|
|
color: var(--fg-dim);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
summary {
|
|
cursor: pointer;
|
|
font-weight: 600;
|
|
color: var(--fg);
|
|
}
|
|
|
|
details[open] > summary {
|
|
margin-bottom: 0.75rem;
|
|
}
|
|
|
|
.more-options {
|
|
margin-bottom: 1.15rem;
|
|
}
|
|
|
|
.summary-detail {
|
|
font-weight: 400;
|
|
color: var(--fg-dim);
|
|
}
|
|
|
|
/* Reversed so the button stays at the right edge and "Saved" appears beside
|
|
it without moving it. */
|
|
.actions {
|
|
display: flex;
|
|
flex-direction: row-reverse;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
flex-wrap: wrap;
|
|
margin-top: 1.5rem;
|
|
}
|
|
|
|
button {
|
|
padding: 0.35rem 0.8rem;
|
|
color: var(--fg);
|
|
background: var(--field-bg);
|
|
border: 1px solid var(--border);
|
|
border-radius: 4px;
|
|
font: inherit;
|
|
cursor: pointer;
|
|
}
|
|
|
|
/* Restore defaults discards every customised setting at once. */
|
|
button.danger {
|
|
color: var(--danger);
|
|
border-color: var(--danger);
|
|
}
|
|
|
|
button.danger:hover {
|
|
color: var(--bg);
|
|
background: var(--danger);
|
|
}
|
|
|
|
#status {
|
|
color: var(--fg-dim);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.note {
|
|
margin-top: 1.25rem;
|
|
padding-top: 1rem;
|
|
border-top: 1px solid var(--border);
|
|
color: var(--fg-dim);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.note summary {
|
|
font-size: 1rem;
|
|
}
|
|
|
|
code {
|
|
padding: 0 0.25em;
|
|
border-radius: 3px;
|
|
background: var(--surface);
|
|
font-family: monospace;
|
|
font-size: 0.9em;
|
|
}
|
|
|
|
/* Written as <Ctrl>+L, so the keys read as words rather than code. */
|
|
kbd {
|
|
font: inherit;
|
|
font-weight: 600;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.usage h2,
|
|
.settings h2 {
|
|
margin: 0 0 0.5rem;
|
|
color: var(--fg);
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.note p,
|
|
.note ol {
|
|
margin: 0 0 0.75rem;
|
|
}
|
|
|
|
.note ol {
|
|
padding-inline-start: 1.25rem;
|
|
}
|
|
|
|
.note li {
|
|
margin-bottom: 0.3rem;
|
|
}
|
|
|
|
.note code {
|
|
overflow-wrap: anywhere;
|
|
}
|
|
|
|
.project-links {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
gap: 0.5rem 0.65rem;
|
|
margin-top: 1.5rem;
|
|
}
|
|
|
|
.project-link {
|
|
display: inline-flex;
|
|
align-items: baseline;
|
|
gap: 0.65rem;
|
|
}
|
|
|
|
.link-separator {
|
|
color: var(--fg-dim);
|
|
}
|
|
|
|
a {
|
|
color: var(--accent);
|
|
text-decoration: underline;
|
|
}
|
|
|
|
a:focus-visible {
|
|
outline: 2px solid var(--accent);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
/* The inline about:addons surface can be very narrow. */
|
|
@media (max-width: 26rem) {
|
|
.actions {
|
|
align-items: flex-end;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.drawing-menu {
|
|
margin-inline-start: 1rem;
|
|
}
|
|
|
|
/* Stack the links rather than wrap one onto a line that starts with "|". */
|
|
.project-links {
|
|
flex-direction: column;
|
|
align-items: center;
|
|
}
|
|
|
|
.link-separator {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
[hidden] { display: none !important; }
|
|
.dependent-settings {
|
|
border-inline-start: 2px solid var(--border);
|
|
padding-inline-start: 1rem;
|
|
margin-bottom: 1.15rem;
|
|
}
|