aboutsummaryrefslogtreecommitdiffstats
path: root/glide
diff options
context:
space:
mode:
Diffstat (limited to 'glide')
-rw-r--r--glide/.config/glide/glide.ts241
-rw-r--r--glide/.config/glide/sitesearch.glide.ts147
-rw-r--r--glide/.config/glide/tabbar.glide.ts256
3 files changed, 639 insertions, 5 deletions
diff --git a/glide/.config/glide/glide.ts b/glide/.config/glide/glide.ts
index 445091f..49c66de 100644
--- a/glide/.config/glide/glide.ts
+++ b/glide/.config/glide/glide.ts
@@ -24,6 +24,8 @@ glide.prefs.set("sidebar.visibility", "hide-sidebar");
// glide.prefs.set("browser.urlbar.placeholderName", "DuckDuckGo");
// glide.prefs.set("browser.urlbar.placeholderName.private", "DuckDuckGo");
+glide.keymaps.set("normal", "<C-x><C-c>", "quit");
+
// Previous tab
glide.keymaps.set("normal", "<A-p>", "tab_prev");
glide.keymaps.del('normal', '<C-k>');
@@ -48,7 +50,7 @@ glide.keymaps.set('command', '<C-n>', 'commandline_focus_next');
// Scroll up
glide.keymaps.set('normal', '<C-p>', 'caret_move up');
-glide.keymaps.set('normal', 'k');
+glide.keymaps.del('normal', 'k');
glide.keymaps.set('command', '<C-p>', 'commandline_focus_back');
// Go back
@@ -65,6 +67,7 @@ glide.keymaps.set("op-pending", "<C-g>", "mode_change normal");
// Close tab
glide.keymaps.set('normal', 'x', 'tab_close');
glide.keymaps.del('normal', '<leader>d');
+glide.keymaps.set('normal', 'X', 'tab_reopen');
// Scroll down
glide.keymaps.set('normal', '<C-v>', 'scroll_page_down');
@@ -79,8 +82,62 @@ glide.keymaps.set('normal', '<A-x>', 'commandline_show');
glide.keymaps.set('normal', 't', 'commandline_show tab_new ');
glide.keymaps.del('normal', ':');
+const keyboard_quit = glide.excmds.create({
+ name: "keyboard_quit",
+ description: 'Cancel whatever is going on and return to normal',
+}, () => {
+ if (glide.findbar.is_open()) {
+ glide.findbar.close();
+ }
+
+ if (glide.commandline.is_active()) {
+ glide.commandline.close();
+ }
+
+ glide.excmds.execute('mode_change normal');
+});
+
+glide.keymaps.set(['insert', 'command', 'normal'], '<C-g>', 'keyboard_quit');
+
+// Search
+const search_next = glide.excmds.create({
+ name: "search_next",
+ description: "Open search or find the next result",
+}, () => {
+ if (glide.findbar.is_focused()) {
+ glide.findbar.next_match();
+ }
+ else {
+ glide.findbar.open();
+ glide.excmds.execute('mode_change insert');
+ }
+});
+
+const search_prev = glide.excmds.create({
+ name: "search_prev",
+ description: "Open search of find the previous result",
+}, () => {
+ if (glide.findbar.is_focused()) {
+ glide.findbar.previous_match();
+ }
+ else {
+ glide.findbar.open();
+ glide.excmds.execute('mode_change insert');
+ }
+});
+
+glide.keymaps.set('normal', '<C-s>', 'search_next');
+glide.keymaps.set('normal', '<C-r>', 'search_prev');
+glide.keymaps.set('insert', '<C-s>', 'search_next');
+glide.keymaps.set('insert', '<C-r>', 'search_prev');
+
async function installPuntAddons() {
- await glide.addons.install("https://addons.mozilla.org/firefox/downloads/file/4677239/1password_x_password_manager-8.12.1.3.xpi");
+ await glide.addons.install("https://addons.mozilla.org/firefox/downloads/file/4677239/1password_x_password_manager-8.12.1.3.xpi");
+ await glide.addons.install('https://addons.mozilla.org/firefox/downloads/file/4508409/vue_js_devtools-7.7.7.xpi');
+}
+
+async function installPersonalAddons() {
+ await glide.addons.install('https://addons.mozilla.org/firefox/downloads/file/4628286/keepassxc_browser-1.9.11.xpi');
}
glide.keymaps.set('normal', '<leader>m', async function() {
@@ -99,10 +156,10 @@ async function open_or_activate(url) {
const tabs = await glide.tabs.query({url: `*://${url.hostname}/*`});
const tab = tabs.find(t => t.url.startsWith(url.href));
- if (tabs.length === 0) {
- glide.excmds.execute(`tab_new ${url}`);
- } else {
+ if (tab) {
await browser.tabs.update(tab.id, { active: true });
+ } else {
+ glide.excmds.execute(`tab_new ${url}`);
}
}
@@ -121,3 +178,177 @@ glide.keymaps.set('normal', '<leader>gd', async function() {
],
});
});
+
+glide.addons.install("https://addons.mozilla.org/firefox/downloads/file/4675310/ublock_origin-1.69.0.xpi");
+
+// From https://github.com/glide-browser/glide/discussions/147#discussioncomment-15617575
+
+interface Heading {
+ text: string;
+ tag: string;
+ id: string;
+ xpath: string;
+}
+
+glide.keymaps.set("normal", "gh", async () => {
+ const activeTabId = await glide.tabs.active();
+
+ // Extract all visible headings from the page
+ const headings = await glide.content.execute((): Heading[] => {
+ function isVisible(element: HTMLElement): boolean {
+ const style = window.getComputedStyle(element);
+ return style.display !== 'none' &&
+ style.visibility !== 'hidden' &&
+ style.opacity !== '0' &&
+ element.offsetParent !== null;
+ }
+
+ function getXPath(element: Element): string {
+ let path = '';
+ for (let el: Element | null = element; el && el.nodeType === Node.ELEMENT_NODE; el = el.parentElement) {
+ let index = 0;
+ for (let sibling = el.previousSibling; sibling; sibling = sibling.previousSibling) {
+ if (sibling.nodeType === Node.ELEMENT_NODE && (sibling as Element).tagName === el.tagName) {
+ index++;
+ }
+ }
+ const tagName = el.tagName.toLowerCase();
+ const pathIndex = `[${index + 1}]`;
+ path = `/${tagName}${pathIndex}${path}`;
+ }
+ return path;
+ }
+
+ return Array.from(document.querySelectorAll('h1, h2, h3, h4, h5, h6'))
+ .filter((heading) => isVisible(heading as HTMLElement))
+ .map((heading): Heading => ({
+ text: heading.textContent?.trim() || '',
+ tag: heading.tagName.toLowerCase(),
+ id: heading.id || '',
+ xpath: getXPath(heading)
+ }));
+ }, { tab_id: activeTabId });
+
+ if (headings.length === 0) {
+ glide.commandline.show({
+ title: "No visible headings found",
+ options: []
+ });
+ return;
+ }
+
+ glide.commandline.show({
+ title: "Jump to heading",
+ options: headings.map((heading) => {
+ const level = parseInt(heading.tag.substring(1));
+ const indent = '*'.repeat(level);
+
+ return {
+ label: `${indent}${indent ? ' ' : ''}${heading.text}`,
+ async execute() {
+ await glide.content.execute((xpath: string) => {
+ const target = document.evaluate(
+ xpath,
+ document,
+ null,
+ XPathResult.FIRST_ORDERED_NODE_TYPE,
+ null
+ ).singleNodeValue as HTMLElement | null;
+
+ if (target) {
+ target.scrollIntoView({ behavior: 'smooth', block: 'start' });
+ target.style.outline = '2px solid orange';
+ setTimeout(() => { target.style.outline = ''; }, 2000);
+ }
+ }, {
+ tab_id: activeTabId,
+ args: [heading.xpath]
+ });
+ },
+ };
+ }),
+ });
+}, { description: "Jump to heading in current page" });
+
+glide.keymaps.set('normal', 'ab', async () => {
+ const currentTab = await glide.tabs.get_first({ active: true });
+
+ glide.commandline.show({
+ title: 'Add',
+ options: [{
+ label: currentTab.title,
+ async execute({ input }) {
+ await browser.bookmarks.create({
+ url: currentTab.url,
+ title: input || currentTab.title,
+ });
+ }
+ }],
+ });
+});
+
+glide.keymaps.set('normal', 'kb', async () => {
+ const bookmarks = await browser.bookmarks.search({});
+
+ glide.commandline.show({
+ title: 'Remove',
+ options: bookmarks.map((b) => ({
+ label: b.title,
+ async execute() {
+ await browser.bookmarks.remove(b.id);
+ },
+ })),
+ });
+});
+
+
+// Split windows
+
+const split_window = glide.excmds.create({
+ name: 'split_window',
+ description: 'Ask for a tab and show it in a split with this window',
+}, async () => {
+ const activeTab = await glide.tabs.active();
+ const tabs = await glide.tabs.query({});
+
+ glide.commandline.show({
+ title: "Show other",
+ options: tabs.map(t => ({
+ label: t.title,
+ async execute() {
+ glide.unstable.split_views.create([activeTab.id, t.id]);
+ }
+ })),
+ });
+});
+
+const unsplit_window = glide.excmds.create({
+ name: 'unsplit_window',
+ description: 'Remove the current split of windows',
+}, ({ tab_id }) => {
+ glide.unstable.split_views.separate(tab_id);
+});
+
+const other_window = glide.excmds.create({
+ name: 'other_window',
+ description: 'Focus other window',
+}, async ({ tab_id }) => {
+ const split_tabs = await glide.unstable.split_views.get(tab_id);
+ const other_tab = split_tabs.tabs.filter(t => t.id !== tab_id)[0];
+
+ await browser.tabs.update(other_tab.id, { active: true });
+});
+
+glide.keymaps.set('normal', '<C-x>4b', 'split_window');
+glide.keymaps.set('normal', '<C-x>1', 'unsplit_window');
+glide.keymaps.set('normal', '<A-o>', 'other_window');
+
+glide.include('sitesearch.glide.ts');
+glide.include('tabbar.glide.ts');
+
+const toggle_reader_mode = glide.excmds.create({
+ name: 'toggle_reader_mode',
+ description: 'Toggle Reader Mode for the current tab',
+}, () => {
+ browser.tabs.toggleReaderMode();
+});
diff --git a/glide/.config/glide/sitesearch.glide.ts b/glide/.config/glide/sitesearch.glide.ts
new file mode 100644
index 0000000..f575015
--- /dev/null
+++ b/glide/.config/glide/sitesearch.glide.ts
@@ -0,0 +1,147 @@
+// From https://github.com/glide-browser/glide/discussions/147#discussioncomment-15337351
+
+/**
+ * custom search providers
+ */
+const search_info: Record<string, { url: string, sep: string }> = {
+ 'youtube': {
+ url: "https://www.youtube.com/results?search_query=", sep: "+"
+ }
+} as const
+
+/*
+ * pick tabs via a selection of bookmarks and history
+ */
+glide.keymaps.set("normal", "<leader>t", async () => {
+
+ //let combined: Array<Browser.Bookmarks.BookmarkTreeNode | Browser.History.HistoryItem> = []
+ let combined = []
+ const tabs = await browser.tabs.query({});
+ tabs.forEach(entry => combined.push({
+ title: entry.title ?? 'Unnamed Tab',
+ url: entry.url,
+ type: 'T',
+ favIconUrl: entry.favIconUrl
+ }));
+
+ const bookmarks = await browser.bookmarks.search({});
+ bookmarks
+ .filter(bmark => bmark.type !== 'folder')
+ .forEach(bmark => combined.push({ title: bmark.title, url: bmark.url, type: 'B', favIconUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAE/ElEQVR4Xu2cW2wUVRjHvzPdXdou0gvUemniegnRQtquimBNa4kpJfrCJrQ+Gewjb5oQfJPLG8akjzxawpMtyeKDpuBDkWqEBNMFEcUINEQTTEVrwbZ7mTmeb9xZ5j6zZXbd7X4n2YdOz3xz5rf//3fOmZ1zGPgsyelvY7m0vIcz/jpw3iNOi/k8teKqMQYLHNg5YNJnI7teG3drIPNq/cTZb95lirKPAx/wqlul/5+TGLy/d6j/tF37HQEJMD0CzNgaBmPmMT6yu3/UfNAWkKoaLo9xDs1VqorVNtsCyQII4YAif+J0hXAoBO2bWqCxfh20Nm8wVNto+nu1rSzleXcXFuHXO/Pqx64IuyX0djMAOnXm/B6FQ9KpgZtjHRDreBzCobpS3kNZYi/eX4JLV6/D8krafL05YbWntYMFQMnp2eZc5t4tJ1v1vdwFG9Y3lqXx5bpINifDzKUrVkhS3ajWuxUATU59/R4HZcyucR2PtUH388+Wq91lvQ4qCSEZCmOnR4b6EnisAGjizMxsfnxjaeDAti5oa20qScNvdg8GGveZy19a4nFxRJYVyIoPFxYxl8s/3TDkJBwnDQ/1txgBTZ23npmPVO2ANCB4g+lMDhQTJEzcF1LXDNxEHlLF80BBLoBiT7bDtq2bA/2mtWDlUJC+4QhpRUAyK+nzcxdWDwjP3PLcU9DW0hS41coNCO8lJ6yWEQlaXx4aUEnkI4K+dPBooKG/++hDQzzMnbEn2gFdoLfacjpLgPQEmh+JQm+8E6IN9erhJQJkFSbOAgZ74yokAuRgXFTSYO+LpQe0vWdLILkjt+vtQOJoQUJnP4W//r4Hd+bvwuL9f2xjY4/86KbW0uagSgak3fn8nwtw8/ZvFkiYuF/peoEAIQEnSG8N7CBAGoEff5mz2I0A6fSBOennW7cNiiFApsxzMfUDAUIC2IvZFQKUp0KAPEZNBIgAPdzAmhRECiIFGQiUYrJK3byLyCgHUQ6iHEQ5qBgNUJL2oEWACFAxhrLWJQWRgkhBtgSq4WcffcPpiSI9UfRnZZqL0VzMn1KcapGCSEFWAlLiTfWgkvzCU141pyDW3gZ1x4+pYOT9HwD/3X4JgUau5gDVfXwIWFenev/8yjWQDxxxVVFNAUJrSfv3GYAox0+4Wq1mABWstT5qVIx4a8zNajUDSG8ts6fcrFYTgOysZYbkZLU1D8jRWmZCDlZb84DcrOXHakEAYmJF9PDuvp14PV+LWez61aAedygnT4FyclK9hPTOsPjs9RwM6iv4Pb+oxx12C+omXFb7lBKQGlt7n9ncYxWFyr2yb0CMpcRiurgW7X9XUIAMXEP5AYQL6UKRcDyx89U5AmR+T/qri6lwJJTQw6mIHFQpCorWR2z3ECCL5b8hAuTxnjQBcgGE457G+rA67jEXshiOvyRptCESGidAOgKFtRoMUtF1kcK4hxSUJ6ACYmxBioTiDYwVxj2OgCanZqaL2SsoqKlGObp5XHmIS6K0grvU7Ih3pqRIOOEGxzgO8tgWx3wj1QQIVx3iwroCoJamI29s7z7s58sxDI7c9u+oVkBLyyvw/fUbD5pvmmt5QTIAUjdyy2Rn/ew8VQ0KkmVZhZPO/LeJgN1cqyhAWBkhZTO5pNNOMFrASgeEysFVhhocQcd2rlU0IO0Er93vKhUQJuQ/RL7Rcg4OArkknfDaDtAJ1L+Y5wqFFVK3lAAAAABJRU5ErkJggg==' }));
+
+ const topsites = await browser.topSites.get({includeFavicon: true});
+ topsites
+ .forEach(s => combined.push({ title: s.title, url: s.url, type: 'S', favIconUrl: s.favicon}));
+
+ const history = await browser.history.search({ text: "", maxResults: 100 });
+ history.forEach(entry => combined.push({ title: entry.title, url: entry.url, type: 'H', favIconUrl: null }));
+
+ // filtering
+ const newtab = (await browser.runtime.getManifest()).chrome_url_overrides?.newtab
+ const startpage = glide.prefs.get("browser.startup.homepage")
+
+ let filtered_combined = combined.filter(e => e.url !== startpage && e.url !== newtab)
+
+ glide.commandline.show({
+ title: "open",
+ options: filtered_combined.map((entry) => ({
+ label: entry.title,
+ render() {
+ return DOM.create_element("div", {
+ style: {
+ display: "flex",
+ alignItems: "center",
+ gap: "8px",
+ },
+ children: [
+ entry.favIconUrl
+ ? DOM.create_element("img", [], {
+ src: entry.favIconUrl,
+ style: {
+ width: '16px',
+ height: '16px',
+ }
+ })
+ : DOM.create_element("span", [entry.type], {
+ style: { color: "#777", fontSize: "0.9em" },
+ }),
+ DOM.create_element("span", [entry.title]),
+ DOM.create_element("span", [entry.url], {
+ style: { color: "#777", fontSize: "0.9em" },
+ }),
+ ],
+ });
+ },
+ async execute({ input: input }) {
+ if (entry.title.toLowerCase().includes(input.toLowerCase())) {
+ const tab = await glide.tabs.get_first({
+ url: entry.url,
+ });
+ if (tab) {
+ const windowid = tab.windowId;
+ if (windowid === undefined) {
+ return
+ }
+ await browser.windows.update(windowid, {
+ focused: true
+ })
+ await browser.tabs.update(tab.id, {
+ active: true,
+ });
+ } else {
+
+ await browser.tabs.create({
+ active: true,
+ url: entry.url,
+ windowId: browser.windows.getCurrent().id,
+ });
+ }
+ } else {
+ const terms = input.split(" ",)
+ const first = terms[0]
+ if (terms.length > 1 && first !== undefined && first in search_info) {
+ let info = search_info[first];
+ let query = info?.url + terms.slice(1).join(info?.sep)
+ browser.tabs.create({
+ active: true,
+ url: query
+ });
+ return;
+ }
+
+ let url: URL;
+ try {
+ url = new URL(input)
+ } catch (_) {
+ try {
+ url = new URL("http://" + input) // firefox automatically makes this https
+
+ // avoids single word searches becoming URLs
+ if (url.hostname.split(".").length == 1 && url.hostname !== "localhost") {
+ throw "probably not a hostname";
+ }
+ } catch (_) { // probably not a url
+ browser.search.search({
+ query: terms.filter(s => s).join(" "),
+ disposition: "NEW_TAB",
+ })
+ return
+ }
+
+ }
+ // so it IS a URL!
+
+ const tab = await glide.tabs.get_first({ url: url.href });
+
+ if (tab) {
+ browser.tabs.update(tab.id, { active: true });
+ }
+ else {
+ browser.tabs.create({ active: true, url });
+ }
+ }
+
+ },
+ })),
+ });
+}, { description: "Open the site searcher" });
diff --git a/glide/.config/glide/tabbar.glide.ts b/glide/.config/glide/tabbar.glide.ts
new file mode 100644
index 0000000..3ad7817
--- /dev/null
+++ b/glide/.config/glide/tabbar.glide.ts
@@ -0,0 +1,256 @@
+// Status bar
+// https://github.com/glide-browser/glide/discussions/147#discussioncomment-15573076
+
+const status_bar_id = "glide-status-bar"
+
+const mode_colors: Record<keyof GlideModes, string> = {
+ "command": "--glide-mode-command",
+ "hint": "--glide-mode-hint",
+ "ignore": "--glide-mode-ignore",
+ "insert": "--glide-mode-insert",
+ "normal": "--glide-mode-normal",
+ "op-pending": "--glide-mode-op-pending",
+ "visual": "--glide-mode-visual",
+}
+const fallback_mode_color = "--glide-fallback-mode"
+
+glide.autocmds.create("ConfigLoaded", async () => {
+ const existing = document.getElementById(status_bar_id)
+ if (existing) {
+ existing.remove()
+ }
+
+ const status_bar = DOM.create_element("div", {
+ id: status_bar_id,
+ children: [
+ DOM.create_element("div", {
+ className: "glide-status-tabs",
+ children: []
+ }),
+ DOM.create_element("div", {
+ className: "glide-status-right",
+ children: []
+ })
+ ]
+ })
+
+ const browser = document.getElementById("browser")
+ if (browser) {
+ browser.appendChild(status_bar)
+ }
+
+ setTimeout(() => {
+ update_status_bar()
+ }, 100)
+})
+
+glide.autocmds.create("WindowLoaded", async () => {
+ let status_bar = document.getElementById(status_bar_id) as HTMLElement
+ if (!status_bar) {
+ status_bar = DOM.create_element("div", {
+ id: status_bar_id,
+ children: [
+ DOM.create_element("div", {
+ className: "glide-status-tabs",
+ children: []
+ }),
+ DOM.create_element("div", {
+ className: "glide-status-right",
+ children: []
+ })
+ ]
+ }) as HTMLElement
+
+ const browser = document.getElementById("browser")
+ if (browser) {
+ browser.appendChild(status_bar)
+ }
+ }
+
+ await update_status_bar()
+})
+
+function ensure_status_bar() {
+ let status_bar = document.getElementById(status_bar_id) as HTMLElement
+ if (!status_bar) {
+ status_bar = DOM.create_element("div", {
+ id: status_bar_id,
+ children: [
+ DOM.create_element("div", {
+ className: "glide-status-tabs",
+ children: []
+ }),
+ DOM.create_element("div", {
+ className: "glide-status-right",
+ children: []
+ })
+ ]
+ }) as HTMLElement
+
+ const browser = document.getElementById("browser")
+ if (browser) {
+ browser.appendChild(status_bar)
+ }
+ } else {
+ let tabs = status_bar.querySelector(".glide-status-tabs")
+ let right = status_bar.querySelector(".glide-status-right")
+ if (!tabs || !right) {
+ status_bar.innerHTML = ""
+ status_bar.appendChild(DOM.create_element("div", {
+ className: "glide-status-tabs",
+ children: []
+ }))
+ status_bar.appendChild(DOM.create_element("div", {
+ className: "glide-status-right",
+ children: []
+ }))
+ }
+ }
+ return status_bar
+}
+
+async function update_status_bar() {
+ // Ensure status bar exists
+ const status_bar = ensure_status_bar() as HTMLElement
+ if (!status_bar) return
+
+ const tabs_container = status_bar.querySelector(".glide-status-tabs")
+ const right = status_bar.querySelector(".glide-status-right")
+ if (!tabs_container || !right) {
+ // If elements don't exist, recreate them
+ ensure_status_bar()
+ return
+ }
+
+ try {
+ const current_window = await browser.windows.getCurrent();
+ const tabs = await browser.tabs.query({
+ windowId: current_window.id,
+ });
+ const active_tab = await glide.tabs.active();
+ const tab_index = tabs.findIndex(t => t.id == active_tab.id);
+ const url = active_tab.url;
+ const title = active_tab.title || "Untitled";
+
+ let display_url = url || "about:blank";
+
+ if (display_url.length > 50) {
+ display_url = display_url.substring(0, 47) + "...";
+ }
+
+ tabs_container.textContent = `[${tab_index + 1}/${tabs.length}]`;
+ right.textContent = `${title} | ${display_url}`;
+ } catch (e) {
+ tabs_container.textContent = e;
+ right.textContent = "Error loading tabs"
+ }
+}
+
+glide.autocmds.create("ModeChanged", "*", (args) => {
+ const style_id = "glide-custom-mode-indicator"
+ glide.styles.remove(style_id)
+ glide.styles.add(`
+ #browser {
+ border-bottom: 3px solid var(${mode_colors[args.new_mode] ?? fallback_mode_color})
+ }
+ `, { id: style_id })
+})
+
+glide.autocmds.create("UrlEnter", /.*/, async () => {
+ await update_status_bar()
+})
+
+browser.tabs.onActivated.addListener(async () => {
+ await update_status_bar()
+})
+
+browser.tabs.onUpdated.addListener(async (tabId, changeInfo) => {
+ if (changeInfo.url || changeInfo.title) {
+ await update_status_bar()
+ }
+})
+
+browser.tabs.onCreated.addListener(async () => {
+ await update_status_bar()
+})
+
+browser.tabs.onRemoved.addListener(async () => {
+ await update_status_bar()
+});
+
+browser.windows.onFocusChanged.addListener(async (windowId) => {
+ await update_status_bar();
+});
+
+glide.styles.add(`
+ #${status_bar_id} {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 24px;
+ background-color: #1e1e1e;
+ color: #d4d4d4;
+ font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', 'Courier New', monospace;
+ font-size: 12px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0 12px;
+ border-top: 1px solid #3e3e3e;
+ z-index: 10000;
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.3);
+ overflow: hidden;
+ }
+
+ #${status_bar_id} .glide-status-tabs {
+ display: flex;
+ align-items: center;
+ gap: 0;
+ flex: 1;
+ overflow-x: auto;
+ overflow-y: hidden;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+ }
+
+ #${status_bar_id} .glide-status-tabs::-webkit-scrollbar {
+ display: none;
+ }
+
+ #${status_bar_id} .glide-tab-item {
+ color: #858585;
+ cursor: pointer;
+ padding: 2px 4px;
+ border-radius: 2px;
+ white-space: nowrap;
+ transition: background-color 0.2s ease, color 0.2s ease;
+ }
+
+ #${status_bar_id} .glide-tab-item:hover {
+ background-color: #2e2e2e;
+ color: #d4d4d4;
+ }
+
+ #${status_bar_id} .glide-tab-item.active {
+ color: #569cd6;
+ font-weight: 600;
+ background-color: #2a2a2a;
+ }
+
+ #${status_bar_id} .glide-tab-separator {
+ color: #3e3e3e;
+ user-select: none;
+ }
+
+ #${status_bar_id} .glide-status-right {
+ color: #858585;
+ margin-left: 12px;
+ white-space: nowrap;
+ flex-shrink: 0;
+ }
+
+ #browser {
+ padding-bottom: 24px;
+ }
+ `, { id: "glide-status-bar-styles" });