From 46c04ac548c1b80bf5520d4ab8d40058a9272b93 Mon Sep 17 00:00:00 2001 From: adesh singh Date: Tue, 5 May 2026 10:22:39 +0530 Subject: [PATCH] adding domvisualizer project --- Projects/domvisualizer/index.html | 131 +++++++++ Projects/domvisualizer/script.js | 338 ++++++++++++++++++++++ Projects/domvisualizer/style.css | 446 ++++++++++++++++++++++++++++++ 3 files changed, 915 insertions(+) create mode 100644 Projects/domvisualizer/index.html create mode 100644 Projects/domvisualizer/script.js create mode 100644 Projects/domvisualizer/style.css diff --git a/Projects/domvisualizer/index.html b/Projects/domvisualizer/index.html new file mode 100644 index 000000000..e9a9ffc85 --- /dev/null +++ b/Projects/domvisualizer/index.html @@ -0,0 +1,131 @@ + + + + + + DOM Visualizer + + + +
+
+ +
+
+
+ 🔍 + + +
+ +
+
+
+
+
+ ▶ Preview + Click element to inspect +
+
+ +
+ + + +
+

Next-generation solutions

+

Build Something Remarkable

+
+ + +
+
+ +
+
+
+

Performance

+

Blazing fast with zero dependencies.

+ Read more → +
+
+
+

Scalability

+

Grows with your product seamlessly.

+ Read more → +
+
+
🔒
+

Security

+

Enterprise-grade protection built-in.

+ Read more → +
+
+ +
+

Contact Us

+
+ + +
+
+ + +
+
+ + +
+ +
+ +
+

© 2026 Acme Corp — All rights reserved

+
+ +
+
+
+ +
+ +
+
+ ⯆ DOM Tree +
+ + +
+
+
+
+ +
+
+ ⓘ Inspector +
+
+

Select an element to inspect it.

+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/Projects/domvisualizer/script.js b/Projects/domvisualizer/script.js new file mode 100644 index 000000000..4fea3e307 --- /dev/null +++ b/Projects/domvisualizer/script.js @@ -0,0 +1,338 @@ + +'use strict'; + +const SKIP_TAGS = new Set(['SCRIPT', 'STYLE', 'NOSCRIPT', 'META', 'LINK', 'TITLE']); + +const elementToRow = new WeakMap(); +const rowToElement = new WeakMap(); + +let selectedEl = null; +let selectedRow = null; + +document.addEventListener('DOMContentLoaded', () => { + const root = document.getElementById('sampleRoot'); + const treeBody = document.getElementById('treeBody'); + + treeBody.appendChild(buildTree(root, 0)); + + attachPreviewListeners(root); + + document.getElementById('expandAll').addEventListener('click', () => { + setAllNodes(true); + }); + document.getElementById('collapseAll').addEventListener('click', () => { + setAllNodes(false); + }); + + const searchInput = document.getElementById('searchInput'); + const clearBtn = document.getElementById('clearSearch'); + const matchCount = document.getElementById('matchCount'); + + searchInput.addEventListener('input', () => { + handleSearch(searchInput.value.trim(), matchCount); + }); + clearBtn.addEventListener('click', () => { + searchInput.value = ''; + handleSearch('', matchCount); + searchInput.focus(); + }); +}); + +function buildTree(el, depth) { + if (SKIP_TAGS.has(el.tagName)) return null; + + const childEls = Array.from(el.childNodes).filter(node => { + if (node.nodeType === Node.ELEMENT_NODE) return !SKIP_TAGS.has(node.tagName); + if (node.nodeType === Node.TEXT_NODE) return node.textContent.trim() !== ''; + return false; + }); + + const hasChildren = childEls.some(n => n.nodeType === Node.ELEMENT_NODE); + + const nodeWrap = document.createElement('div'); + nodeWrap.className = 'tree-node'; + + const row = buildRow(el, hasChildren, childEls); + nodeWrap.appendChild(row); + + elementToRow.set(el, row); + rowToElement.set(row, el); + + if (childEls.length > 0) { + const childWrap = document.createElement('div'); + childWrap.className = 'tree-children'; + + childEls.forEach(child => { + if (child.nodeType === Node.ELEMENT_NODE) { + const subtree = buildTree(child, depth + 1); + if (subtree) childWrap.appendChild(subtree); + } + }); + + nodeWrap.appendChild(childWrap); + } + + return nodeWrap; +} + + +function buildRow(el, hasChildren, childEls) { + const row = document.createElement('div'); + row.className = 'tree-row'; + + const toggle = document.createElement('span'); + toggle.className = hasChildren ? 'tree-toggle open' : 'tree-toggle leaf'; + toggle.textContent = hasChildren ? '▶' : '·'; + row.appendChild(toggle); + + const tag = document.createElement('span'); + tag.className = 'tree-tag'; + tag.textContent = `<${el.tagName.toLowerCase()}>`; + row.appendChild(tag); + + if (el.id) { + const idSpan = document.createElement('span'); + idSpan.className = 'tree-tag-id'; + idSpan.textContent = `#${el.id}`; + row.appendChild(idSpan); + } + + if (el.classList.length) { + const classSpan = document.createElement('span'); + classSpan.className = 'tree-tag-class'; + classSpan.textContent = '.' + Array.from(el.classList).join('.'); + row.appendChild(classSpan); + } + + const textNodes = Array.from(el.childNodes).filter( + n => n.nodeType === Node.TEXT_NODE && n.textContent.trim() + ); + const hasOnlyText = textNodes.length > 0 && !Array.from(el.children).length; + if (hasOnlyText) { + const txt = document.createElement('span'); + txt.className = 'tree-tag-text'; + txt.textContent = `"${textNodes.map(n => n.textContent.trim()).join(' ')}"`; + row.appendChild(txt); + } + + const attrCount = el.attributes.length; + if (attrCount > 0 && (el.id || el.classList.length)) { + const others = Array.from(el.attributes).filter( + a => a.name !== 'id' && a.name !== 'class' + ); + if (others.length) { + const attrSpan = document.createElement('span'); + attrSpan.className = 'tree-attr'; + attrSpan.textContent = `[+${others.length} attr]`; + row.appendChild(attrSpan); + } + } else if (attrCount > 0 && !el.id && !el.classList.length) { + const attrSpan = document.createElement('span'); + attrSpan.className = 'tree-attr'; + attrSpan.textContent = `[${attrCount} attr]`; + row.appendChild(attrSpan); + } + + if (hasChildren) { + toggle.addEventListener('click', (e) => { + e.stopPropagation(); + toggleNode(row.parentElement); + }); + } + + row.addEventListener('mouseenter', () => { + clearHover(); + el.classList.add('dom-hovered'); + el.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); + }); + row.addEventListener('mouseleave', () => { + el.classList.remove('dom-hovered'); + }); + + row.addEventListener('click', (e) => { + e.stopPropagation(); + selectElement(el, row); + }); + + return row; +} + +function selectElement(el, row) { + if (selectedEl) selectedEl.classList.remove('dom-selected'); + if (selectedRow) selectedRow.classList.remove('tree-selected'); + + selectedEl = el; + selectedRow = row; + + el.classList.add('dom-selected'); + row.classList.add('tree-selected'); + + row.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); + + renderInspector(el); +} + +function renderInspector(el) { + const infoBody = document.getElementById('infoBody'); + infoBody.innerHTML = ''; + + appendSection(infoBody, 'Element', () => { + const pill = document.createElement('span'); + pill.className = 'info-tag-pill'; + pill.textContent = `<${el.tagName.toLowerCase()}>`; + return [pill]; + }); + + appendSection(infoBody, 'Attributes', () => { + const attrs = Array.from(el.attributes); + if (!attrs.length) return [emptyNote('none')]; + return attrs.map(a => kv(a.name, a.value || '""')); + }); + + appendSection(infoBody, 'Classes', () => { + const classes = Array.from(el.classList); + if (!classes.length) return [emptyNote('none')]; + return classes.map(c => kv('.class', c)); + }); + + appendSection(infoBody, 'Inner Text', () => { + const text = el.innerText?.trim().replace(/\s+/g, ' ').slice(0, 120) || ''; + return [kv('text', text || '(empty)')]; + }); + + appendSection(infoBody, 'Computed Styles', () => { + const cs = window.getComputedStyle(el); + const props = [ + 'color', 'background-color', 'font-size', 'font-weight', + 'font-family', 'display', 'position', 'width', 'height', + 'padding', 'margin', 'border', 'border-radius', 'opacity', + ]; + return props.map(p => kv(p, cs.getPropertyValue(p) || '–')); + }); +} + +function appendSection(container, title, contentFn) { + const section = document.createElement('div'); + section.className = 'info-section'; + + const h = document.createElement('div'); + h.className = 'info-section-title'; + h.textContent = title; + section.appendChild(h); + + contentFn().forEach(node => section.appendChild(node)); + container.appendChild(section); +} + +function kv(key, value) { + const wrap = document.createElement('div'); + wrap.className = 'info-kv'; + const k = document.createElement('span'); + k.className = 'info-kv-key'; + k.textContent = key; + const v = document.createElement('span'); + v.className = 'info-kv-value'; + v.textContent = value; + wrap.append(k, v); + return wrap; +} + +function emptyNote(msg) { + const s = document.createElement('span'); + s.className = 'info-empty'; + s.textContent = msg; + return s; +} + +function attachPreviewListeners(root) { + root.addEventListener('click', (e) => { + e.preventDefault(); + let target = e.target; + while (target && target !== root.parentElement) { + const row = elementToRow.get(target); + if (row) { + selectElement(target, row); + expandAncestors(row); + return; + } + target = target.parentElement; + } + }); +} + +function expandAncestors(row) { + let node = row.parentElement; + while (node && node.id !== 'treeBody') { + if (node.classList.contains('tree-children') && node.classList.contains('hidden')) { + node.classList.remove('hidden') + const parentNode = node.parentElement; + if (parentNode) { + const toggle = parentNode.querySelector(':scope > .tree-row > .tree-toggle'); + if (toggle) toggle.classList.add('open'); + } + } + node = node.parentElement; + } +} + +function toggleNode(treeNode) { + const children = treeNode.querySelector(':scope > .tree-children'); + if (!children) return; + const toggle = treeNode.querySelector(':scope > .tree-row > .tree-toggle'); + const isHidden = children.classList.toggle('hidden'); + if (toggle) { + toggle.classList.toggle('open', !isHidden); + } +} + +function setAllNodes(expand) { + document.querySelectorAll('.tree-children').forEach(c => { + c.classList.toggle('hidden', !expand); + }); + document.querySelectorAll('.tree-toggle:not(.leaf)').forEach(t => { + t.classList.toggle('open', expand); + }); +} + +function clearHover() { + document.querySelectorAll('.dom-hovered').forEach(el => { + el.classList.remove('dom-hovered'); + }); +} + + +function handleSearch(query, matchCountEl) { + const allRows = document.querySelectorAll('.tree-row'); + + if (!query) { + allRows.forEach(r => r.classList.remove('tree-search-match')); + matchCountEl.textContent = ''; + return; + } + + const isClass = query.startsWith('.'); + const needle = isClass ? query.slice(1).toLowerCase() : query.toLowerCase(); + let matches = 0; + + allRows.forEach(row => { + const el = rowToElement.get(row); + if (!el) return; + + let hit = false; + if (isClass) { + hit = Array.from(el.classList).some(c => c.toLowerCase().includes(needle)); + } else { + hit = el.tagName.toLowerCase().includes(needle); + } + + row.classList.toggle('tree-search-match', hit); + + if (hit) { + matches++; + expandAncestors(row); + row.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); + } + }); + + matchCountEl.textContent = matches ? `${matches} match${matches !== 1 ? 'es' : ''}` : 'No matches'; +} \ No newline at end of file diff --git a/Projects/domvisualizer/style.css b/Projects/domvisualizer/style.css new file mode 100644 index 000000000..1b7f0bddb --- /dev/null +++ b/Projects/domvisualizer/style.css @@ -0,0 +1,446 @@ +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +:root { + --bg-base: #000000; + --bg-panel: #0a0a0a; + --bg-panel-alt: #111111; + --bg-header: #0d0d0d; + --bg-hover: #1a1a1a; + --bg-selected: #141414; + + --border: #1f1f1f; + --border-light: #2a2a2a; + + --text-primary: #e5e7eb; + --text-secondary: #9ca3af; + --text-muted: #6b7280; + + --accent: #3b82f6; + --accent-glow: rgba(59,130,246,0.25); + --accent-green: #22c55e; + --accent-orange: #f59e0b; + --accent-purple: #a855f7; + --accent-red: #ef4444; + --accent-teal: #14b8a6; + + --highlight-ring: 2px solid var(--accent-red); + --highlight-bg: rgba(239, 68, 68, 0.1); + + --font-ui: 'Segoe UI', system-ui, sans-serif; + --font-mono: 'Cascadia Code', 'Fira Code', 'JetBrains Mono', 'Consolas', monospace; + + --radius-sm: 4px; + --radius-md: 8px; + --radius-lg: 12px; + + --topbar-h: 52px; + --transition: 140ms ease; +} + +html, body { + height: 100%; + overflow: hidden; + background: var(--bg-base); + color: var(--text-primary); + font-family: var(--font-ui); + font-size: 14px; + line-height: 1.5; +} + +.topbar { + position: fixed; + inset: 0 0 auto 0; + height: var(--topbar-h); + background: var(--bg-header); + border-bottom: 1px solid var(--border); + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 18px; + z-index: 100; + gap: 12px; +} + +.topbar-left { display: flex; align-items: center; gap: 10px; } + +.logo { + font-size: 15px; + font-weight: 700; + letter-spacing: .02em; + color: var(--accent); +} + +.badge { + background: var(--accent-glow); + color: var(--accent); + border: 1px solid rgba(79,158,255,.35); + border-radius: 30px; + padding: 2px 9px; + font-size: 11px; + font-weight: 600; + letter-spacing: .04em; +} + +.topbar-right { + display: flex; + align-items: center; + gap: 10px; + flex: 1; + max-width: 480px; + margin-left: auto; +} + +.search-wrap { + display: flex; + align-items: center; + gap: 6px; + background: var(--bg-panel-alt); + border: 1px solid var(--border-light); + border-radius: var(--radius-md); + padding: 0 10px; + flex: 1; + transition: border-color var(--transition); +} +.search-wrap:focus-within { border-color: var(--accent); } + +.search-icon { color: var(--text-muted); font-size: 13px; } + +#searchInput { + flex: 1; + background: transparent; + border: none; + outline: none; + color: var(--text-primary); + font-family: var(--font-mono); + font-size: 13px; + padding: 6px 0; +} +#searchInput::placeholder { color: var(--text-muted); } + +#clearSearch { + background: none; + border: none; + color: var(--text-muted); + cursor: pointer; + font-size: 12px; + padding: 2px 4px; + border-radius: 3px; + transition: color var(--transition); +} +#clearSearch:hover { color: var(--accent-red); } + +.match-count { + font-size: 12px; + color: var(--accent-green); + white-space: nowrap; + min-width: 60px; +} + +.workspace { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0; + height: calc(100vh - var(--topbar-h)); + margin-top: var(--topbar-h); + overflow: hidden; +} + +.panel { + background: var(--bg-panel); + border: 1px solid var(--border); + display: flex; + flex-direction: column; + overflow: hidden; +} + +.preview-panel { + border-left: none; + border-top: none; + border-bottom: none; +} + +.right-panel { + display: flex; + flex-direction: column; + border-top: none; + border-bottom: none; + border-right: none; +} + +.panel-tree { + flex: 1 1 0; + border: none; + border-bottom: 1px solid var(--border); +} + +.panel-info { + flex: 0 0 260px; + border: none; +} + +.panel-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 14px; + height: 38px; + background: var(--bg-header); + border-bottom: 1px solid var(--border); + flex-shrink: 0; +} + +.panel-title { + font-size: 12px; + font-weight: 700; + letter-spacing: .06em; + text-transform: uppercase; + color: var(--text-secondary); +} + +.panel-hint { + font-size: 11px; + color: var(--text-muted); +} + +.panel-body { + flex: 1; + overflow-y: auto; + overflow-x: auto; + padding: 12px; +} + + +.panel-body::-webkit-scrollbar { width: 6px; height: 6px; } +.panel-body::-webkit-scrollbar-track { background: transparent; } +.panel-body::-webkit-scrollbar-thumb { background: var(--border-light); border-radius: 3px; } +.panel-body::-webkit-scrollbar-thumb:hover { background: var(--text-muted); } + + +.tree-actions { display: flex; gap: 4px; } + +.action-btn { + background: var(--bg-panel-alt); + border: 1px solid var(--border-light); + color: var(--text-secondary); + border-radius: var(--radius-sm); + width: 24px; + height: 24px; + cursor: pointer; + font-size: 15px; + line-height: 1; + display: flex; align-items: center; justify-content: center; + transition: background var(--transition), color var(--transition); +} +.action-btn:hover { background: var(--bg-hover); color: var(--accent); } + +#previewBody { padding: 0; } + +.sample-root { + min-height: 100%; + background: #111420; + color: #cdd5f0; + font-family: var(--font-ui); +} + +/* header */ +.page-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 14px 20px; + background: #151826; + border-bottom: 1px solid #252b3b; +} +.site-title { font-size: 19px; font-weight: 800; color: #e2e8f8; } +.site-title .accent { color: #4f9eff; } +.main-nav { display: flex; gap: 18px; } +.nav-link { color: #8895b3; text-decoration: none; font-size: 13px; font-weight: 500; transition: color .15s; } +.nav-link:hover, .nav-link.active { color: #4f9eff; } + +.hero { + padding: 36px 20px 28px; + text-align: center; + background: var(--bg-base); +} +.hero-sub { font-size: 12px; color: #4f9eff; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; margin-bottom: 8px; } +.hero-title { font-size: 28px; font-weight: 800; color: #e2e8f8; margin-bottom: 18px; } +.hero-title em { font-style: normal; color: #4f9eff; } +.cta-group { display: flex; gap: 10px; justify-content: center; } + +.btn { + padding: 8px 20px; + border-radius: 6px; + font-size: 13px; + font-weight: 600; + cursor: pointer; + border: none; + transition: opacity .15s; +} +.btn:hover { opacity: .85; } +.btn-primary { background: #4f9eff; color: #fff; } +.btn-outline { background: transparent; color: #4f9eff; border: 1.5px solid #4f9eff; } + +.cards { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 12px; + padding: 20px; + background: var(--bg-base); +} +.card { + background: #16192a; + border: 1px solid #252b3b; + border-radius: 10px; + padding: 18px 16px; + transition: border-color .2s; +} +.card:hover { border-color: #4f9eff; } +.card-icon { font-size: 22px; margin-bottom: 8px; } +.card-title { font-size: 14px; font-weight: 700; color: #e2e8f8; margin-bottom: 6px; } +.card-body { font-size: 12px; color: #8895b3; margin-bottom: 10px; line-height: 1.6; } +.card-link { font-size: 12px; color: #4f9eff; text-decoration: none; font-weight: 600; } + +.contact-form { + margin: 20px; + padding: 20px; + background: var(--bg-base); + border: 1px solid #252b3b; + border-radius: 10px; +} +.form-title { font-size: 15px; font-weight: 700; color: #e2e8f8; margin-bottom: 14px; } +.field-row { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; } +.field-label { font-size: 12px; color: #8895b3; font-weight: 600; } +.field-input { + background: #0f1220; + border: 1px solid #252b3b; + border-radius: 6px; + padding: 7px 10px; + color: #e2e8f8; + font-size: 13px; + font-family: inherit; + outline: none; + transition: border-color .15s; +} +.field-input:focus { border-color: #4f9eff; } + +.page-footer { + padding: 14px 20px; + background: #0d0f1a; + border-top: 1px solid #252b3b; + text-align: center; + color: #525e7a; + font-size: 12px; +} + + +.dom-hovered { + outline: var(--highlight-ring) !important; + outline-offset: 1px !important; + background-color: var(--highlight-bg) !important; + border-radius: 2px; +} + +.dom-selected { + outline: 2px solid var(--accent-orange) !important; + outline-offset: 1px !important; + background-color: rgba(240, 160, 90, 0.1) !important; + border-radius: 2px; +} + +#treeBody { + font-family: var(--font-mono); + font-size: 12.5px; + padding: 8px 6px; + user-select: none; +} + +.tree-node { + display: flex; + flex-direction: column; +} + +.tree-row { + display: flex; + align-items: baseline; + gap: 4px; + padding: 2px 6px 2px 0; + border-radius: var(--radius-sm); + cursor: pointer; + white-space: nowrap; + transition: background var(--transition); + position: relative; +} +.tree-row:hover { background: var(--bg-hover); } +.tree-row.tree-selected { background: var(--bg-selected); } +.tree-row.tree-search-match { background: rgba(62, 207, 142, .12); } +.tree-row.tree-search-match .tree-tag { color: var(--accent-green); } + +.tree-toggle { + width: 16px; + flex-shrink: 0; + color: var(--text-muted); + font-size: 10px; + text-align: center; + line-height: 1; + margin-top: 1px; + transition: transform var(--transition); + display: inline-block; +} +.tree-toggle.open { transform: rotate(90deg); } +.tree-toggle.leaf { cursor: default; color: transparent; } + +.tree-children { + border-left: 1px solid var(--border); + margin-left: 8px; + padding-left: 8px; +} +.tree-children.hidden { display: none; } + +.tree-tag { color: var(--accent); font-weight: 600; } +.tree-tag-id { color: var(--accent-orange); font-size: 11px; } +.tree-tag-class { color: var(--accent-green); font-size: 11px; } +.tree-tag-text { color: var(--text-muted); font-size: 11px; font-style: italic; max-width: 220px; overflow: hidden; text-overflow: ellipsis; } +.tree-attr { color: var(--accent-teal); font-size: 11px; } + +.info-placeholder { color: var(--text-muted); font-size: 12px; padding: 6px 0; } + +.info-section { margin-bottom: 14px; } + +.info-section-title { + font-size: 10px; + font-weight: 700; + letter-spacing: .1em; + text-transform: uppercase; + color: var(--text-muted); + margin-bottom: 6px; + padding-bottom: 4px; + border-bottom: 1px solid var(--border); +} + +.info-tag-pill { + display: inline-block; + background: var(--accent-glow); + color: var(--accent); + border: 1px solid rgba(79,158,255,.3); + border-radius: 4px; + padding: 2px 9px; + font-family: var(--font-mono); + font-size: 13px; + font-weight: 700; + margin-bottom: 4px; +} + +.info-kv { + display: flex; + gap: 6px; + font-family: var(--font-mono); + font-size: 11.5px; + padding: 3px 0; + border-bottom: 1px solid rgba(37,43,59,.5); + word-break: break-all; +} +.info-kv:last-child { border-bottom: none; } +.info-kv-key { color: var(--accent-purple); min-width: 80px; flex-shrink: 0; } +.info-kv-value { color: var(--text-secondary); } + +.info-empty { color: var(--text-muted); font-size: 11px; font-style: italic; } \ No newline at end of file