diff --git a/pages/css/common.css b/pages/css/common.css index de3cd34..443ee18 100644 --- a/pages/css/common.css +++ b/pages/css/common.css @@ -2,29 +2,43 @@ html, body { font-family: sans; margin: 0; padding: 0; -} -.popup { --step: 8px; - --color-bg: #ffffff; - --color-text: #333333; - --color-accent: #888888; + /* @see https://acorn.firefox.com/latest/styles/color-MZHBVuZc#section-gray-c2 */ + --gray-light-05: #fbfbfe; + --gray-light-10: #f9f9fb; + --gray-light-20: #f0f0f4; + --gray-light-30: #e0e0e6; + --gray-light-40: #cfcfd8; + --gray-light-50: #bfbfc9; + + --gray-dark-05: #5b5b66; + --gray-dark-10: #52525e; + --gray-dark-30: #42414d; + --gray-dark-40: #3a3944; + --gray-dark-60: #2b2a33; + --gray-dark-80: #1c1b22; + --gray-dark-90: #15141a; +} + +body { + --color-bg: var(--gray-light-10); + --color-text: var(--gray-dark-80); } @media (prefers-color-scheme: dark) { - .popup { - --color-bg: #1c1c1c; - --color-text: #eeeeee; - --color-accent: #cccccc; + body { + --color-bg: var(--gray-dark-60); + --color-text: var(--gray-light-40); } } -/* Controls */ +/* Common */ -*:focus-visible { - outline-color: var(--color-accent); - outline-offset: 4px; - outline-style: solid; - outline-width: 1px; +body { + font-size: calc(2 * var(--step)); + + background-color: var(--color-bg); + color: var(--color-text); } diff --git a/pages/search/modules/labels.js b/pages/search/modules/labels.js new file mode 100644 index 0000000..398f313 --- /dev/null +++ b/pages/search/modules/labels.js @@ -0,0 +1,36 @@ +const labels = { + /* tabId: label, */ +} + +const lettersOrder = 'lkjhyuionm' + +const digits2label = (digits) => [...digits] + .map((digit) => lettersOrder[digit]) + .join('') + +const label2digits = (label) => [...label] + .map((letter) => [...lettersOrder].findIndex((x) => x === letter)) + .join('') + +/* */ + +export const id2label = (id, tabs) => { + if (!labels[id]) { + const label = Object.keys(labels).length + labels[id] = String(label) + } + + const keyLength = String(tabs?.length).length + const digits = String(labels[id]).padStart(keyLength, 0) + return digits2label(digits) +} + +export const label2id = (label) => { + const paddedDigits = label2digits(label) + const digits = String(parseInt(paddedDigits)) + + const [key] = Object.entries(labels) + .find(([_, value]) => value === digits) + + return parseInt(key) +} diff --git a/pages/search/modules/store.js b/pages/search/modules/store.js new file mode 100644 index 0000000..4ce5762 --- /dev/null +++ b/pages/search/modules/store.js @@ -0,0 +1,58 @@ +import * as labels from './labels.js' + +export const init = ({ + tabs: browserTabs, + onStateUpdate, +}) => { + /* Initial state */ + const state = { + tabs: [], + } + + /* */ + + const shapeTabs = (tabs) => tabs + .map((tab) => ({ + label: labels.id2label(tab.id, tabs), + ...tab, + })) + .map((tab) => [ + 'favIconUrl', + 'id', + 'label', + 'title', + 'url', + ].reduce((acc, x) => (acc[x] = tab[x], acc), {})) + + const fetchTabs = () => + browserTabs.query({ currentWindow: true, active: false }) + .then(shapeTabs) + .then((tabs) => tabs.reverse()) + .then((tabs) => void (state.tabs = tabs)) + + /* */ + + const updateState = () => + fetchTabs() + .then(() => onStateUpdate(state)) + + updateState() + + /* */ + + return { + getCurrentState() { + return state + }, + actions: { + goToTab(id) { + browserTabs.update(id, { active: true }) + .then(updateState) + }, + closeTab(id) { + browserTabs.remove(id) + .then(updateState) + }, + }, + } +} diff --git a/pages/search/search.css b/pages/search/search.css index aa1634c..484a026 100644 --- a/pages/search/search.css +++ b/pages/search/search.css @@ -1,3 +1,63 @@ -body { - background-color: red; +header { + display: flex; + padding: calc(2 * var(--step)); + gap: calc(2 * var(--step)); +} + +header > input { + border: 0; + border-bottom: 2px solid var(--gray-light-30); + padding: var(--step); + flex: 1 1 auto; + font: inherit; + background: inherit; +} + +header > input#searchbox { + flex-grow: 2; +} + +header > input:focus-visible { + outline: none; + border-bottom: 2px solid var(--color-text); +} + +main { + padding: calc(2 * var(--step)); + display: flex; + flex-direction: column; +} + +.tab { + appearance: none; + text-align: unset; + + background: inherit; + font: inherit; + border: inherit; + + width: auto; + + display: flex; + padding: calc(1 * var(--step)); + gap: calc(2 * var(--step)); + + overflow: hidden; +} + +.tab .label { + font-family: monospace; + color: var(--gray-dark-05); + flex-shrink: 0; +} + +.tab > .title, +.tab > .url { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tab .url { + color: var(--gray-dark-05); } diff --git a/pages/search/search.html b/pages/search/search.html index 96a9107..fc3b8f0 100644 --- a/pages/search/search.html +++ b/pages/search/search.html @@ -2,13 +2,36 @@ - Tabswhither + Tabswitcher - - lorem +
+ + +
+
+ + +
+ diff --git a/pages/search/search.js b/pages/search/search.js new file mode 100644 index 0000000..e24dbc8 --- /dev/null +++ b/pages/search/search.js @@ -0,0 +1,10 @@ +import * as Store from './modules/store.js' + +console.log('1234') + +const store = Store.init({ + tabs: browser.tabs, + onStateUpdate: console.log, +}) + +console.log(store.getCurrentState())