diff --git a/popup/css/popup.css b/popup/css/popup.css index ce278fa..88c365c 100644 --- a/popup/css/popup.css +++ b/popup/css/popup.css @@ -6,8 +6,10 @@ html, body { .popup { --color-bg: #eeeeee; + --color-bg: #ffffff; --color-text: #333333; --color-accent: #666666; + --color-accent: #777777; --step: 8px; } @@ -32,26 +34,15 @@ html, body { /* Button */ button { - background: var(--color-bg); - + border: none; border-radius: 0; - border: 1px solid var(--color-text); - + background: var(--color-bg); color: var(--color-text); - cursor: pointer; font: inherit; - - padding: var(--step); } button:active { border-color: var(--color-accent); color: var(--color-accent); } - -/* Link */ - -a { - color: var(--color-accent); -} diff --git a/popup/tabswiper/tabswiper.css b/popup/tabswiper/tabswiper.css index a9deb68..3907296 100644 --- a/popup/tabswiper/tabswiper.css +++ b/popup/tabswiper/tabswiper.css @@ -3,50 +3,62 @@ border: 1px solid var(--color-accent); color: var(--color-text); width: 640px; + padding: calc(2 * var(--step)); } /* Header */ .tabswiper header { - padding: var(--step); - border-block-end: 1px solid var(--color-accent); + padding-block-end: calc(2 * var(--step)); + /* border-block-end: 1px solid var(--color-accent); */ display: flex; flex-direction: row; justify-content: space-between; - aligh-items: center; + align-items: center; +} + +.tabswiper .favicon { + width: calc(3 * var(--step)); + height: calc(3 * var(--step)); + margin-inline-end: calc(1 * var(--step)); +} + +.tabswiper .tabCounter { + display: flex; + align-items: center; +} + +.tabswiper .actions { + display: flex; + flex-direction: row; + gap: var(--step); } /* Current Tab */ .tabswiper .currentTab { - padding: calc(1 * var(--step)) var(--step); + /* padding-block-start: calc(2 * var(--step)); */ + /* padding-block-end: calc(3 * var(--step)); */ cursor: pointer; word-wrap: break-word; /* line-height: 1.5; */ } .tabswiper .currentTab .title { - /* font-size: 1.2em; */ + font-size: 1.25em; margin-block-end: calc(1 * var(--step)); - font-weight: bold; + /* font-weight: bold; */ } .tabswiper .currentTab .url { /* font-size: 0.8em; */ color: var(--color-accent); + text-decoration: none; } /* Footer */ -.tabswiper footer { - padding: var(--step); - border-block-start: 1px solid var(--color-accent); - - display: flex; - flex-direction: row; - gap: var(--step); -} .tabswiper footer .actionButton { flex: 1 1 auto; diff --git a/popup/tabswiper/tabswiper.html b/popup/tabswiper/tabswiper.html index 7367704..fed9269 100644 --- a/popup/tabswiper/tabswiper.html +++ b/popup/tabswiper/tabswiper.html @@ -12,16 +12,32 @@
- Tab 1 of 20 + Favicon + Tab  + 0 +  of  + 0 + +
+
+ +
- - Info -
+
Some title here @@ -34,22 +50,6 @@ https://some.url/here
-
diff --git a/popup/tabswiper/tabswiper.js b/popup/tabswiper/tabswiper.js index 28058a9..b293c3c 100644 --- a/popup/tabswiper/tabswiper.js +++ b/popup/tabswiper/tabswiper.js @@ -1,3 +1,6 @@ +/* https://png-pixel.com/ */ +const defaultFavicon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkqAcAAIUAgUW0RjgAAAAASUVORK5CYII=' + /* */ const state = { @@ -6,22 +9,28 @@ const state = { currentTab: null, } +const getCurrentState = () => state + +/* */ + const updateState = () => updateTabs() .then(updateCurrent) .then(updateInterface) const updateTabs = () => - browser.tabs.query({currentWindow: true}) + browser.tabs.query({ currentWindow: true }) .then((tabs) => tabs.reverse()) .then((tabs) => void (state.tabs = tabs)) const updateCurrent = () => { - const filteredTabs = state.tabs + const untouchedTabs = state.tabs .filter(({ id }) => state.skipped.includes(id) === false) - state.currentTab = filteredTabs[0] ?? null + state.currentTab = untouchedTabs[0] ?? null } +/* */ + const keepTab = (tab) => { state.skipped.push(tab.id) updateState() @@ -29,44 +38,86 @@ const keepTab = (tab) => { const goToTab = (tab) => { browser.tabs.update(tab.id, { active: true }) - updateState() + .then(updateState) } const closeTab = (tab) => { browser.tabs.remove(tab.id) - updateState() + .then(updateState) } /* */ -const setDOMListeners = () => { - const pairs = [ +const setDOMListeners = (getCurrentState) => { + /* UI controls with handlers. */ + + const controls = [ ['buttonClose', closeTab], ['buttonKeep', keepTab], ['linkTab', goToTab], ] - pairs.forEach(([elementId, handler]) => { + controls.forEach(([elementId, handler]) => { document.getElementById(elementId).addEventListener('click', (e) => { - console.log('Element:', elementId, 'Handler:', handler) e.preventDefault() - handler(state.currentTab) + handler(getCurrentState().currentTab) }) }) + + /* Keyboard handlers. */ + document.addEventListener('keydown', (e) => { + switch (e.key) { + case 'j': + case 'ArrowLeft': + closeTab(getCurrentState().currentTab) + return + case 'k': + case 'ArrowRight': + keepTab(getCurrentState().currentTab) + return + case 'f': + goToTab(getCurrentState().currentTab) + return + case 'r': + location.reload() + return + } + }) + + /* Replace unavalible favicon with default one. */ + document.getElementById('favicon').addEventListener('error', (e) => { + e.currentTarget.src = defaultFavicon + }) + + /* Close popup when tab switched. */ + browser.tabs.onActivated.addListener(() => { + window.close() + }) } const updateInterface = () => { - console.log(state) + /* Close popup if there ara no tabs. */ + if (state.tabs.length === 0) { + window.close() + return + } + /* Start over when all tabs skipped. */ if (state.currentTab === null) { location.reload() return } + /* Update UI. */ const items = [ + ['favicon', 'src', state.currentTab.favIconUrl ?? defaultFavicon], ['titleTab', 'textContent', state.currentTab.title], ['linkTab', 'textContent', state.currentTab.url], ['linkTab', 'href', state.currentTab.url], + ['tabTotalNumber', 'textContent', state.tabs.length], + ['tabNumber', 'textContent', state.tabs.length - state.tabs.findIndex(({ id }) => + id === state.currentTab.id + )], ] items.forEach(([elementId, property, value]) => { @@ -76,10 +127,12 @@ const updateInterface = () => { /* */ -const init = () => +// const state = initState({onUpdate: updateInterface}) +// setDomListeners(state) + +const init = () => { updateState() - .then(setDOMListeners) - // .then(setKeyboardListeners) - // .then(setBrowserListeners) + setDOMListeners(getCurrentState) +} init()