Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions static/js/app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { formatFileSize, formatQuotaSize } from '../core/formatters.js';
import { i18n } from '../core/i18n.js';
import { oxiIconsInit } from '../core/icons.js';
import { Modal } from '../core/modal.js';
import { fileOps } from '../features/files/fileOperations.js';
import { multiSelect } from '../features/files/multiSelect.js';
Expand Down Expand Up @@ -334,6 +335,8 @@ function switchSectionTo(section) {
* Initialize the application
*/
function initApp() {
oxiIconsInit();

// Cache DOM elements
cacheElements();

Expand Down
28 changes: 14 additions & 14 deletions static/js/core/icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// All icons use viewBox="0 0 {width} 512" and fill="currentColor".
// Keys use FA5 class names (without "fa-" prefix) for backward compatibility.

const _ICONS = {
const OxiIcons = {
'arrow-left': [
448,
'M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L109.2 288 416 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-306.7 0L214.6 118.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-160 160z'
Expand Down Expand Up @@ -430,7 +430,7 @@ const _ICONS = {
* @returns {string} SVG markup string, or empty string if icon not found
*/
function oxiIcon(name, extraClass) {
const entry = _ICONS[name];
const entry = OxiIcons[name];
if (!entry) return '';
const [w, d] = entry;
const cls = extraClass ? `oxi-icon ${extraClass}` : 'oxi-icon';
Expand Down Expand Up @@ -477,13 +477,13 @@ function replaceIconsInElement(container) {
}

// Use outline variant if available and element uses "far"
if (isRegular && _ICONS[`${iconName}-outline`]) {
if (isRegular && OxiIcons[`${iconName}-outline`]) {
iconName = `${iconName}-outline`;
}

if (!iconName || !_ICONS[iconName]) continue;
if (!iconName || !OxiIcons[iconName]) continue;

const [w, d] = _ICONS[iconName];
const [w, d] = OxiIcons[iconName];

// Build SVG element
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
Expand All @@ -510,14 +510,7 @@ function replaceIconsInElement(container) {
}
}

// ── Expose globally ────────────────────────────────────────────
export { oxiIcon, replaceIconsInElement };
export const OxiIcons = _ICONS;

// ── Auto-replace: MutationObserver bridge ──────────────────────
// Watches the DOM for new <i class="fa-..."> elements and converts them
// to inline SVGs automatically. Debounced to at most once per frame.
(function autoReplace() {
function oxiIconsInit() {
let raf = 0;
const scan = () => {
raf = 0;
Expand All @@ -541,4 +534,11 @@ export const OxiIcons = _ICONS;
}
}
}).observe(document.documentElement, { childList: true, subtree: true });
})();
}

// ── Expose globally ────────────────────────────────────────────
export { OxiIcons, oxiIcon, oxiIconsInit, replaceIconsInElement };

// ── Auto-replace: MutationObserver bridge ──────────────────────
// Watches the DOM for new <i class="fa-..."> elements and converts them
// to inline SVGs automatically. Debounced to at most once per frame.
2 changes: 2 additions & 0 deletions static/js/views/admin/admin.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getCsrfHeaders } from '../../core/csrf.js';
import { escapeHtml } from '../../core/formatters.js';
import { i18n } from '../../core/i18n.js';
import { oxiIconsInit } from '../../core/icons.js';

const API = '/api';
let currentAdminId = '';
Expand Down Expand Up @@ -1041,6 +1042,7 @@ async function completeMigration() {

async function init() {
try {
oxiIconsInit();
const me = await fetch(`${API}/auth/me`, {
headers: headers(),
credentials: 'same-origin'
Expand Down
3 changes: 3 additions & 0 deletions static/js/views/device-verify/device-verify.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// device-verify.js — Extracted from inline <script> in device-verify.html
import { getCsrfHeaders } from '../../core/csrf.js';
import { oxiIconsInit } from '../../core/icons.js';

(() => {
var API_BASE = window.location.origin;
Expand All @@ -12,6 +13,8 @@ import { getCsrfHeaders } from '../../core/csrf.js';
var debounceTimer = null;
var currentCode = '';

oxiIconsInit();

// Pre-fill from URL query param (?code=ABCD-1234)
var params = new URLSearchParams(window.location.search);
if (params.get('code')) {
Expand Down
2 changes: 2 additions & 0 deletions static/js/views/profile/profile.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getCsrfHeaders } from '../../core/csrf.js';
import { i18n } from '../../core/i18n.js';
import { oxiIconsInit } from '../../core/icons.js';

const API = '/api';

Expand Down Expand Up @@ -29,6 +30,7 @@ function timeAgo(dateStr) {

async function init() {
try {
oxiIconsInit();
const resp = await fetch(`${API}/auth/me`, {
headers: headers(),
credentials: 'same-origin'
Expand Down
4 changes: 4 additions & 0 deletions static/js/views/public/publicShare.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { oxiIconsInit } from '../../core/icons';

/**
* publicShare.js — Client-side logic for the public share page (/s/{token}).
*
Expand Down Expand Up @@ -27,6 +29,8 @@
const tokenIdx = pathParts.indexOf('s');
const TOKEN = tokenIdx !== -1 ? pathParts[tokenIdx + 1] : null;

oxiIconsInit();

if (!TOKEN) {
showState('expired');
$expiredMsg.textContent = 'Invalid share link.';
Expand Down
18 changes: 9 additions & 9 deletions tools/check-icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

What it does:
1. Scans every file under static/ for fas fa-<name> occurrences.
2. Reads the _ICONS registry from static/js/core/icons.js.
2. Reads the OxiIcons registry from static/js/core/icons.js.
3. For each icon name that is missing from the registry, looks up
tmp/Font-Awesome/svgs/solid/<name>.svg
and adds the entry '<name>': [<width>, '<path>'] to _ICONS.
and adds the entry '<name>': [<width>, '<path>'] to OxiIcons.
4. Rewrites icons.js in-place (unless --dry-run is given).

FontAwesome source: tmp/Font-Awesome/svgs/solid/
Expand Down Expand Up @@ -75,15 +75,15 @@

print(f"Found {len(used_icons)} distinct FA icon(s) referenced in static/")

# ── 2. Parse existing _ICONS keys from icons.js ───────────────────────────────
# ── 2. Parse existing OxiIcons keys from icons.js ───────────────────────────────
icons_src = ICONS_JS.read_text(encoding="utf-8")

# Extract only the _ICONS object body so we never accidentally match keys from
# Extract only the OxiIcons object body so we never accidentally match keys from
# other objects or functions elsewhere in the file.
_ICONS_BLOCK_RE = re.compile(r'const _ICONS\s*=\s*\{(.*?)^};', re.DOTALL | re.MULTILINE)
_ICONS_BLOCK_RE = re.compile(r'const OxiIcons\s*=\s*\{(.*?)^};', re.DOTALL | re.MULTILINE)
block_match = _ICONS_BLOCK_RE.search(icons_src)
if not block_match:
print("✗ Could not locate 'const _ICONS = { … };' in icons.js — aborting.")
print("✗ Could not locate 'const OxiIcons = { … };' in icons.js — aborting.")
sys.exit(1)
icons_block = block_match.group(1)

Expand All @@ -93,7 +93,7 @@
ICON_KEY_RE = re.compile(r"""['"]?([\w-]+)['"]?\s*:\s*\[""")
registered: set[str] = {m.group(1) for m in ICON_KEY_RE.finditer(icons_block)}

print(f"Registry has {len(registered)} icon(s) in _ICONS")
print(f"Registry has {len(registered)} icon(s) in OxiIcons")

# ── 3. Find missing icons ─────────────────────────────────────────────────────
missing = {name: files for name, files in used_icons.items() if name not in registered}
Expand Down Expand Up @@ -150,12 +150,12 @@

insert_block = "\n".join(insert_lines) + "\n"

# Insert just before the closing "};" of _ICONS (line 396 area)
# Insert just before the closing "};" of OxiIcons (line 396 area)
# Anchor: the line that is exactly "};"
ICONS_END_RE = re.compile(r'^};$', re.MULTILINE)
m = ICONS_END_RE.search(icons_src)
if not m:
print("\n✗ Could not locate the closing '}; ' of _ICONS in icons.js — aborting.")
print("\n✗ Could not locate the closing '}; ' of OxiIcons in icons.js — aborting.")
sys.exit(1)

# Ensure the last existing entry has a trailing comma before we append.
Expand Down
Loading