diff --git a/.github/workflows/chrome-extension.yml b/.github/workflows/chrome-extension.yml new file mode 100644 index 000000000..88e775734 --- /dev/null +++ b/.github/workflows/chrome-extension.yml @@ -0,0 +1,87 @@ +name: Chrome Extension + +on: + # Build on PRs that touch extension code + pull_request: + paths: + - "apps/chrome-extension/**" + - "packages/core/**" + - "packages/common/**" + + # Publish when a GitHub release is created (after changeset release) + release: + types: [published] + + # Manual trigger for testing + workflow_dispatch: + inputs: + publish: + description: "Publish to Chrome Web Store" + required: false + default: "false" + type: choice + options: + - "false" + - "true" + +concurrency: + group: chrome-extension-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build Extension + runs-on: ubuntu-latest + steps: + - name: Check out + uses: actions/checkout@v4 + + - name: Install Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: package.json + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Build packages (core + common) + run: bun run build:packages + + - name: Build Chrome extension + working-directory: apps/chrome-extension + run: bun run build + + - name: Package extension + working-directory: apps/chrome-extension + run: cd dist && zip -r ../web3icons-chrome.zip . + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + name: chrome-extension + path: apps/chrome-extension/web3icons-chrome.zip + retention-days: 30 + + publish: + name: Publish to Chrome Web Store + needs: build + runs-on: ubuntu-latest + # Only publish on release events or manual trigger with publish=true + if: > + github.event_name == 'release' || + (github.event_name == 'workflow_dispatch' && github.event.inputs.publish == 'true') + steps: + - name: Download build artifact + uses: actions/download-artifact@v4 + with: + name: chrome-extension + + - name: Upload to Chrome Web Store + uses: mnao305/chrome-extension-upload@v5.0.0 + with: + file-path: web3icons-chrome.zip + extension-id: ${{ secrets.CHROME_EXTENSION_ID }} + client-id: ${{ secrets.CHROME_CLIENT_ID }} + client-secret: ${{ secrets.CHROME_CLIENT_SECRET }} + refresh-token: ${{ secrets.CHROME_REFRESH_TOKEN }} + publish: true diff --git a/apps/chrome-extension/.gitignore b/apps/chrome-extension/.gitignore new file mode 100644 index 000000000..1eae0cf67 --- /dev/null +++ b/apps/chrome-extension/.gitignore @@ -0,0 +1,2 @@ +dist/ +node_modules/ diff --git a/apps/chrome-extension/icons/icon-128.png b/apps/chrome-extension/icons/icon-128.png new file mode 100644 index 000000000..a272c0e9c Binary files /dev/null and b/apps/chrome-extension/icons/icon-128.png differ diff --git a/apps/chrome-extension/icons/icon-16.png b/apps/chrome-extension/icons/icon-16.png new file mode 100644 index 000000000..9b46a79c7 Binary files /dev/null and b/apps/chrome-extension/icons/icon-16.png differ diff --git a/apps/chrome-extension/icons/icon-32.png b/apps/chrome-extension/icons/icon-32.png new file mode 100644 index 000000000..672368137 Binary files /dev/null and b/apps/chrome-extension/icons/icon-32.png differ diff --git a/apps/chrome-extension/icons/icon-48.png b/apps/chrome-extension/icons/icon-48.png new file mode 100644 index 000000000..afa6e55f8 Binary files /dev/null and b/apps/chrome-extension/icons/icon-48.png differ diff --git a/apps/chrome-extension/manifest.json b/apps/chrome-extension/manifest.json new file mode 100644 index 000000000..78245a8ac --- /dev/null +++ b/apps/chrome-extension/manifest.json @@ -0,0 +1,22 @@ +{ + "manifest_version": 3, + "name": "Web3 Icons", + "version": "1.0.0", + "description": "Browse and copy 2,500+ crypto icons. Tokens, networks, wallets, and exchanges in branded, mono, and background variants.", + "permissions": ["clipboardWrite"], + "action": { + "default_popup": "popup.html", + "default_icon": { + "16": "icons/icon-16.png", + "32": "icons/icon-32.png", + "48": "icons/icon-48.png", + "128": "icons/icon-128.png" + } + }, + "icons": { + "16": "icons/icon-16.png", + "32": "icons/icon-32.png", + "48": "icons/icon-48.png", + "128": "icons/icon-128.png" + } +} diff --git a/apps/chrome-extension/package.json b/apps/chrome-extension/package.json new file mode 100644 index 000000000..38e84107c --- /dev/null +++ b/apps/chrome-extension/package.json @@ -0,0 +1,21 @@ +{ + "name": "@web3icons/chrome-extension", + "version": "1.0.0", + "private": true, + "description": "Browse and copy 2,500+ crypto icons from any tab. Tokens, networks, wallets, and exchanges in branded, mono, and background variants.", + "author": "AK ", + "scripts": { + "dev": "bun run build:css --watch & bun run build:js --watch", + "build": "bun run build:css && bun run build:js", + "build:css": "npx @tailwindcss/cli --input ./src/css/input.css --output ./dist/popup.css --minify", + "build:js": "bun run scripts/build.ts" + }, + "dependencies": { + "@web3icons/core": "4.0.50", + "@web3icons/common": "0.11.45" + }, + "devDependencies": { + "tailwindcss": "^4.1.11", + "typescript": ">=5" + } +} diff --git a/apps/chrome-extension/popup.html b/apps/chrome-extension/popup.html new file mode 100644 index 000000000..ca37aa1fa --- /dev/null +++ b/apps/chrome-extension/popup.html @@ -0,0 +1,46 @@ + + + + + + + + +
+ +
+
+
+ + +
+ +
+ + +
+ + +
+
+
+ + +
+ Copied! +
+ + + +
+ + + diff --git a/apps/chrome-extension/scripts/build.ts b/apps/chrome-extension/scripts/build.ts new file mode 100644 index 000000000..cd64ab257 --- /dev/null +++ b/apps/chrome-extension/scripts/build.ts @@ -0,0 +1,31 @@ +import { build } from 'bun' +import { cpSync, mkdirSync, existsSync } from 'fs' +import { join } from 'path' + +const ROOT = join(import.meta.dir, '..') +const DIST = join(ROOT, 'dist') + +// Ensure dist exists +mkdirSync(DIST, { recursive: true }) + +// Bundle popup.ts +await build({ + entrypoints: [join(ROOT, 'src/popup.ts')], + outdir: DIST, + naming: 'popup.js', + minify: true, + target: 'browser', + format: 'esm', +}) + +// Copy static files +cpSync(join(ROOT, 'popup.html'), join(DIST, 'popup.html')) +cpSync(join(ROOT, 'manifest.json'), join(DIST, 'manifest.json')) + +// Copy icons if they exist +const iconsDir = join(ROOT, 'icons') +if (existsSync(iconsDir)) { + cpSync(iconsDir, join(DIST, 'icons'), { recursive: true }) +} + +console.log('Build complete: dist/') diff --git a/apps/chrome-extension/src/css/input.css b/apps/chrome-extension/src/css/input.css new file mode 100644 index 000000000..6cba821b1 --- /dev/null +++ b/apps/chrome-extension/src/css/input.css @@ -0,0 +1,35 @@ +@import "tailwindcss"; + +@theme { + --color-gray-lightest: #222222; + --color-gray-light: #131313; + --color-gray: #111111; + --color-gray-dark: #0F0F0F; + --color-gray-darker: #0B0B0B; + --color-gray-darkest: #080808; + --color-primary: #FF3D00; +} + +body { + background-color: var(--color-gray-darkest); + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; + font-size: 0.75rem; +} + +/* Icon grid scrollbar */ +#icon-grid::-webkit-scrollbar { + width: 4px; +} +#icon-grid::-webkit-scrollbar-track { + background: transparent; +} +#icon-grid::-webkit-scrollbar-thumb { + background: #222; + border-radius: 2px; +} + +/* SVG sizing inside icon cards */ +.icon-card svg { + width: 32px; + height: 32px; +} diff --git a/apps/chrome-extension/src/popup.ts b/apps/chrome-extension/src/popup.ts new file mode 100644 index 000000000..508e1c16a --- /dev/null +++ b/apps/chrome-extension/src/popup.ts @@ -0,0 +1,207 @@ +import { svgs } from '@web3icons/core' +import type { TType, TVariant } from '@web3icons/common' + +type IconEntry = { name: string; svg: string } + +let activeType: TType = 'token' +let activeVariant: TVariant = 'branded' +let searchQuery = '' +let toastTimeout: ReturnType | null = null + +const TYPES: TType[] = ['token', 'network', 'wallet', 'exchange'] +const VARIANTS: TVariant[] = ['branded', 'mono', 'background'] + +// --- Icon data (cached per type+variant) --- + +const iconCache = new Map() + +function getIcons(type: TType, variant: TVariant, query: string): IconEntry[] { + const cacheKey = `${type}-${variant}` + let entries = iconCache.get(cacheKey) + + if (!entries) { + const typePlural = `${type}s` as keyof typeof svgs + const variantGroup = variant as keyof (typeof svgs)[typeof typePlural] + const modules = svgs[typePlural][variantGroup] as Record< + string, + { default: string } + > + + entries = Object.entries(modules).map(([exportName, mod]) => { + const name = exportName + .replace( + /^(Network|Token|Exchange|Wallet)(Mono|Branded|Background)/, + '', + ) + .toLowerCase() + return { name, svg: mod.default } + }) + + iconCache.set(cacheKey, entries) + } + + if (!query) return entries + + const q = query.toLowerCase() + return entries.filter((e) => e.name.includes(q)) +} + +// --- Toast --- + +function showToast(message: string) { + const toast = document.getElementById('toast')! + toast.textContent = message + toast.style.opacity = '1' + if (toastTimeout) clearTimeout(toastTimeout) + toastTimeout = setTimeout(() => { + toast.style.opacity = '0' + }, 1200) +} + +// --- Copy to clipboard --- + +async function copyToClipboard(svg: string, name: string) { + try { + await navigator.clipboard.writeText(svg) + showToast(`Copied ${name}`) + } catch { + // Fallback + const textarea = document.createElement('textarea') + textarea.value = svg + document.body.appendChild(textarea) + textarea.select() + document.execCommand('copy') + document.body.removeChild(textarea) + showToast(`Copied ${name}`) + } +} + +// --- Render tabs --- + +function renderTabs() { + const container = document.getElementById('tabs')! + const indicator = document.getElementById('tab-indicator')! + + // Clear existing tabs (keep indicator) + Array.from(container.children).forEach((child) => { + if (child.id !== 'tab-indicator') container.removeChild(child) + }) + + TYPES.forEach((type) => { + const btn = document.createElement('button') + btn.textContent = type.charAt(0).toUpperCase() + type.slice(1) + btn.className = `z-[1] flex items-center justify-center rounded-full px-4 py-2 text-xs text-white duration-150 ${ + activeType === type ? 'opacity-100' : 'opacity-40' + }` + btn.addEventListener('click', () => { + activeType = type + renderTabs() + renderIcons() + }) + container.insertBefore(btn, indicator) + }) + + // Update indicator + requestAnimationFrame(() => { + const activeIndex = TYPES.indexOf(activeType) + const activeBtn = container.children[activeIndex] as HTMLElement + if (activeBtn) { + indicator.style.width = `${activeBtn.offsetWidth}px` + indicator.style.transform = `translateX(${activeBtn.offsetLeft}px)` + } + }) +} + +// --- Render variant toggle --- + +function renderVariants() { + const container = document.getElementById('variants')! + container.innerHTML = '' + + VARIANTS.forEach((variant) => { + const label = document.createElement('button') + label.textContent = variant + label.className = `z-[1] flex w-full items-center justify-center rounded-full px-4 py-1 text-sm ${ + activeVariant === variant ? 'bg-gray-lightest' : '' + }` + label.addEventListener('click', () => { + activeVariant = variant + renderVariants() + renderIcons() + }) + container.appendChild(label) + }) +} + +// --- Render icon grid --- + +function renderIcons() { + const container = document.getElementById('icons')! + container.innerHTML = '' + + const icons = getIcons(activeType, activeVariant, searchQuery) + + if (icons.length === 0) { + container.innerHTML = + '
No icons found
' + return + } + + // Render in batches for performance + const BATCH_SIZE = 100 + let rendered = 0 + + function renderBatch() { + const fragment = document.createDocumentFragment() + const end = Math.min(rendered + BATCH_SIZE, icons.length) + + for (let i = rendered; i < end; i++) { + const icon = icons[i]! + const card = document.createElement('button') + card.className = + 'icon-card flex flex-col items-center justify-center gap-1 px-2 py-4 duration-150 hover:bg-gray-light cursor-pointer' + card.innerHTML = ` +
${icon.svg}
+ ${icon.name} + ` + card.title = `Copy ${icon.name} SVG` + card.addEventListener('click', () => copyToClipboard(icon.svg, icon.name)) + fragment.appendChild(card) + } + + container.appendChild(fragment) + rendered = end + + if (rendered < icons.length) { + requestAnimationFrame(renderBatch) + } + } + + renderBatch() +} + +// --- Search --- + +function setupSearch() { + const input = document.getElementById('search') as HTMLInputElement + let debounceTimer: ReturnType | null = null + + input.addEventListener('input', () => { + if (debounceTimer) clearTimeout(debounceTimer) + debounceTimer = setTimeout(() => { + searchQuery = input.value.trim() + renderIcons() + }, 150) + }) +} + +// --- Init --- + +function init() { + renderTabs() + renderVariants() + renderIcons() + setupSearch() +} + +document.addEventListener('DOMContentLoaded', init) diff --git a/apps/chrome-extension/tsconfig.json b/apps/chrome-extension/tsconfig.json new file mode 100644 index 000000000..0c66ee9cf --- /dev/null +++ b/apps/chrome-extension/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/apps/website/src/app/blog/[slug]/page.tsx b/apps/website/src/app/blog/[slug]/page.tsx index 62c28c8fb..77ee3d764 100644 --- a/apps/website/src/app/blog/[slug]/page.tsx +++ b/apps/website/src/app/blog/[slug]/page.tsx @@ -138,7 +138,14 @@ export default async function BlogPost({ {formatDate(frontmatter.date)} ยท - {frontmatter.author} + + {frontmatter.author} +
{frontmatter.tags?.map((tag: string) => ( diff --git a/apps/website/src/app/privacy/page.tsx b/apps/website/src/app/privacy/page.tsx new file mode 100644 index 000000000..1c5ba96b8 --- /dev/null +++ b/apps/website/src/app/privacy/page.tsx @@ -0,0 +1,67 @@ +import { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Privacy Policy | Web3 Icons', + description: 'Privacy policy for Web3 Icons and the Web3 Icons Chrome extension.', +} + +export default function PrivacyPage() { + return ( +
+

Privacy Policy

+

Last updated: February 2, 2026

+ +

Overview

+

+ Web3 Icons is an open-source icon library for cryptocurrency tokens, + networks, wallets, and exchanges. This policy covers the Web3 Icons + website (web3icons.io) and the Web3 Icons Chrome extension. +

+ +

Data We Collect

+

+ We do not collect any personal data. The Chrome + extension runs entirely on your device. It does not track you, send + analytics, or communicate with any server. +

+

+ The website uses Vercel Analytics for anonymous, aggregated page view + statistics. No cookies are used for tracking. No personal information is + collected or stored. +

+ +

Permissions

+

+ The Chrome extension requests the clipboardWrite permission + solely to copy SVG icon code to your clipboard when you click the copy + button. No clipboard data is read or transmitted. +

+ +

Third Parties

+

+ We do not share any data with third parties because we do not collect + any. +

+ +

Open Source

+

+ The full source code is available at{' '} + + github.com/0xa3k5/web3icons + + . You can verify everything described in this policy by reviewing the + code. +

+ +

Contact

+

+ Questions? Reach out at{' '} + hey@akml.io. +

+
+ ) +} diff --git a/apps/website/src/components/footer.tsx b/apps/website/src/components/footer.tsx index 43b93f337..2cb8f9bff 100644 --- a/apps/website/src/components/footer.tsx +++ b/apps/website/src/components/footer.tsx @@ -46,6 +46,15 @@ export const Footer = () => { )}
))} + / + + by ak + diff --git a/bun.lock b/bun.lock index 52c3efad5..a5a6ddcaf 100644 --- a/bun.lock +++ b/bun.lock @@ -1,6 +1,5 @@ { "lockfileVersion": 1, - "configVersion": 0, "workspaces": { "": { "name": "web3icons", @@ -33,6 +32,18 @@ "website": "^0.1.1", }, }, + "apps/chrome-extension": { + "name": "@web3icons/chrome-extension", + "version": "1.0.0", + "dependencies": { + "@web3icons/common": "0.11.45", + "@web3icons/core": "4.0.50", + }, + "devDependencies": { + "tailwindcss": "^4.1.11", + "typescript": ">=5", + }, + }, "apps/figma-plugin": { "name": "@web3icons/figma-plugin", "dependencies": { @@ -95,7 +106,7 @@ }, "packages/common": { "name": "@web3icons/common", - "version": "0.11.35", + "version": "0.11.45", "devDependencies": { "bun-types": "latest", }, @@ -105,9 +116,9 @@ }, "packages/core": { "name": "@web3icons/core", - "version": "4.0.40", + "version": "4.0.50", "dependencies": { - "@web3icons/common": "0.11.35", + "@web3icons/common": "0.11.45", }, "devDependencies": { "bun-types": "latest", @@ -137,7 +148,7 @@ }, "packages/react": { "name": "@web3icons/react", - "version": "4.1.6", + "version": "4.1.16", "dependencies": { "@web3icons/common": "0.11.35", }, @@ -834,6 +845,8 @@ "@vercel/style-guide": ["@vercel/style-guide@5.2.0", "", { "dependencies": { "@babel/core": "^7.22.11", "@babel/eslint-parser": "^7.22.11", "@rushstack/eslint-patch": "^1.3.3", "@typescript-eslint/eslint-plugin": "^6.5.0", "@typescript-eslint/parser": "^6.5.0", "eslint-config-prettier": "^9.0.0", "eslint-import-resolver-alias": "^1.1.2", "eslint-import-resolver-typescript": "^3.6.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.28.1", "eslint-plugin-jest": "^27.2.3", "eslint-plugin-jsx-a11y": "^6.7.1", "eslint-plugin-playwright": "^0.16.0", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-testing-library": "^6.0.1", "eslint-plugin-tsdoc": "^0.2.17", "eslint-plugin-unicorn": "^48.0.1", "prettier-plugin-packagejson": "^2.4.5" }, "peerDependencies": { "@next/eslint-plugin-next": ">=12.3.0 <15", "eslint": ">=8.48.0 <9", "prettier": ">=3.0.0 <4", "typescript": ">=4.8.0 <6" }, "optionalPeers": ["@next/eslint-plugin-next", "eslint", "prettier", "typescript"] }, "sha512-fNSKEaZvSkiBoF6XEefs8CcgAV9K9e+MbcsDZjUsktHycKdA0jvjAzQi1W/FzLS+Nr5zZ6oejCwq/97dHUKe0g=="], + "@web3icons/chrome-extension": ["@web3icons/chrome-extension@workspace:apps/chrome-extension"], + "@web3icons/common": ["@web3icons/common@workspace:packages/common"], "@web3icons/core": ["@web3icons/core@workspace:packages/core"], @@ -936,7 +949,7 @@ "builtin-modules": ["builtin-modules@3.3.0", "", {}, "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw=="], - "bun-types": ["bun-types@1.3.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ=="], + "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="], "busboy": ["busboy@1.6.0", "", { "dependencies": { "streamsearch": "^1.1.0" } }, "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA=="], @@ -2152,7 +2165,7 @@ "synckit": ["synckit@0.11.11", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw=="], - "tailwindcss": ["tailwindcss@3.4.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ=="], + "tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="], "tapable": ["tapable@2.3.0", "", {}, "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg=="], @@ -2368,8 +2381,6 @@ "@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], - "@tailwindcss/node/tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="], - "@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="], "@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], @@ -2384,8 +2395,6 @@ "@tailwindcss/postcss/postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], - "@tailwindcss/postcss/tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="], - "@tailwindcss/typography/postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="], "@typescript-eslint/typescript-estree/globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="], @@ -2398,7 +2407,9 @@ "@web3icons/figma-plugin/prettier-plugin-tailwindcss": ["prettier-plugin-tailwindcss@0.7.1", "", { "peerDependencies": { "@ianvs/prettier-plugin-sort-imports": "*", "@prettier/plugin-hermes": "*", "@prettier/plugin-oxc": "*", "@prettier/plugin-pug": "*", "@shopify/prettier-plugin-liquid": "*", "@trivago/prettier-plugin-sort-imports": "*", "@zackad/prettier-plugin-twig": "*", "prettier": "^3.0", "prettier-plugin-astro": "*", "prettier-plugin-css-order": "*", "prettier-plugin-jsdoc": "*", "prettier-plugin-marko": "*", "prettier-plugin-multiline-arrays": "*", "prettier-plugin-organize-attributes": "*", "prettier-plugin-organize-imports": "*", "prettier-plugin-sort-imports": "*", "prettier-plugin-svelte": "*" }, "optionalPeers": ["@ianvs/prettier-plugin-sort-imports", "@prettier/plugin-hermes", "@prettier/plugin-oxc", "@prettier/plugin-pug", "@shopify/prettier-plugin-liquid", "@trivago/prettier-plugin-sort-imports", "@zackad/prettier-plugin-twig", "prettier-plugin-astro", "prettier-plugin-css-order", "prettier-plugin-jsdoc", "prettier-plugin-marko", "prettier-plugin-multiline-arrays", "prettier-plugin-organize-attributes", "prettier-plugin-organize-imports", "prettier-plugin-sort-imports", "prettier-plugin-svelte"] }, "sha512-Bzv1LZcuiR1Sk02iJTS1QzlFNp/o5l2p3xkopwOrbPmtMeh3fK9rVW5M3neBQzHq+kGKj/4LGQMTNcTH4NGPtQ=="], - "@web3icons/website/tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="], + "@web3icons/figma-plugin/tailwindcss": ["tailwindcss@3.4.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ=="], + + "@web3icons/react/bun-types": ["bun-types@1.3.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-5ua817+BZPZOlNaRgGBpZJOSAQ9RQ17pkwPD0yR7CfJg+r8DgIILByFifDTa+IPDDxzf5VNhtNlcKqFzDgJvlQ=="], "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], @@ -2444,6 +2455,8 @@ "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "eslint-plugin-tailwindcss/tailwindcss": ["tailwindcss@3.4.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ=="], + "eslint-plugin-testing-library/@typescript-eslint/utils": ["@typescript-eslint/utils@5.62.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ=="], "eslint-plugin-unicorn/indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], @@ -2534,8 +2547,6 @@ "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], - "tailwindcss/postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], - "tempy/is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], "tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], @@ -2594,6 +2605,8 @@ "@vercel/style-guide/@typescript-eslint/parser/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" } }, "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A=="], + "@web3icons/figma-plugin/tailwindcss/postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + "concurrently/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], @@ -2614,6 +2627,8 @@ "eslint-plugin-jest/@typescript-eslint/utils/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], + "eslint-plugin-tailwindcss/tailwindcss/postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + "eslint-plugin-testing-library/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@5.62.0", "", { "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0" } }, "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w=="], "eslint-plugin-testing-library/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@5.62.0", "", {}, "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ=="],