mirror of
https://github.com/He4eT/tabswiper.git
synced 2026-05-04 16:47:23 +00:00
Prototype
This commit is contained in:
parent
9306068d2a
commit
88b35a75cb
4 changed files with 122 additions and 66 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -12,29 +12,14 @@
|
|||
<article class='tabswiper'>
|
||||
<header>
|
||||
<section class='tabCounter'>
|
||||
Tab 1 of 20
|
||||
<img id='favicon' class='favicon' alt='Favicon' />
|
||||
Tab <span id='tabNumber'>
|
||||
0
|
||||
</span> of <span id='tabTotalNumber'>
|
||||
0
|
||||
</span>
|
||||
</section>
|
||||
<a
|
||||
class='infoLink'
|
||||
target='_blank'
|
||||
href='#'
|
||||
>
|
||||
Info
|
||||
</a>
|
||||
</header>
|
||||
<section class='currentTab'>
|
||||
<section id='titleTab' class='title'>
|
||||
Some title here
|
||||
</section>
|
||||
<a
|
||||
id='linkTab'
|
||||
class='url'
|
||||
href='https://some.url/here'
|
||||
>
|
||||
https://some.url/here
|
||||
</a>
|
||||
</section>
|
||||
<footer>
|
||||
<section class='actions'>
|
||||
<button
|
||||
id='buttonClose'
|
||||
class='actionButton close'
|
||||
|
|
@ -49,7 +34,22 @@
|
|||
>
|
||||
Keep
|
||||
</button>
|
||||
</section>
|
||||
</header>
|
||||
<footer>
|
||||
</footer>
|
||||
<section class='currentTab'>
|
||||
<section id='titleTab' class='title'>
|
||||
Some title here
|
||||
</section>
|
||||
<a
|
||||
id='linkTab'
|
||||
class='url'
|
||||
href='https://some.url/here'
|
||||
>
|
||||
https://some.url/here
|
||||
</a>
|
||||
</section>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue