algorembrant commited on
Commit
4af09f9
·
verified ·
1 Parent(s): 7b078c4

Upload 31 files

Browse files
dist/assets/index-CEnsgmh2.js ADDED
The diff for this file is too large to render. See raw diff
 
dist/assets/index-OrJvPUH_.css ADDED
@@ -0,0 +1 @@
 
 
1
+ @keyframes marching-ants{0%{background-position:0 0,0 100%,0 0,100% 0}to{background-position:20px 0,-20px 100%,0 -20px,100% 20px}}:root{--rc-drag-handle-size: 12px;--rc-drag-handle-mobile-size: 24px;--rc-drag-handle-bg-colour: rgba(0, 0, 0, .2);--rc-drag-bar-size: 6px;--rc-border-color: rgba(255, 255, 255, .7);--rc-focus-color: #0088ff}.ReactCrop{position:relative;display:inline-block;cursor:crosshair;max-width:100%}.ReactCrop *,.ReactCrop *:before,.ReactCrop *:after{box-sizing:border-box}.ReactCrop--disabled,.ReactCrop--locked{cursor:inherit}.ReactCrop__child-wrapper{overflow:hidden;max-height:inherit}.ReactCrop__child-wrapper>img,.ReactCrop__child-wrapper>video{display:block;max-width:100%;max-height:inherit}.ReactCrop:not(.ReactCrop--disabled) .ReactCrop__child-wrapper>img,.ReactCrop:not(.ReactCrop--disabled) .ReactCrop__child-wrapper>video{touch-action:none}.ReactCrop:not(.ReactCrop--disabled) .ReactCrop__crop-selection{touch-action:none}.ReactCrop__crop-mask{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;width:calc(100% + .5px);height:calc(100% + .5px)}.ReactCrop__crop-selection{position:absolute;top:0;left:0;transform:translateZ(0);cursor:move}.ReactCrop--disabled .ReactCrop__crop-selection{cursor:inherit}.ReactCrop--circular-crop .ReactCrop__crop-selection{border-radius:50%}.ReactCrop--circular-crop .ReactCrop__crop-selection:after{pointer-events:none;content:"";position:absolute;top:-1px;right:-1px;bottom:-1px;left:-1px;border:1px solid var(--rc-border-color);opacity:.3}.ReactCrop--no-animate .ReactCrop__crop-selection{outline:1px dashed white}.ReactCrop__crop-selection:not(.ReactCrop--no-animate .ReactCrop__crop-selection){animation:marching-ants 1s;background-image:linear-gradient(to right,#fff 50%,#444 50%),linear-gradient(to right,#fff 50%,#444 50%),linear-gradient(to bottom,#fff 50%,#444 50%),linear-gradient(to bottom,#fff 50%,#444 50%);background-size:10px 1px,10px 1px,1px 10px,1px 10px;background-position:0 0,0 100%,0 0,100% 0;background-repeat:repeat-x,repeat-x,repeat-y,repeat-y;color:#fff;animation-play-state:running;animation-timing-function:linear;animation-iteration-count:infinite}.ReactCrop__crop-selection:focus{outline:2px solid var(--rc-focus-color);outline-offset:-1px}.ReactCrop--invisible-crop .ReactCrop__crop-mask,.ReactCrop--invisible-crop .ReactCrop__crop-selection{display:none}.ReactCrop__rule-of-thirds-vt:before,.ReactCrop__rule-of-thirds-vt:after,.ReactCrop__rule-of-thirds-hz:before,.ReactCrop__rule-of-thirds-hz:after{content:"";display:block;position:absolute;background-color:#fff6}.ReactCrop__rule-of-thirds-vt:before,.ReactCrop__rule-of-thirds-vt:after{width:1px;height:100%}.ReactCrop__rule-of-thirds-vt:before{left:33.3333333333%}.ReactCrop__rule-of-thirds-vt:after{left:66.6666666667%}.ReactCrop__rule-of-thirds-hz:before,.ReactCrop__rule-of-thirds-hz:after{width:100%;height:1px}.ReactCrop__rule-of-thirds-hz:before{top:33.3333333333%}.ReactCrop__rule-of-thirds-hz:after{top:66.6666666667%}.ReactCrop__drag-handle{position:absolute;width:var(--rc-drag-handle-size);height:var(--rc-drag-handle-size);background-color:var(--rc-drag-handle-bg-colour);border:1px solid var(--rc-border-color)}.ReactCrop__drag-handle:focus{background:var(--rc-focus-color)}.ReactCrop .ord-nw{top:0;left:0;transform:translate(-50%,-50%);cursor:nw-resize}.ReactCrop .ord-n{top:0;left:50%;transform:translate(-50%,-50%);cursor:n-resize}.ReactCrop .ord-ne{top:0;right:0;transform:translate(50%,-50%);cursor:ne-resize}.ReactCrop .ord-e{top:50%;right:0;transform:translate(50%,-50%);cursor:e-resize}.ReactCrop .ord-se{bottom:0;right:0;transform:translate(50%,50%);cursor:se-resize}.ReactCrop .ord-s{bottom:0;left:50%;transform:translate(-50%,50%);cursor:s-resize}.ReactCrop .ord-sw{bottom:0;left:0;transform:translate(-50%,50%);cursor:sw-resize}.ReactCrop .ord-w{top:50%;left:0;transform:translate(-50%,-50%);cursor:w-resize}.ReactCrop__disabled .ReactCrop__drag-handle{cursor:inherit}.ReactCrop__drag-bar{position:absolute}.ReactCrop__drag-bar.ord-n{top:0;left:0;width:100%;height:var(--rc-drag-bar-size);transform:translateY(-50%)}.ReactCrop__drag-bar.ord-e{right:0;top:0;width:var(--rc-drag-bar-size);height:100%;transform:translate(50%)}.ReactCrop__drag-bar.ord-s{bottom:0;left:0;width:100%;height:var(--rc-drag-bar-size);transform:translateY(50%)}.ReactCrop__drag-bar.ord-w{top:0;left:0;width:var(--rc-drag-bar-size);height:100%;transform:translate(-50%)}.ReactCrop--new-crop .ReactCrop__drag-bar,.ReactCrop--new-crop .ReactCrop__drag-handle,.ReactCrop--fixed-aspect .ReactCrop__drag-bar,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-n,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-e,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-s,.ReactCrop--fixed-aspect .ReactCrop__drag-handle.ord-w{display:none}@media (pointer: coarse){.ReactCrop .ord-n,.ReactCrop .ord-e,.ReactCrop .ord-s,.ReactCrop .ord-w{display:none}.ReactCrop__drag-handle{width:var(--rc-drag-handle-mobile-size);height:var(--rc-drag-handle-mobile-size)}}*{box-sizing:border-box;margin:0;padding:0;border-radius:2px!important}:root{--bg-color: #f7f7f7;--bg-panel: #ffffff;--text-primary: #111111;--text-secondary: #666666;--border-color: #eeeeee;--accent-color: #2e6ff2;--font-ibm-plex: "IBM Plex Mono", monospace;--font-claude-sans: "Inter", system-ui, sans-serif;--font-wix-display: "Wix Madefor Display", sans-serif;--font-courier-new: "Courier New", Courier, monospace;--radius-sm: 2px;--radius-md: 2px;--bg-opacity: .15;--fg-opacity: 1;--transition-smooth: all .3s cubic-bezier(.16, 1, .3, 1)}html,body{height:100%;width:100%}body{background-color:var(--bg-color);color:var(--text-primary);font-family:var(--font-ibm-plex);overflow:hidden}.font-ibm-plex-mono{font-family:var(--font-ibm-plex)}.font-claudesans{font-family:var(--font-claude-sans)}.font-wixmadefordisplay{font-family:var(--font-wix-display)}.font-couriernew{font-family:var(--font-courier-new)}.app-container{display:flex;height:100vh;width:100vw;position:relative;overflow:hidden}.app-background{position:absolute;top:0;left:0;right:0;bottom:0;background-size:cover;background-position:center;z-index:-1;opacity:var(--bg-opacity)}.mini-sidebar{width:48px;background-color:var(--bg-panel);border-right:1px solid var(--border-color);display:flex;flex-direction:column;align-items:center;padding:12px 0;gap:16px;z-index:10}.sidebar-panel{width:260px;background-color:#ffffffd9;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-right:1px solid var(--border-color);display:flex;flex-direction:column;z-index:10;transition:width .3s ease}.sidebar-header{height:48px;padding:0 16px;display:flex;align-items:center;border-bottom:1px solid var(--border-color);font-weight:500;font-size:14px}.editor-main{flex:1;background-color:transparent;position:relative;display:flex;flex-direction:column;overflow:hidden}.editor-placeholder{display:flex;align-items:center;justify-content:center;height:100%;color:var(--text-secondary)}button{all:unset;cursor:pointer;border-radius:var(--radius-sm);transition:var(--transition-smooth)}.tree-view{padding-bottom:20px}.tree-children{position:relative;transition:all .3s ease}.tree-children:before{content:"";position:absolute;top:0;left:0;bottom:0;width:1px;background-color:#00000008}.tree-item-wrapper{position:relative}.tree-item{transition:background-color .15s ease,border-left .1s ease}.tree-item:hover{background-color:#00000005}.tree-item:hover .more-btn{opacity:.6!important}.tree-item .more-btn:hover{opacity:1!important;background-color:#0000000d}.tree-item.active{background-color:#0000000a!important;font-weight:500}.btn-icon-sm{all:unset;cursor:pointer;padding:4px;border-radius:4px;display:flex;align-items:center;justify-content:center;transition:all .2s ease;color:var(--text-secondary);opacity:.6}.btn-icon-sm:hover{background-color:#0000000d;opacity:1;color:var(--text-primary)}.context-menu button{all:unset;cursor:pointer;font-family:var(--font-ibm-plex)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.spin{animation:spin 1s linear infinite}.pixilize{filter:blur(5px) grayscale(.5);transition:filter .3s ease;-webkit-user-select:none;user-select:none}.pixilize:hover{filter:none}.ContentEditable{flex:1;outline:none;padding:0 24px 100px;font-size:14px;line-height:1.5;color:var(--text-primary);-moz-tab-size:4;tab-size:4;white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word}.editor-paragraph{margin:0;position:relative}.comment-bubble{background:var(--bg-panel);border:1px solid var(--border-color);border-radius:4px;padding:8px 12px;font-size:11px;box-shadow:0 4px 12px #0000000d;margin-bottom:8px;color:var(--text-primary);max-width:250px;line-height:1.4}.comment-toggle{opacity:.1;transition:opacity .2s ease}.tree-item-wrapper:hover .comment-toggle,.line-numbers-container:hover .comment-toggle,.comment-toggle.active{opacity:1}.editor-text-bold{font-weight:700}.editor-text-italic{font-style:italic}.editor-text-strikethrough{text-decoration:line-through}.editor-text-underline{text-decoration:underline}@keyframes fadeInSlide{0%{opacity:0;transform:translateY(-5px)}to{opacity:1;transform:translateY(0)}}
dist/index.html ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <link rel="apple-touch-icon" href="/vite.svg" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
+ <meta name="theme-color" content="#ffffff" />
9
+ <title>Hybrid Editor Docs</title>
10
+ <script type="module" crossorigin src="/assets/index-CEnsgmh2.js"></script>
11
+ <link rel="stylesheet" crossorigin href="/assets/index-OrJvPUH_.css">
12
+ <link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
13
+ <body>
14
+ <div id="root"></div>
15
+ </body>
16
+ </html>
dist/manifest.webmanifest ADDED
@@ -0,0 +1 @@
 
 
1
+ {"name":"Hybrid Editor","short_name":"HyEditor","start_url":"/","display":"standalone","background_color":"#ffffff","theme_color":"#ffffff","lang":"en","scope":"/","icons":[{"src":"/vite.svg","sizes":"192x192","type":"image/svg+xml"}]}
dist/registerSW.js ADDED
@@ -0,0 +1 @@
 
 
1
+ if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})}
dist/sw.js ADDED
@@ -0,0 +1 @@
 
 
1
+ if(!self.define){let e,i={};const s=(s,n)=>(s=new URL(s+".js",n).href,i[s]||new Promise(i=>{if("document"in self){const e=document.createElement("script");e.src=s,e.onload=i,document.head.appendChild(e)}else e=s,importScripts(s),i()}).then(()=>{let e=i[s];if(!e)throw new Error(`Module ${s} didn’t register its module`);return e}));self.define=(n,r)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(i[t])return;let o={};const c=e=>s(e,t),l={module:{uri:t},exports:o,require:c};i[t]=Promise.all(n.map(e=>l[e]||c(e))).then(e=>(r(...e),o))}}define(["./workbox-8c29f6e4"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"4eb96d0de252c344aeb66f921298b735"},{url:"assets/index-OrJvPUH_.css",revision:null},{url:"manifest.webmanifest",revision:"c3985fa8a6595bf51bd1f5acbb440bb5"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
dist/workbox-8c29f6e4.js ADDED
@@ -0,0 +1 @@
 
 
1
+ define(["exports"],function(t){"use strict";try{self["workbox:core:7.3.0"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}try{self["workbox:routing:7.3.0"]&&_()}catch(t){}const n=t=>t&&"object"==typeof t?t:{handle:t};class i{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}setCatchHandler(t){this.catchHandler=n(t)}}class r extends i{constructor(t,e,s){super(({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)},e,s)}}class o{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)})}addCacheListener(){self.addEventListener("message",t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map(e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})}));t.waitUntil(s),t.ports&&t.ports[0]&&s.then(()=>t.ports[0].postMessage(!0))}})}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:i,route:r}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let o=r&&r.handler;const c=t.method;if(!o&&this.i.has(c)&&(o=this.i.get(c)),!o)return;let a;try{a=o.handle({url:s,request:t,event:e,params:i})}catch(t){a=Promise.reject(t)}const h=r&&r.catchHandler;return a instanceof Promise&&(this.o||h)&&(a=a.catch(async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:i})}catch(t){t instanceof Error&&(n=t)}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n})),a}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const i=this.t.get(s.method)||[];for(const r of i){let i;const o=r.match({url:t,sameOrigin:e,request:s,event:n});if(o)return i=o,(Array.isArray(i)&&0===i.length||o.constructor===Object&&0===Object.keys(o).length||"boolean"==typeof o)&&(i=void 0),{route:r,params:i}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}setCatchHandler(t){this.o=n(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-route-but-not-found-with-method",{method:t.method});const e=this.t.get(t.method).indexOf(t);if(!(e>-1))throw new s("unregister-route-route-not-registered");this.t.get(t.method).splice(e,1)}}let c;const a=()=>(c||(c=new o,c.addFetchListener(),c.addCacheListener()),c);function h(t,e,n){let o;if("string"==typeof t){const s=new URL(t,location.href);o=new i(({url:t})=>t.href===s.href,e,n)}else if(t instanceof RegExp)o=new r(t,e,n);else if("function"==typeof t)o=new i(t,e,n);else{if(!(t instanceof i))throw new s("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});o=t}return a().registerRoute(o),o}const u={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},l=t=>[u.prefix,t,u.suffix].filter(t=>t&&t.length>0).join("-"),f=t=>t||l(u.precache),w=t=>t||l(u.runtime);function d(t,e){const s=e();return t.waitUntil(s),s}try{self["workbox:precaching:7.3.0"]&&_()}catch(t){}function p(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const i=new URL(n,location.href),r=new URL(n,location.href);return i.searchParams.set("__WB_REVISION__",e),{cacheKey:i.href,url:r.href}}class y{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:t,state:e})=>{e&&(e.originalRequest=t)},this.cachedResponseWillBeUsed=async({event:t,state:e,cachedResponse:s})=>{if("install"===t.type&&e&&e.originalRequest&&e.originalRequest instanceof Request){const t=e.originalRequest.url;s?this.notUpdatedURLs.push(t):this.updatedURLs.push(t)}return s}}}class g{constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({request:t,params:e})=>{const s=(null==e?void 0:e.cacheKey)||this.h.getCacheKeyForURL(t.url);return s?new Request(s,{headers:t.headers}):t},this.h=t}}let R;async function m(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!==self.location.origin)throw new s("cross-origin-copy-response",{origin:n});const i=t.clone(),r={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=e?e(r):r,c=function(){if(void 0===R){const t=new Response("");if("body"in t)try{new Response(t.body),R=!0}catch(t){R=!1}R=!1}return R}()?i.body:await i.blob();return new Response(c,o)}function v(t,e){const s=new URL(t);for(const t of e)s.searchParams.delete(t);return s.href}class q{constructor(){this.promise=new Promise((t,e)=>{this.resolve=t,this.reject=e})}}const U=new Set;try{self["workbox:strategies:7.3.0"]&&_()}catch(t){}function L(t){return"string"==typeof t?new Request(t):t}class b{constructor(t,e){this.u={},Object.assign(this,e),this.event=e.event,this.l=t,this.p=new q,this.R=[],this.m=[...t.plugins],this.v=new Map;for(const t of this.m)this.v.set(t,{});this.event.waitUntil(this.p.promise)}async fetch(t){const{event:e}=this;let n=L(t);if("navigate"===n.mode&&e instanceof FetchEvent&&e.preloadResponse){const t=await e.preloadResponse;if(t)return t}const i=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:e})}catch(t){if(t instanceof Error)throw new s("plugin-error-request-will-fetch",{thrownErrorMessage:t.message})}const r=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.l.fetchOptions);for(const s of this.iterateCallbacks("fetchDidSucceed"))t=await s({event:e,request:r,response:t});return t}catch(t){throw i&&await this.runCallbacks("fetchDidFail",{error:t,event:e,originalRequest:i.clone(),request:r.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=L(t);let s;const{cacheName:n,matchOptions:i}=this.l,r=await this.getCacheKey(e,"read"),o=Object.assign(Object.assign({},i),{cacheName:n});s=await caches.match(r,o);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:i,cachedResponse:s,request:r,event:this.event})||void 0;return s}async cachePut(t,e){const n=L(t);var i;await(i=0,new Promise(t=>setTimeout(t,i)));const r=await this.getCacheKey(n,"write");if(!e)throw new s("cache-put-with-no-response",{url:(o=r.url,new URL(String(o),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var o;const c=await this.q(e);if(!c)return!1;const{cacheName:a,matchOptions:h}=this.l,u=await self.caches.open(a),l=this.hasCallback("cacheDidUpdate"),f=l?await async function(t,e,s,n){const i=v(e.url,s);if(e.url===i)return t.match(e,n);const r=Object.assign(Object.assign({},n),{ignoreSearch:!0}),o=await t.keys(e,r);for(const e of o)if(i===v(e.url,s))return t.match(e,n)}(u,r.clone(),["__WB_REVISION__"],h):null;try{await u.put(r,l?c.clone():c)}catch(t){if(t instanceof Error)throw"QuotaExceededError"===t.name&&await async function(){for(const t of U)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:a,oldResponse:f,newResponse:c.clone(),request:r,event:this.event});return!0}async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.u[s]){let n=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))n=L(await t({mode:e,request:n,event:this.event,params:this.params}));this.u[s]=n}return this.u[s]}hasCallback(t){for(const e of this.l.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.l.plugins)if("function"==typeof e[t]){const s=this.v.get(e),n=n=>{const i=Object.assign(Object.assign({},n),{state:s});return e[t](i)};yield n}}waitUntil(t){return this.R.push(t),t}async doneWaiting(){for(;this.R.length;){const t=this.R.splice(0),e=(await Promise.allSettled(t)).find(t=>"rejected"===t.status);if(e)throw e.reason}}destroy(){this.p.resolve(null)}async q(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class C{constructor(t={}){this.cacheName=w(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,i=new b(this,{event:e,request:s,params:n}),r=this.U(i,s,e);return[r,this.L(r,i,s,e)]}async U(t,e,n){let i;await t.runCallbacks("handlerWillStart",{event:n,request:e});try{if(i=await this._(e,t),!i||"error"===i.type)throw new s("no-response",{url:e.url})}catch(s){if(s instanceof Error)for(const r of t.iterateCallbacks("handlerDidError"))if(i=await r({error:s,event:n,request:e}),i)break;if(!i)throw s}for(const s of t.iterateCallbacks("handlerWillRespond"))i=await s({event:n,request:e,response:i});return i}async L(t,e,s,n){let i,r;try{i=await t}catch(r){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:i}),await e.doneWaiting()}catch(t){t instanceof Error&&(r=t)}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:i,error:r}),e.destroy(),r)throw r}}class E extends C{constructor(t={}){t.cacheName=f(t.cacheName),super(t),this.C=!1!==t.fallbackToNetwork,this.plugins.push(E.copyRedirectedCacheableResponsesPlugin)}async _(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"install"===e.event.type?await this.O(t,e):await this.N(t,e))}async N(t,e){let n;const i=e.params||{};if(!this.C)throw new s("missing-precache-entry",{cacheName:this.cacheName,url:t.url});{const s=i.integrity,r=t.integrity,o=!r||r===s;n=await e.fetch(new Request(t,{integrity:"no-cors"!==t.mode?r||s:void 0})),s&&o&&"no-cors"!==t.mode&&(this.P(),await e.cachePut(t,n.clone()))}return n}async O(t,e){this.P();const n=await e.fetch(t);if(!await e.cachePut(t,n.clone()))throw new s("bad-precaching-response",{url:t.url,status:n.status});return n}P(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==E.copyRedirectedCacheableResponsesPlugin&&(n===E.defaultPrecacheCacheabilityPlugin&&(t=s),n.cacheWillUpdate&&e++);0===e?this.plugins.push(E.defaultPrecacheCacheabilityPlugin):e>1&&null!==t&&this.plugins.splice(t,1)}}E.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:t})=>!t||t.status>=400?null:t},E.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:t})=>t.redirected?await m(t):t};class O{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this.j=new Map,this.k=new Map,this.K=new Map,this.l=new E({cacheName:f(t),plugins:[...e,new g({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this.l}precache(t){this.addToCacheList(t),this.T||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this.T=!0)}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:i}=p(n),r="string"!=typeof n&&n.revision?"reload":"default";if(this.j.has(i)&&this.j.get(i)!==t)throw new s("add-to-cache-list-conflicting-entries",{firstEntry:this.j.get(i),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.K.has(t)&&this.K.get(t)!==n.integrity)throw new s("add-to-cache-list-conflicting-integrities",{url:i});this.K.set(t,n.integrity)}if(this.j.set(i,t),this.k.set(i,r),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}install(t){return d(t,async()=>{const e=new y;this.strategy.plugins.push(e);for(const[e,s]of this.j){const n=this.K.get(s),i=this.k.get(e),r=new Request(e,{integrity:n,cache:i,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:r,event:t}))}const{updatedURLs:s,notUpdatedURLs:n}=e;return{updatedURLs:s,notUpdatedURLs:n}})}activate(t){return d(t,async()=>{const t=await self.caches.open(this.strategy.cacheName),e=await t.keys(),s=new Set(this.j.values()),n=[];for(const i of e)s.has(i.url)||(await t.delete(i),n.push(i.url));return{deletedURLs:n}})}getURLsToCacheKeys(){return this.j}getCachedURLs(){return[...this.j.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.j.get(e.href)}getIntegrityForCacheKey(t){return this.K.get(t)}async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.getCacheKeyForURL(e);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)throw new s("non-precached-url",{url:t});return s=>(s.request=new Request(t),s.params=Object.assign({cacheKey:e},s.params),this.strategy.handle(s))}}let x;const N=()=>(x||(x=new O),x);class P extends i{constructor(t,e){super(({request:s})=>{const n=t.getURLsToCacheKeys();for(const i of function*(t,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:n=!0,urlManipulation:i}={}){const r=new URL(t,location.href);r.hash="",yield r.href;const o=function(t,e=[]){for(const s of[...t.searchParams.keys()])e.some(t=>t.test(s))&&t.searchParams.delete(s);return t}(r,e);if(yield o.href,s&&o.pathname.endsWith("/")){const t=new URL(o.href);t.pathname+=s,yield t.href}if(n){const t=new URL(o.href);t.pathname+=".html",yield t.href}if(i){const t=i({url:r});for(const e of t)yield e.href}}(s.url,e)){const e=n.get(i);if(e){return{cacheKey:e,integrity:t.getIntegrityForCacheKey(e)}}}},t.strategy)}}t.NavigationRoute=class extends i{constructor(t,{allowlist:e=[/./],denylist:s=[]}={}){super(t=>this.W(t),t),this.M=e,this.S=s}W({url:t,request:e}){if(e&&"navigate"!==e.mode)return!1;const s=t.pathname+t.search;for(const t of this.S)if(t.test(s))return!1;return!!this.M.some(t=>t.test(s))}},t.cleanupOutdatedCaches=function(){self.addEventListener("activate",t=>{const e=f();t.waitUntil((async(t,e="-precache-")=>{const s=(await self.caches.keys()).filter(s=>s.includes(e)&&s.includes(self.registration.scope)&&s!==t);return await Promise.all(s.map(t=>self.caches.delete(t))),s})(e).then(t=>{}))})},t.clientsClaim=function(){self.addEventListener("activate",()=>self.clients.claim())},t.createHandlerBoundToURL=function(t){return N().createHandlerBoundToURL(t)},t.precacheAndRoute=function(t,e){!function(t){N().precache(t)}(t),function(t){const e=N();h(new P(e,t))}(e)},t.registerRoute=h});
index.html ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <link rel="apple-touch-icon" href="/vite.svg" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
+ <meta name="theme-color" content="#ffffff" />
9
+ <title>Hybrid Editor Docs</title>
10
+ </head>
11
+ <body>
12
+ <div id="root"></div>
13
+ <script type="module" src="/src/main.tsx"></script>
14
+ </body>
15
+ </html>
keys.txt ADDED
@@ -0,0 +1,4572 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ use hugeicons react icons for all buttons and UI designs by simply using a search-tool in this file, no need to lunch browsers because this file contain all react icons to use.
3
+ ---
4
+
5
+ use this react icons at https://hugeicons.com/ simply by:
6
+
7
+ `npm install @hugeicons/react @hugeicons/core-free-icons`
8
+ `<HugeiconsIcon icon={} />`
9
+
10
+ and using the icon_name icon names: {
11
+
12
+ FirstBracketCircleIcon
13
+ FirstBracketSquareIcon
14
+ FirstBracketIcon
15
+ SecondBracketCircleIcon
16
+ SecondBracketSquareIcon
17
+ SecondBracketIcon
18
+ ThreeDViewIcon
19
+ ThreeDMoveIcon
20
+ ThreeDPrinterIcon
21
+ ThreeDRotateIcon
22
+ ThreeDScaleIcon
23
+ ThirdBracketCircleIcon
24
+ ThirdBracketSquareIcon
25
+ ThirdBracketIcon
26
+ FourKIcon
27
+ SevenZ01Icon
28
+ SevenZ02Icon
29
+ AbacusIcon
30
+ AbsoluteIcon
31
+ AccelerationIcon
32
+ AccessIcon
33
+ AccidentIcon
34
+ AccountSetting01Icon
35
+ AccountSetting02Icon
36
+ AccountSetting03Icon
37
+ Activity01Icon
38
+ Activity02Icon
39
+ Activity03Icon
40
+ Activity04Icon
41
+ AcuteIcon
42
+ Add01Icon
43
+ Add02Icon
44
+ AddCircleHalfDotIcon
45
+ AddCircleIcon
46
+ AddFemaleIcon
47
+ AddInvoiceIcon
48
+ AddMaleIcon
49
+ AddMoneyCircleIcon
50
+ AddSquareIcon
51
+ AddTeam02Icon
52
+ AddTeamIcon
53
+ AddToListIcon
54
+ AddressBookIcon
55
+ AdobeAfterEffectIcon
56
+ AdobeIllustratorIcon
57
+ AdobeIndesignIcon
58
+ AdobePhotoshopIcon
59
+ AdobePremierIcon
60
+ AdobeXdIcon
61
+ AdventureIcon
62
+ AdvertisimentIcon
63
+ AdzanIcon
64
+ AffiliateIcon
65
+ Agreement01Icon
66
+ Agreement02Icon
67
+ Agreement03Icon
68
+ AiAudioIcon
69
+ AiBeautifyIcon
70
+ AiBookIcon
71
+ AiBrain01Icon
72
+ AiBrain02Icon
73
+ AiBrain03Icon
74
+ AiBrain04Icon
75
+ AiBrain05Icon
76
+ AiBrowserIcon
77
+ AiChat01Icon
78
+ AiChat02Icon
79
+ AiChemistry01Icon
80
+ AiChemistry02Icon
81
+ AiChemistry03Icon
82
+ AiChipIcon
83
+ AiCloud01Icon
84
+ AiCloud02Icon
85
+ AiCloudIcon
86
+ AiComputerIcon
87
+ AiContentGenerator01Icon
88
+ AiContentGenerator02Icon
89
+ AiDnaIcon
90
+ AiEditingIcon
91
+ AiEraserIcon
92
+ AiFileIcon
93
+ AiFolder01Icon
94
+ AiFolder02Icon
95
+ AiGameIcon
96
+ AiGenerativeIcon
97
+ AiIdeaIcon
98
+ AiImageIcon
99
+ AiInnovation01Icon
100
+ AiInnovation02Icon
101
+ AiInnovation03Icon
102
+ AiLaptopIcon
103
+ AiLearningIcon
104
+ AiLockIcon
105
+ AiMagicIcon
106
+ AiMail01Icon
107
+ AiMail02Icon
108
+ AiMailIcon
109
+ AiMicIcon
110
+ AiNetworkIcon
111
+ AiPhone01Icon
112
+ AiPhone02Icon
113
+ AiProgrammingIcon
114
+ AiScanIcon
115
+ AiSchedulingIcon
116
+ AiSearch02Icon
117
+ AiSearchIcon
118
+ AiSecurity01Icon
119
+ AiSecurity02Icon
120
+ AiSecurity03Icon
121
+ AiSettingIcon
122
+ AiSheetsIcon
123
+ AiSmartwatchIcon
124
+ AiUserIcon
125
+ AiVideoIcon
126
+ AiViewIcon
127
+ AiVisionRecognitionIcon
128
+ AiVoiceGeneratorIcon
129
+ AiVoiceIcon
130
+ AiWebBrowsingIcon
131
+ AidsIcon
132
+ AirbnbIcon
133
+ AircraftGameIcon
134
+ AirdropIcon
135
+ Airplane01Icon
136
+ Airplane02Icon
137
+ AirplaneLanding01Icon
138
+ AirplaneLanding02Icon
139
+ AirplaneModeOffIcon
140
+ AirplaneModeIcon
141
+ AirplaneSeat02Icon
142
+ AirplaneSeatIcon
143
+ AirplaneTakeOff01Icon
144
+ AirplaneTakeOff02Icon
145
+ AirplayLineIcon
146
+ Airpod01Icon
147
+ Airpod02Icon
148
+ Airpod03Icon
149
+ AirportIcon
150
+ AlAqsaMosqueIcon
151
+ AlarmClockIcon
152
+ Album01Icon
153
+ Album02Icon
154
+ AlbumNotFound01Icon
155
+ AlbumNotFound02Icon
156
+ Alert01Icon
157
+ Alert02Icon
158
+ AlertCircleIcon
159
+ AlertDiamondIcon
160
+ AlertSquareIcon
161
+ AlgorithmIcon
162
+ Alien01Icon
163
+ Alien02Icon
164
+ AlignBottomIcon
165
+ AlignBoxBottomCenterIcon
166
+ AlignBoxBottomLeftIcon
167
+ AlignBoxBottomRightIcon
168
+ AlignBoxMiddleCenterIcon
169
+ AlignBoxMiddleLeftIcon
170
+ AlignBoxMiddleRightIcon
171
+ AlignBoxTopCenterIcon
172
+ AlignBoxTopLeftIcon
173
+ AlignBoxTopRightIcon
174
+ AlignHorizontalCenterIcon
175
+ AlignKeyObjectIcon
176
+ AlignLeftIcon
177
+ AlignRightIcon
178
+ AlignSelectionIcon
179
+ AlignTopIcon
180
+ AlignVerticalCenterIcon
181
+ AllBookmarkIcon
182
+ AllahIcon
183
+ AlmsIcon
184
+ AlphaCircleIcon
185
+ AlphaSquareIcon
186
+ AlphaIcon
187
+ AlphabetArabicIcon
188
+ AlphabetBanglaIcon
189
+ AlphabetChineseIcon
190
+ AlphabetGreekIcon
191
+ AlphabetHebrewIcon
192
+ AlphabetHindiIcon
193
+ AlphabetJapaneseIcon
194
+ AlphabetKoreanIcon
195
+ AlphabetThaiIcon
196
+ AmazonIcon
197
+ AmbulanceIcon
198
+ AmericanFootballIcon
199
+ AmieIcon
200
+ AmmoIcon
201
+ AmpouleIcon
202
+ AnalysisTextLinkIcon
203
+ Analytics01Icon
204
+ Analytics02Icon
205
+ Analytics03Icon
206
+ AnalyticsDownIcon
207
+ AnalyticsUpIcon
208
+ AnchorPointIcon
209
+ AnchorIcon
210
+ AndroidIcon
211
+ AngelIcon
212
+ Angle01Icon
213
+ AngleIcon
214
+ AngryBirdIcon
215
+ AngryIcon
216
+ AnonymousIcon
217
+ ApiIcon
218
+ AppStoreIcon
219
+ Apple01Icon
220
+ AppleFinderIcon
221
+ AppleIntelligenceIcon
222
+ AppleNewsIcon
223
+ ApplePieIcon
224
+ AppleReminderIcon
225
+ AppleStocksIcon
226
+ AppleIcon
227
+ AppleVisionProIcon
228
+ Appointment01Icon
229
+ Appointment02Icon
230
+ ApproximatelyEqualCircleIcon
231
+ ApproximatelyEqualSquareIcon
232
+ ApproximatelyEqualIcon
233
+ ApricotIcon
234
+ ApronIcon
235
+ ArcBrowserIcon
236
+ ArcherIcon
237
+ Archive01Icon
238
+ Archive02Icon
239
+ Archive03Icon
240
+ Archive04Icon
241
+ ArchiveArrowDownIcon
242
+ ArchiveArrowUpIcon
243
+ ArchiveOff03Icon
244
+ ArchiveOff04Icon
245
+ ArchiveIcon
246
+ ArmoredBootIcon
247
+ ArrangeByLettersAZIcon
248
+ ArrangeByLettersZAIcon
249
+ ArrangeByNumbers19Icon
250
+ ArrangeByNumbers91Icon
251
+ ArrangeIcon
252
+ ArrowAllDirectionIcon
253
+ ArrowDataTransferDiagonalIcon
254
+ ArrowDataTransferHorizontalIcon
255
+ ArrowDataTransferVerticalIcon
256
+ ArrowDiagonalIcon
257
+ ArrowDown01Icon
258
+ ArrowDown02Icon
259
+ ArrowDown03Icon
260
+ ArrowDown04Icon
261
+ ArrowDown05Icon
262
+ ArrowDownDoubleIcon
263
+ ArrowDownLeft01Icon
264
+ ArrowDownLeft02Icon
265
+ ArrowDownRight01Icon
266
+ ArrowDownRight02Icon
267
+ ArrowExpand01Icon
268
+ ArrowExpand02Icon
269
+ ArrowExpandDiagonal01Icon
270
+ ArrowExpandDiagonal02Icon
271
+ ArrowExpandIcon
272
+ ArrowHorizontalIcon
273
+ ArrowLeft01Icon
274
+ ArrowLeft02Icon
275
+ ArrowLeft03Icon
276
+ ArrowLeft04Icon
277
+ ArrowLeft05Icon
278
+ ArrowLeftDoubleIcon
279
+ ArrowLeftRightIcon
280
+ ArrowMoveDownLeftIcon
281
+ ArrowMoveDownRightIcon
282
+ ArrowMoveLeftDownIcon
283
+ ArrowMoveRightDownIcon
284
+ ArrowMoveUpLeftIcon
285
+ ArrowMoveUpRightIcon
286
+ ArrowReloadHorizontalIcon
287
+ ArrowReloadVerticalIcon
288
+ ArrowRight01Icon
289
+ ArrowRight02Icon
290
+ ArrowRight03Icon
291
+ ArrowRight04Icon
292
+ ArrowRight05Icon
293
+ ArrowRightDoubleIcon
294
+ ArrowShrink01Icon
295
+ ArrowShrink02Icon
296
+ ArrowShrinkIcon
297
+ ArrowTurnBackwardIcon
298
+ ArrowTurnDownIcon
299
+ ArrowTurnForwardIcon
300
+ ArrowTurnUpIcon
301
+ ArrowUp01Icon
302
+ ArrowUp02Icon
303
+ ArrowUp03Icon
304
+ ArrowUp04Icon
305
+ ArrowUp05Icon
306
+ ArrowUpDoubleIcon
307
+ ArrowUpDownIcon
308
+ ArrowUpLeft01Icon
309
+ ArrowUpLeft02Icon
310
+ ArrowUpRight01Icon
311
+ ArrowUpRight02Icon
312
+ ArrowUpRight03Icon
313
+ ArrowVerticalIcon
314
+ ArtboardIcon
315
+ ArtboardToolIcon
316
+ ArtificialIntelligence01Icon
317
+ ArtificialIntelligence02Icon
318
+ ArtificialIntelligence03Icon
319
+ ArtificialIntelligence04Icon
320
+ ArtificialIntelligence05Icon
321
+ ArtificialIntelligence06Icon
322
+ ArtificialIntelligence07Icon
323
+ ArtificialIntelligence08Icon
324
+ AspectRatioIcon
325
+ AssignmentsIcon
326
+ Asterisk02Icon
327
+ AsteriskIcon
328
+ Asteroid01Icon
329
+ Asteroid02Icon
330
+ Astronaut01Icon
331
+ Astronaut02Icon
332
+ AtIcon
333
+ Atm01Icon
334
+ Atm02Icon
335
+ Atom01Icon
336
+ Atom02Icon
337
+ AtomicPowerIcon
338
+ Attachment01Icon
339
+ Attachment02Icon
340
+ AttachmentCircleIcon
341
+ AttachmentSquareIcon
342
+ AttachmentIcon
343
+ AuctionIcon
344
+ AudioBook01Icon
345
+ AudioBook02Icon
346
+ AudioBook03Icon
347
+ AudioBook04Icon
348
+ AudioWave01Icon
349
+ AudioWave02Icon
350
+ Audit01Icon
351
+ Audit02Icon
352
+ AugmentedRealityArIcon
353
+ AuthorizedIcon
354
+ AutoConversationsIcon
355
+ AutomotiveBattery01Icon
356
+ AutomotiveBattery02Icon
357
+ AvalancheIcon
358
+ AvocadoIcon
359
+ Award01Icon
360
+ Award02Icon
361
+ Award03Icon
362
+ Award04Icon
363
+ Award05Icon
364
+ Baby01Icon
365
+ Baby02Icon
366
+ BabyBed01Icon
367
+ BabyBed02Icon
368
+ BabyBottleIcon
369
+ BabyBoyDressIcon
370
+ BabyGirlDressIcon
371
+ BackMuscleBodyIcon
372
+ BackgroundIcon
373
+ Backpack01Icon
374
+ Backpack02Icon
375
+ Backpack03Icon
376
+ Backward01Icon
377
+ Backward02Icon
378
+ BacteriaIcon
379
+ BadmintonShuttleIcon
380
+ BadmintonIcon
381
+ BalanceScaleIcon
382
+ BalloonsIcon
383
+ BananaIcon
384
+ BandageIcon
385
+ BankIcon
386
+ BarChartHorizontalIcon
387
+ BarChartIcon
388
+ BarCode01Icon
389
+ BarCode02Icon
390
+ BarnsIcon
391
+ BaseballBatIcon
392
+ BaseballHelmetIcon
393
+ BaseballIcon
394
+ BashIcon
395
+ Basketball01Icon
396
+ Basketball02Icon
397
+ BasketballHoopIcon
398
+ Bathtub01Icon
399
+ Bathtub02Icon
400
+ BatteriesEnergyIcon
401
+ BatteryCharging01Icon
402
+ BatteryCharging02Icon
403
+ BatteryEcoChargingIcon
404
+ BatteryEmptyIcon
405
+ BatteryFullIcon
406
+ BatteryLowIcon
407
+ BatteryMedium01Icon
408
+ BatteryMedium02Icon
409
+ BbqGrillIcon
410
+ Beach02Icon
411
+ BeachIcon
412
+ BeaterIcon
413
+ BeboIcon
414
+ BedBunkIcon
415
+ BedDoubleIcon
416
+ BedSingle01Icon
417
+ BedSingle02Icon
418
+ BedIcon
419
+ Bedug01Icon
420
+ Bedug02Icon
421
+ Behance01Icon
422
+ Behance02Icon
423
+ BeltIcon
424
+ BendToolIcon
425
+ BerlinIcon
426
+ BerlinTowerIcon
427
+ BetaIcon
428
+ Bicycle01Icon
429
+ BicycleIcon
430
+ Billiard01Icon
431
+ Billiard02Icon
432
+ BinaryCodeIcon
433
+ BingIcon
434
+ BinocularsIcon
435
+ BioEnergyIcon
436
+ BiomassEnergyIcon
437
+ BiometricAccessIcon
438
+ BiometricDeviceIcon
439
+ BirthdayCakeIcon
440
+ BiscuitIcon
441
+ Bitcoin01Icon
442
+ Bitcoin02Icon
443
+ Bitcoin03Icon
444
+ Bitcoin04Icon
445
+ BitcoinBagIcon
446
+ BitcoinCircleIcon
447
+ BitcoinCloudIcon
448
+ BitcoinCpuIcon
449
+ BitcoinCreditCardIcon
450
+ BitcoinDatabaseIcon
451
+ BitcoinDown01Icon
452
+ BitcoinDown02Icon
453
+ BitcoinEllipseIcon
454
+ BitcoinEyeIcon
455
+ BitcoinFilterIcon
456
+ BitcoinFlashdiskIcon
457
+ BitcoinGraphIcon
458
+ BitcoinInvoiceIcon
459
+ BitcoinKeyIcon
460
+ BitcoinLocationIcon
461
+ BitcoinLockIcon
462
+ BitcoinMailIcon
463
+ BitcoinMindIcon
464
+ BitcoinMoney01Icon
465
+ BitcoinMoney02Icon
466
+ BitcoinPieChartIcon
467
+ BitcoinPiggyBankIcon
468
+ BitcoinPresentationIcon
469
+ BitcoinReceiptIcon
470
+ BitcoinReceiveIcon
471
+ BitcoinRectangleIcon
472
+ BitcoinSafeIcon
473
+ BitcoinSearchIcon
474
+ BitcoinSendIcon
475
+ BitcoinSettingIcon
476
+ BitcoinShieldIcon
477
+ BitcoinShoppingIcon
478
+ BitcoinSmartphone01Icon
479
+ BitcoinSmartphone02Icon
480
+ BitcoinSquareIcon
481
+ BitcoinStoreIcon
482
+ BitcoinIcon
483
+ BitcoinTagIcon
484
+ BitcoinTargetIcon
485
+ BitcoinTransactionIcon
486
+ BitcoinUp01Icon
487
+ BitcoinUp02Icon
488
+ BitcoinWalletIcon
489
+ BitcoinWithdrawIcon
490
+ BlackHole01Icon
491
+ BlackHoleIcon
492
+ BlendIcon
493
+ BlenderIcon
494
+ BlockGameIcon
495
+ Blockchain01Icon
496
+ Blockchain02Icon
497
+ Blockchain03Icon
498
+ Blockchain04Icon
499
+ Blockchain05Icon
500
+ Blockchain06Icon
501
+ Blockchain07Icon
502
+ BlockedIcon
503
+ BloggerIcon
504
+ BloodBagIcon
505
+ BloodBottleIcon
506
+ BloodPressureIcon
507
+ BloodIcon
508
+ BloodTypeIcon
509
+ BlueskyIcon
510
+ BluetoothCircleIcon
511
+ BluetoothNotConnectedIcon
512
+ BluetoothSearchIcon
513
+ BluetoothSquareIcon
514
+ BluetoothIcon
515
+ BlurIcon
516
+ BlushBrush01Icon
517
+ BlushBrush02Icon
518
+ BoardMathIcon
519
+ BoatIcon
520
+ BodyArmorIcon
521
+ BodyPartLegIcon
522
+ BodyPartMuscleIcon
523
+ BodyPartSixPackIcon
524
+ BodySoapIcon
525
+ BodyWeightIcon
526
+ BombIcon
527
+ Bone01Icon
528
+ Bone02Icon
529
+ Book01Icon
530
+ Book02Icon
531
+ Book03Icon
532
+ Book04Icon
533
+ BookBookmark01Icon
534
+ BookBookmark02Icon
535
+ BookDownloadIcon
536
+ BookEditIcon
537
+ BookOpen01Icon
538
+ BookOpen02Icon
539
+ BookUploadIcon
540
+ Bookmark01Icon
541
+ Bookmark02Icon
542
+ Bookmark03Icon
543
+ BookmarkAdd01Icon
544
+ BookmarkAdd02Icon
545
+ BookmarkBlock01Icon
546
+ BookmarkBlock02Icon
547
+ BookmarkCheck01Icon
548
+ BookmarkCheck02Icon
549
+ BookmarkMinus01Icon
550
+ BookmarkMinus02Icon
551
+ BookmarkOff01Icon
552
+ BookmarkOff02Icon
553
+ BookmarkRemove01Icon
554
+ BookmarkRemove02Icon
555
+ Books01Icon
556
+ Books02Icon
557
+ Bookshelf01Icon
558
+ Bookshelf02Icon
559
+ Bookshelf03Icon
560
+ BootstrapIcon
561
+ BorderAll01Icon
562
+ BorderAll02Icon
563
+ BorderBottom01Icon
564
+ BorderBottom02Icon
565
+ BorderFullIcon
566
+ BorderHorizontalIcon
567
+ BorderInnerIcon
568
+ BorderLeft01Icon
569
+ BorderLeft02Icon
570
+ BorderNone01Icon
571
+ BorderNone02Icon
572
+ BorderRight01Icon
573
+ BorderRight02Icon
574
+ BorderTop01Icon
575
+ BorderTop02Icon
576
+ BorderVerticalIcon
577
+ BorobudurIcon
578
+ BotIcon
579
+ BounceLeftIcon
580
+ BounceRightIcon
581
+ BoundingBoxIcon
582
+ BowTieIcon
583
+ BowlingBallIcon
584
+ BowlingPinsIcon
585
+ BowlingIcon
586
+ BoxerIcon
587
+ BoxingBagIcon
588
+ BoxingGlove01Icon
589
+ BoxingGloveIcon
590
+ Brain01Icon
591
+ Brain02Icon
592
+ Brain03Icon
593
+ BrainIcon
594
+ BrandfetchIcon
595
+ Bread01Icon
596
+ Bread02Icon
597
+ Bread03Icon
598
+ Bread04Icon
599
+ BreastPumpIcon
600
+ BridgeIcon
601
+ Briefcase01Icon
602
+ Briefcase02Icon
603
+ Briefcase03Icon
604
+ Briefcase04Icon
605
+ Briefcase05Icon
606
+ Briefcase06Icon
607
+ Briefcase07Icon
608
+ Briefcase08Icon
609
+ Briefcase09Icon
610
+ BriefcaseDollarIcon
611
+ BroccoliIcon
612
+ BrochureIcon
613
+ BrokenBoneIcon
614
+ BrowserIcon
615
+ BrushIcon
616
+ BubbleChatAddIcon
617
+ BubbleChatBlockedIcon
618
+ BubbleChatCancelIcon
619
+ BubbleChatDelayIcon
620
+ BubbleChatDoneIcon
621
+ BubbleChatDownload01Icon
622
+ BubbleChatDownload02Icon
623
+ BubbleChatEditIcon
624
+ BubbleChatFavouriteIcon
625
+ BubbleChatIncomeIcon
626
+ BubbleChatLockIcon
627
+ BubbleChatNotificationIcon
628
+ BubbleChatOutcomeIcon
629
+ BubbleChatPreviewIcon
630
+ BubbleChatQuestionIcon
631
+ BubbleChatSearchIcon
632
+ BubbleChatSecureIcon
633
+ BubbleChatSpark01Icon
634
+ BubbleChatSparkIcon
635
+ BubbleChatIcon
636
+ BubbleChatTemporaryIcon
637
+ BubbleChatTranslateIcon
638
+ BubbleChatUnlockIcon
639
+ BubbleChatUploadIcon
640
+ BubbleChatUserIcon
641
+ BubbleTea01Icon
642
+ BubbleTea02Icon
643
+ Bug01Icon
644
+ Bug02Icon
645
+ Building01Icon
646
+ Building02Icon
647
+ Building03Icon
648
+ Building04Icon
649
+ Building05Icon
650
+ Building06Icon
651
+ BulbChargingIcon
652
+ BulbIcon
653
+ BulletIcon
654
+ BulletproofVestIcon
655
+ BurjAlArabIcon
656
+ BurningCdIcon
657
+ Bus01Icon
658
+ Bus02Icon
659
+ Bus03Icon
660
+ CIcon
661
+ CProgrammingIcon
662
+ Cabinet01Icon
663
+ Cabinet02Icon
664
+ Cabinet03Icon
665
+ Cabinet04Icon
666
+ CableCarIcon
667
+ CactusIcon
668
+ CaduceusIcon
669
+ CafeIcon
670
+ CalculateIcon
671
+ Calculator01Icon
672
+ CalculatorIcon
673
+ Calendar01Icon
674
+ Calendar02Icon
675
+ Calendar03Icon
676
+ Calendar04Icon
677
+ CalendarAdd01Icon
678
+ CalendarAdd02Icon
679
+ CalendarBlock01Icon
680
+ CalendarBlock02Icon
681
+ CalendarCheckIn01Icon
682
+ CalendarCheckIn02Icon
683
+ CalendarCheckOut01Icon
684
+ CalendarCheckOut02Icon
685
+ CalendarDownload01Icon
686
+ CalendarDownload02Icon
687
+ CalendarFavorite01Icon
688
+ CalendarFavorite02Icon
689
+ CalendarLock01Icon
690
+ CalendarLock02Icon
691
+ CalendarLove01Icon
692
+ CalendarLove02Icon
693
+ CalendarMinus01Icon
694
+ CalendarMinus02Icon
695
+ CalendarRemove01Icon
696
+ CalendarRemove02Icon
697
+ CalendarSetting01Icon
698
+ CalendarSetting02Icon
699
+ CalendarUpload01Icon
700
+ CalendarUpload02Icon
701
+ CalendarUserIcon
702
+ Call02Icon
703
+ CallAdd02Icon
704
+ CallAddIcon
705
+ CallBlocked02Icon
706
+ CallBlockedIcon
707
+ CallDisabled02Icon
708
+ CallDisabledIcon
709
+ CallDone02Icon
710
+ CallDoneIcon
711
+ CallEnd01Icon
712
+ CallEnd02Icon
713
+ CallEnd03Icon
714
+ CallEnd04Icon
715
+ CallIncoming01Icon
716
+ CallIncoming02Icon
717
+ CallIncoming03Icon
718
+ CallIncoming04Icon
719
+ CallInternal02Icon
720
+ CallInternalIcon
721
+ CallLocked02Icon
722
+ CallLockedIcon
723
+ CallMinus02Icon
724
+ CallMinusIcon
725
+ CallMissed01Icon
726
+ CallMissed02Icon
727
+ CallMissed03Icon
728
+ CallMissed04Icon
729
+ CallOutgoing01Icon
730
+ CallOutgoing02Icon
731
+ CallOutgoing03Icon
732
+ CallOutgoing04Icon
733
+ CallPaused02Icon
734
+ CallPausedIcon
735
+ CallReceived02Icon
736
+ CallReceivedIcon
737
+ CallRinging01Icon
738
+ CallRinging02Icon
739
+ CallRinging03Icon
740
+ CallRinging04Icon
741
+ CallIcon
742
+ CallUnlocked02Icon
743
+ CallUnlockedIcon
744
+ Calling02Icon
745
+ CallingIcon
746
+ CamelIcon
747
+ Camera01Icon
748
+ Camera02Icon
749
+ Camera03Icon
750
+ CameraAdd01Icon
751
+ CameraAdd02Icon
752
+ CameraAdd03Icon
753
+ CameraAiIcon
754
+ CameraAutomatically01Icon
755
+ CameraAutomatically02Icon
756
+ CameraLensIcon
757
+ CameraMicrophone01Icon
758
+ CameraMicrophone02Icon
759
+ CameraNightMode01Icon
760
+ CameraNightMode02Icon
761
+ CameraOff01Icon
762
+ CameraOff02Icon
763
+ CameraRotated01Icon
764
+ CameraRotated02Icon
765
+ CameraSmile01Icon
766
+ CameraSmile02Icon
767
+ CameraTripodIcon
768
+ CameraVideoIcon
769
+ CamperIcon
770
+ CampfireIcon
771
+ Cancel01Icon
772
+ Cancel02Icon
773
+ CancelCircleHalfDotIcon
774
+ CancelCircleIcon
775
+ CancelSquareIcon
776
+ Candelier01Icon
777
+ Candelier02Icon
778
+ CanvasIcon
779
+ CapProjectingIcon
780
+ CapRoundIcon
781
+ CapStraightIcon
782
+ CapIcon
783
+ CapcutRectangleIcon
784
+ CapcutIcon
785
+ Car01Icon
786
+ Car02Icon
787
+ Car03Icon
788
+ Car04Icon
789
+ Car05Icon
790
+ CarAlertIcon
791
+ CarParking01Icon
792
+ CarParking02Icon
793
+ CarSignalIcon
794
+ CarTimeIcon
795
+ CaravanIcon
796
+ CardExchange01Icon
797
+ CardExchange02Icon
798
+ CardiganIcon
799
+ Cardiogram01Icon
800
+ Cardiogram02Icon
801
+ Cards01Icon
802
+ Cards02Icon
803
+ CargoShipIcon
804
+ CarouselHorizontal02Icon
805
+ CarouselHorizontalIcon
806
+ CarouselVerticalIcon
807
+ CarrotIcon
808
+ Cash01Icon
809
+ Cash02Icon
810
+ CashbackBitcoinIcon
811
+ CashbackEuroIcon
812
+ CashbackPoundIcon
813
+ CashbackIcon
814
+ CashbackYenIcon
815
+ Cashier02Icon
816
+ CashierIcon
817
+ CastboxIcon
818
+ Castle01Icon
819
+ Castle02Icon
820
+ CastleIcon
821
+ CatalogueIcon
822
+ CayanTowerIcon
823
+ CctvCameraIcon
824
+ CdIcon
825
+ CellsIcon
826
+ CellularNetworkOfflineIcon
827
+ CellularNetworkIcon
828
+ CelsiusIcon
829
+ CenterFocusIcon
830
+ CentralShaheedMinarIcon
831
+ CentralizedIcon
832
+ Certificate01Icon
833
+ Certificate02Icon
834
+ Chair01Icon
835
+ Chair02Icon
836
+ Chair03Icon
837
+ Chair04Icon
838
+ Chair05Icon
839
+ ChairBarberIcon
840
+ ChampionIcon
841
+ ChangeScreenModeIcon
842
+ CharacterPhoneticIcon
843
+ CharityIcon
844
+ Chart01Icon
845
+ Chart02Icon
846
+ Chart03Icon
847
+ ChartAverageIcon
848
+ ChartBarLineIcon
849
+ ChartBreakoutCircleIcon
850
+ ChartBreakoutSquareIcon
851
+ ChartBubble01Icon
852
+ ChartBubble02Icon
853
+ ChartColumnIcon
854
+ ChartDecreaseIcon
855
+ ChartDownIcon
856
+ ChartEvaluationIcon
857
+ ChartHighLowIcon
858
+ ChartHistogramIcon
859
+ ChartIncreaseIcon
860
+ ChartLineData01Icon
861
+ ChartLineData02Icon
862
+ ChartLineData03Icon
863
+ ChartMaximumIcon
864
+ ChartMediumIcon
865
+ ChartMinimumIcon
866
+ ChartRadarIcon
867
+ ChartRelationshipIcon
868
+ ChartRingIcon
869
+ ChartRoseIcon
870
+ ChartScatterIcon
871
+ ChartIcon
872
+ ChartUpIcon
873
+ Chat01Icon
874
+ ChatAdd01Icon
875
+ ChatAddIcon
876
+ ChatBlocked01Icon
877
+ ChatBlockedIcon
878
+ ChatBotIcon
879
+ ChatCancel01Icon
880
+ ChatCancelIcon
881
+ ChatDelay01Icon
882
+ ChatDelayIcon
883
+ ChatDone01Icon
884
+ ChatDoneIcon
885
+ ChatDownload01Icon
886
+ ChatDownloadIcon
887
+ ChatEdit01Icon
888
+ ChatEditIcon
889
+ ChatFavourite01Icon
890
+ ChatFavouriteIcon
891
+ ChatFeedback01Icon
892
+ ChatFeedbackIcon
893
+ ChatGptIcon
894
+ ChatIncome01Icon
895
+ ChatIncomeIcon
896
+ ChatLock01Icon
897
+ ChatLockIcon
898
+ ChatNotification01Icon
899
+ ChatNotificationIcon
900
+ ChatOutcome01Icon
901
+ ChatOutcomeIcon
902
+ ChatPreview01Icon
903
+ ChatPreviewIcon
904
+ ChatQuestion01Icon
905
+ ChatQuestionIcon
906
+ ChatSearch01Icon
907
+ ChatSearchIcon
908
+ ChatSecure01Icon
909
+ ChatSecureIcon
910
+ ChatSpark01Icon
911
+ ChatSparkIcon
912
+ ChatIcon
913
+ ChatTranslate01Icon
914
+ ChatTranslateIcon
915
+ ChatUnlock01Icon
916
+ ChatUnlockIcon
917
+ ChatUpload01Icon
918
+ ChatUploadIcon
919
+ ChatUser01Icon
920
+ ChatUserIcon
921
+ Chatting01Icon
922
+ CheckListIcon
923
+ CheckUnread01Icon
924
+ CheckUnread02Icon
925
+ CheckUnread03Icon
926
+ CheckUnread04Icon
927
+ CheckmarkBadge01Icon
928
+ CheckmarkBadge02Icon
929
+ CheckmarkBadge03Icon
930
+ CheckmarkBadge04Icon
931
+ CheckmarkCircle01Icon
932
+ CheckmarkCircle02Icon
933
+ CheckmarkCircle03Icon
934
+ CheckmarkCircle04Icon
935
+ CheckmarkSquare01Icon
936
+ CheckmarkSquare02Icon
937
+ CheckmarkSquare03Icon
938
+ CheckmarkSquare04Icon
939
+ CheeseCake01Icon
940
+ CheeseCake02Icon
941
+ CheeseIcon
942
+ ChefHatIcon
943
+ ChefIcon
944
+ Chemistry01Icon
945
+ Chemistry02Icon
946
+ Chemistry03Icon
947
+ CherryIcon
948
+ Chess01Icon
949
+ Chess02Icon
950
+ ChessPawnIcon
951
+ ChickenThighsIcon
952
+ ChildIcon
953
+ ChimneyIcon
954
+ ChinaTempleIcon
955
+ Chip02Icon
956
+ ChipIcon
957
+ ChocolateIcon
958
+ ChopsticksIcon
959
+ ChromeIcon
960
+ ChryslerIcon
961
+ ChurchIcon
962
+ CinnamonRollIcon
963
+ CircleArrowDataTransferDiagonalIcon
964
+ CircleArrowDataTransferHorizontalIcon
965
+ CircleArrowDataTransferVerticalIcon
966
+ CircleArrowDiagonal01Icon
967
+ CircleArrowDiagonal02Icon
968
+ CircleArrowDown01Icon
969
+ CircleArrowDown02Icon
970
+ CircleArrowDown03Icon
971
+ CircleArrowDownDoubleIcon
972
+ CircleArrowDownLeftIcon
973
+ CircleArrowDownRightIcon
974
+ CircleArrowExpand01Icon
975
+ CircleArrowExpand02Icon
976
+ CircleArrowHorizontalIcon
977
+ CircleArrowLeft01Icon
978
+ CircleArrowLeft02Icon
979
+ CircleArrowLeft03Icon
980
+ CircleArrowLeftDoubleIcon
981
+ CircleArrowLeftRightIcon
982
+ CircleArrowMoveDownLeftIcon
983
+ CircleArrowMoveDownRightIcon
984
+ CircleArrowMoveLeftDownIcon
985
+ CircleArrowMoveRightDownIcon
986
+ CircleArrowMoveUpLeftIcon
987
+ CircleArrowMoveUpRightIcon
988
+ CircleArrowReload01Icon
989
+ CircleArrowReload02Icon
990
+ CircleArrowRight01Icon
991
+ CircleArrowRight02Icon
992
+ CircleArrowRight03Icon
993
+ CircleArrowRightDoubleIcon
994
+ CircleArrowShrink01Icon
995
+ CircleArrowShrink02Icon
996
+ CircleArrowUp01Icon
997
+ CircleArrowUp02Icon
998
+ CircleArrowUp03Icon
999
+ CircleArrowUpDoubleIcon
1000
+ CircleArrowUpDownIcon
1001
+ CircleArrowUpLeftIcon
1002
+ CircleArrowUpRight02Icon
1003
+ CircleArrowUpRightIcon
1004
+ CircleArrowVerticalIcon
1005
+ CircleLock01Icon
1006
+ CircleLock02Icon
1007
+ CircleLockAdd01Icon
1008
+ CircleLockAdd02Icon
1009
+ CircleLockCheck01Icon
1010
+ CircleLockCheck02Icon
1011
+ CircleLockMinus01Icon
1012
+ CircleLockMinus02Icon
1013
+ CircleLockRemove01Icon
1014
+ CircleLockRemove02Icon
1015
+ CirclePasswordIcon
1016
+ CircleIcon
1017
+ CircleUnlock01Icon
1018
+ CircleUnlock02Icon
1019
+ City01Icon
1020
+ City02Icon
1021
+ City03Icon
1022
+ Clapping01Icon
1023
+ Clapping02Icon
1024
+ ClaudeIcon
1025
+ CleanIcon
1026
+ CleaningBucketIcon
1027
+ ClinicIcon
1028
+ ClipIcon
1029
+ ClipartsIcon
1030
+ ClipboardIcon
1031
+ Clock01Icon
1032
+ Clock02Icon
1033
+ Clock03Icon
1034
+ Clock04Icon
1035
+ Clock05Icon
1036
+ ClosedCaptionAltIcon
1037
+ ClosedCaptionIcon
1038
+ ClothesIcon
1039
+ CloudAngledRainIcon
1040
+ CloudAngledRainZapIcon
1041
+ CloudAngledZapIcon
1042
+ CloudBigRainIcon
1043
+ CloudDownloadIcon
1044
+ CloudFastWindIcon
1045
+ CloudHailstoneIcon
1046
+ CloudLittleRainIcon
1047
+ CloudLittleSnowIcon
1048
+ CloudLoadingIcon
1049
+ CloudMidRainIcon
1050
+ CloudMidSnowIcon
1051
+ CloudSavingDone01Icon
1052
+ CloudSavingDone02Icon
1053
+ CloudServerIcon
1054
+ CloudSlowWindIcon
1055
+ CloudSnowIcon
1056
+ CloudIcon
1057
+ CloudUploadIcon
1058
+ Clubs01Icon
1059
+ Clubs02Icon
1060
+ CoPresentIcon
1061
+ CodeCircleIcon
1062
+ CodeFolderIcon
1063
+ CodeSquareIcon
1064
+ CodeIcon
1065
+ CodesandboxIcon
1066
+ Coffee01Icon
1067
+ Coffee02Icon
1068
+ CoffeeBeansIcon
1069
+ CoinbaseIcon
1070
+ Coins01Icon
1071
+ Coins02Icon
1072
+ CoinsBitcoinIcon
1073
+ CoinsDollarIcon
1074
+ CoinsEuroIcon
1075
+ CoinsPoundIcon
1076
+ CoinsSwapIcon
1077
+ CoinsYenIcon
1078
+ CollectionsBookmarkIcon
1079
+ ColorPickerIcon
1080
+ ColorsIcon
1081
+ ColosseumIcon
1082
+ ColumnDeleteIcon
1083
+ ColumnInsertIcon
1084
+ Comet01Icon
1085
+ Comet02Icon
1086
+ ComingSoon01Icon
1087
+ ComingSoon02Icon
1088
+ CommandLineIcon
1089
+ CommandIcon
1090
+ Comment01Icon
1091
+ Comment02Icon
1092
+ Comment03Icon
1093
+ CommentAdd01Icon
1094
+ CommentAdd02Icon
1095
+ CommentAdd03Icon
1096
+ CommentBlock01Icon
1097
+ CommentBlock02Icon
1098
+ CommentBlock03Icon
1099
+ CommentRemove01Icon
1100
+ CommentRemove02Icon
1101
+ CommentRemove03Icon
1102
+ Compass01Icon
1103
+ CompassIcon
1104
+ ComplaintIcon
1105
+ ComputerActivityIcon
1106
+ ComputerAddIcon
1107
+ ComputerArrowDownIcon
1108
+ ComputerArrowUpIcon
1109
+ ComputerChartDownIcon
1110
+ ComputerChartUpIcon
1111
+ ComputerCheckIcon
1112
+ ComputerCloudIcon
1113
+ ComputerDesk01Icon
1114
+ ComputerDesk02Icon
1115
+ ComputerDesk03Icon
1116
+ ComputerDollarIcon
1117
+ ComputerEthernetIcon
1118
+ ComputerPhoneSyncIcon
1119
+ ComputerProgramming01Icon
1120
+ ComputerProgramming02Icon
1121
+ ComputerProtectionIcon
1122
+ ComputerRemoveIcon
1123
+ ComputerScreenShareIcon
1124
+ ComputerSettingsIcon
1125
+ ComputerIcon
1126
+ ComputerTerminal01Icon
1127
+ ComputerTerminal02Icon
1128
+ ComputerUserIcon
1129
+ ComputerVideoCallIcon
1130
+ ComputerVideoIcon
1131
+ Cone01Icon
1132
+ Cone02Icon
1133
+ ConferenceIcon
1134
+ Configuration01Icon
1135
+ Configuration02Icon
1136
+ ConfusedIcon
1137
+ CongruentToCircleIcon
1138
+ CongruentToSquareIcon
1139
+ CongruentToIcon
1140
+ ConnectIcon
1141
+ ConsoleIcon
1142
+ ConstellationIcon
1143
+ Contact01Icon
1144
+ Contact02Icon
1145
+ ContactBookIcon
1146
+ ContactIcon
1147
+ ContainerTruck01Icon
1148
+ ContainerTruck02Icon
1149
+ ContainerTruckIcon
1150
+ ContentWritingIcon
1151
+ ContractsIcon
1152
+ ConversationIcon
1153
+ CookBookIcon
1154
+ CookieIcon
1155
+ Coordinate01Icon
1156
+ Coordinate02Icon
1157
+ CopilotIcon
1158
+ Copy01Icon
1159
+ Copy02Icon
1160
+ CopyLinkIcon
1161
+ CopyrightIcon
1162
+ CornIcon
1163
+ CorporateIcon
1164
+ CosIcon
1165
+ Cosine01Icon
1166
+ Cosine02Icon
1167
+ CottageIcon
1168
+ CottonCandyIcon
1169
+ Coupon01Icon
1170
+ Coupon02Icon
1171
+ Coupon03Icon
1172
+ CouponPercentIcon
1173
+ CourseIcon
1174
+ CourtHouseIcon
1175
+ CourtLawIcon
1176
+ CovariateIcon
1177
+ CovidInfoIcon
1178
+ CowboyHatIcon
1179
+ CppIcon
1180
+ CpuChargeIcon
1181
+ CpuSettingsIcon
1182
+ CpuIcon
1183
+ CrabIcon
1184
+ CraneIcon
1185
+ CrazyIcon
1186
+ CreativeMarketIcon
1187
+ CreditCardAcceptIcon
1188
+ CreditCardAddIcon
1189
+ CreditCardChangeIcon
1190
+ CreditCardDefrostIcon
1191
+ CreditCardFreezeIcon
1192
+ CreditCardNotAcceptIcon
1193
+ CreditCardNotFoundIcon
1194
+ CreditCardPosIcon
1195
+ CreditCardIcon
1196
+ CreditCardValidationIcon
1197
+ CricketBatIcon
1198
+ CricketHelmetIcon
1199
+ CroissantIcon
1200
+ CropIcon
1201
+ CrowdfundingIcon
1202
+ Crown02Icon
1203
+ Crown03Icon
1204
+ CrownMinusIcon
1205
+ CrownPlusIcon
1206
+ CrownIcon
1207
+ CryingIcon
1208
+ Css3Icon
1209
+ CssFile01Icon
1210
+ CssFile02Icon
1211
+ Csv01Icon
1212
+ Csv02Icon
1213
+ CubeIcon
1214
+ Cupcake01Icon
1215
+ Cupcake02Icon
1216
+ Cupcake03Icon
1217
+ CurlingIcon
1218
+ Cursor01Icon
1219
+ Cursor02Icon
1220
+ CursorAddSelection01Icon
1221
+ CursorAddSelection02Icon
1222
+ CursorCircleSelection01Icon
1223
+ CursorCircleSelection02Icon
1224
+ CursorDisabled01Icon
1225
+ CursorDisabled02Icon
1226
+ CursorEdit01Icon
1227
+ CursorEdit02Icon
1228
+ CursorHold01Icon
1229
+ CursorHold02Icon
1230
+ CursorInWindowIcon
1231
+ CursorInfo01Icon
1232
+ CursorInfo02Icon
1233
+ CursorLoading01Icon
1234
+ CursorLoading02Icon
1235
+ CursorMagicSelection01Icon
1236
+ CursorMagicSelection02Icon
1237
+ CursorMagicSelection03Icon
1238
+ CursorMagicSelection04Icon
1239
+ CursorMove01Icon
1240
+ CursorMove02Icon
1241
+ CursorPointer01Icon
1242
+ CursorPointer02Icon
1243
+ CursorProgress01Icon
1244
+ CursorProgress02Icon
1245
+ CursorProgress03Icon
1246
+ CursorProgress04Icon
1247
+ CursorRectangleSelection01Icon
1248
+ CursorRectangleSelection02Icon
1249
+ CursorRemoveSelection01Icon
1250
+ CursorRemoveSelection02Icon
1251
+ CursorTextIcon
1252
+ CurtainsIcon
1253
+ CurvyLeftDirectionIcon
1254
+ CurvyLeftRightDirectionIcon
1255
+ CurvyRightDirectionIcon
1256
+ CurvyUpDownDirectionIcon
1257
+ CustomFieldIcon
1258
+ CustomerService01Icon
1259
+ CustomerService02Icon
1260
+ CustomerServiceIcon
1261
+ CustomerSupportIcon
1262
+ CustomizeIcon
1263
+ Cylinder01Icon
1264
+ Cylinder02Icon
1265
+ Cylinder03Icon
1266
+ Cylinder04Icon
1267
+ DangerIcon
1268
+ DarkModeIcon
1269
+ DartIcon
1270
+ DashboardBrowsingIcon
1271
+ DashboardCircleAddIcon
1272
+ DashboardCircleEditIcon
1273
+ DashboardCircleRemoveIcon
1274
+ DashboardCircleSettingsIcon
1275
+ DashboardCircleIcon
1276
+ DashboardSpeed01Icon
1277
+ DashboardSpeed02Icon
1278
+ DashboardSquare01Icon
1279
+ DashboardSquare02Icon
1280
+ DashboardSquare03Icon
1281
+ DashboardSquareAddIcon
1282
+ DashboardSquareEditIcon
1283
+ DashboardSquareRemoveIcon
1284
+ DashboardSquareSettingIcon
1285
+ DashedLine01Icon
1286
+ DashedLine02Icon
1287
+ DashedLineCircleIcon
1288
+ DataRecoveryIcon
1289
+ Database01Icon
1290
+ Database02Icon
1291
+ DatabaseAddIcon
1292
+ DatabaseExportIcon
1293
+ DatabaseImportIcon
1294
+ DatabaseLockedIcon
1295
+ DatabaseRestoreIcon
1296
+ DatabaseSettingIcon
1297
+ DatabaseIcon
1298
+ DatabaseSync01Icon
1299
+ DatabaseSyncIcon
1300
+ DateTimeIcon
1301
+ DatesIcon
1302
+ DatevIcon
1303
+ DeadIcon
1304
+ DeepseekIcon
1305
+ Delete01Icon
1306
+ Delete02Icon
1307
+ Delete03Icon
1308
+ Delete04Icon
1309
+ DeleteColumnIcon
1310
+ DeletePutBackIcon
1311
+ DeleteRowIcon
1312
+ DeleteThrowIcon
1313
+ DeliveredSentIcon
1314
+ DeliveryBox01Icon
1315
+ DeliveryBox02Icon
1316
+ DeliveryDelay01Icon
1317
+ DeliveryDelay02Icon
1318
+ DeliveryReturn01Icon
1319
+ DeliveryReturn02Icon
1320
+ DeliverySecure01Icon
1321
+ DeliverySecure02Icon
1322
+ DeliverySent01Icon
1323
+ DeliverySent02Icon
1324
+ DeliveryTracking01Icon
1325
+ DeliveryTracking02Icon
1326
+ DeliveryTruck01Icon
1327
+ DeliveryTruck02Icon
1328
+ DeliveryView01Icon
1329
+ DeliveryView02Icon
1330
+ DentalBracesIcon
1331
+ DentalBrokenToothIcon
1332
+ DentalCareIcon
1333
+ DentalToothIcon
1334
+ DepartementIcon
1335
+ DesertIcon
1336
+ Desk01Icon
1337
+ Desk02Icon
1338
+ DeskIcon
1339
+ DetergentIcon
1340
+ DeveloperIcon
1341
+ DeviantartIcon
1342
+ DeviceAccessIcon
1343
+ DiagonalScrollPoint01Icon
1344
+ DiagonalScrollPoint02Icon
1345
+ DialpadCircle01Icon
1346
+ DialpadCircle02Icon
1347
+ DialpadSquare01Icon
1348
+ DialpadSquare02Icon
1349
+ DiameterIcon
1350
+ Diamond01Icon
1351
+ Diamond02Icon
1352
+ DiamondIcon
1353
+ DiaperIcon
1354
+ DiceFaces01Icon
1355
+ DiceFaces02Icon
1356
+ DiceFaces03Icon
1357
+ DiceFaces04Icon
1358
+ DiceFaces05Icon
1359
+ DiceFaces06Icon
1360
+ DiceIcon
1361
+ DigestionIcon
1362
+ DiggIcon
1363
+ DigitalClockIcon
1364
+ DimSum01Icon
1365
+ DimSum02Icon
1366
+ DiningTableIcon
1367
+ DiplomaIcon
1368
+ DirectionLeft01Icon
1369
+ DirectionLeft02Icon
1370
+ DirectionRight01Icon
1371
+ DirectionRight02Icon
1372
+ Directions01Icon
1373
+ Directions02Icon
1374
+ DirhamIcon
1375
+ Disability01Icon
1376
+ Disability02Icon
1377
+ DiscordIcon
1378
+ Discount01Icon
1379
+ DiscountIcon
1380
+ DiscountTag01Icon
1381
+ DiscountTag02Icon
1382
+ DiscoverCircleIcon
1383
+ DiscoverSquareIcon
1384
+ Dish01Icon
1385
+ Dish02Icon
1386
+ DishWasherIcon
1387
+ DispleasedIcon
1388
+ DistributeHorizontalCenterIcon
1389
+ DistributeHorizontalLeftIcon
1390
+ DistributeHorizontalRightIcon
1391
+ DistributeVerticalBottomIcon
1392
+ DistributeVerticalCenterIcon
1393
+ DistributeVerticalTopIcon
1394
+ DistributionIcon
1395
+ DivideSignCircleIcon
1396
+ DivideSignSquareIcon
1397
+ DivideSignIcon
1398
+ Dna01Icon
1399
+ DnaIcon
1400
+ DoNotTouch01Icon
1401
+ DoNotTouch02Icon
1402
+ Doc01Icon
1403
+ Doc02Icon
1404
+ Doctor01Icon
1405
+ Doctor02Icon
1406
+ Doctor03Icon
1407
+ DocumentAttachmentIcon
1408
+ DocumentCodeIcon
1409
+ DocumentValidationIcon
1410
+ Dollar01Icon
1411
+ Dollar02Icon
1412
+ DollarCircleIcon
1413
+ DollarReceive01Icon
1414
+ DollarReceive02Icon
1415
+ DollarSend01Icon
1416
+ DollarSend02Icon
1417
+ DollarSquareIcon
1418
+ DomeIcon
1419
+ DominoIcon
1420
+ Door01Icon
1421
+ Door02Icon
1422
+ DoorLockIcon
1423
+ DoorIcon
1424
+ DoughnutIcon
1425
+ Download01Icon
1426
+ Download02Icon
1427
+ Download03Icon
1428
+ Download04Icon
1429
+ Download05Icon
1430
+ DownloadCircle01Icon
1431
+ DownloadCircle02Icon
1432
+ DownloadSquare01Icon
1433
+ DownloadSquare02Icon
1434
+ Drag01Icon
1435
+ Drag02Icon
1436
+ Drag03Icon
1437
+ Drag04Icon
1438
+ DragDropHorizontalIcon
1439
+ DragDropIcon
1440
+ DragDropVerticalIcon
1441
+ DragLeft01Icon
1442
+ DragLeft02Icon
1443
+ DragLeft03Icon
1444
+ DragLeft04Icon
1445
+ DragRight01Icon
1446
+ DragRight02Icon
1447
+ DragRight03Icon
1448
+ DragRight04Icon
1449
+ DrawingCompassIcon
1450
+ DrawingModeIcon
1451
+ Dress01Icon
1452
+ Dress02Icon
1453
+ Dress03Icon
1454
+ Dress04Icon
1455
+ Dress05Icon
1456
+ Dress06Icon
1457
+ Dress07Icon
1458
+ DressingTable01Icon
1459
+ DressingTable02Icon
1460
+ DressingTable03Icon
1461
+ DribbbleIcon
1462
+ DrinkIcon
1463
+ DriveIcon
1464
+ DroneIcon
1465
+ DroolingIcon
1466
+ DropboxIcon
1467
+ DropletIcon
1468
+ DropperIcon
1469
+ Ds3ToolIcon
1470
+ DuaIcon
1471
+ Dumbbell01Icon
1472
+ Dumbbell02Icon
1473
+ Dumbbell03Icon
1474
+ EarRings01Icon
1475
+ EarRings02Icon
1476
+ EarRings03Icon
1477
+ EarIcon
1478
+ EarthIcon
1479
+ EaseCurveControlPointsIcon
1480
+ EaseInControlPointIcon
1481
+ EaseInOutIcon
1482
+ EaseInIcon
1483
+ EaseOutControlPointIcon
1484
+ EaseOutIcon
1485
+ EcoEnergyIcon
1486
+ EcoLab01Icon
1487
+ EcoLab02Icon
1488
+ EcoLabIcon
1489
+ EcoPowerIcon
1490
+ EdgeStyleIcon
1491
+ Edit01Icon
1492
+ Edit02Icon
1493
+ Edit03Icon
1494
+ Edit04Icon
1495
+ EditOff03Icon
1496
+ EditOff04Icon
1497
+ EditOffIcon
1498
+ EditRoadIcon
1499
+ EditTableIcon
1500
+ EditUser02Icon
1501
+ EggsIcon
1502
+ EidMubarakIcon
1503
+ EiffelTowerIcon
1504
+ EightCircleIcon
1505
+ EightSquareIcon
1506
+ ElearningExchangeIcon
1507
+ ElectricHome01Icon
1508
+ ElectricHome02Icon
1509
+ ElectricPlugsIcon
1510
+ ElectricTower01Icon
1511
+ ElectricTower02Icon
1512
+ ElectricWireIcon
1513
+ EllipseSelectionIcon
1514
+ EncryptIcon
1515
+ EnergyEllipseIcon
1516
+ EnergyRectangleIcon
1517
+ EnergyIcon
1518
+ EnteringGeoFenceIcon
1519
+ EntranceStairsIcon
1520
+ EnvatoIcon
1521
+ EqualSignCircleIcon
1522
+ EqualSignSquareIcon
1523
+ EqualSignIcon
1524
+ EquipmentBenchPressIcon
1525
+ EquipmentChestPressIcon
1526
+ EquipmentGym01Icon
1527
+ EquipmentGym02Icon
1528
+ EquipmentGym03Icon
1529
+ EquipmentWeightliftingIcon
1530
+ Eraser01Icon
1531
+ EraserAddIcon
1532
+ EraserAutoIcon
1533
+ EraserIcon
1534
+ Estimate01Icon
1535
+ Estimate02Icon
1536
+ EthereumEllipseIcon
1537
+ EthereumRectangleIcon
1538
+ EthereumIcon
1539
+ EuroCircleIcon
1540
+ EuroReceiveIcon
1541
+ EuroSendIcon
1542
+ EuroSquareIcon
1543
+ EuroIcon
1544
+ EvChargingIcon
1545
+ EvilIcon
1546
+ Exchange01Icon
1547
+ Exchange02Icon
1548
+ Exchange03Icon
1549
+ ExpanderIcon
1550
+ ExternalDriveIcon
1551
+ EyeIcon
1552
+ FaceIdIcon
1553
+ Facebook01Icon
1554
+ Facebook02Icon
1555
+ Factory01Icon
1556
+ Factory02Icon
1557
+ FactoryIcon
1558
+ FahrenheitIcon
1559
+ FallingStarIcon
1560
+ Fan01Icon
1561
+ Fan02Icon
1562
+ FastWindIcon
1563
+ FavouriteCircleIcon
1564
+ FavouriteSquareIcon
1565
+ FavouriteIcon
1566
+ FeatherIcon
1567
+ Female02Icon
1568
+ FemaleSymbolIcon
1569
+ FencingMaskIcon
1570
+ FencingIcon
1571
+ FerrisWheelIcon
1572
+ FerryBoatIcon
1573
+ FigmaIcon
1574
+ File01Icon
1575
+ File02Icon
1576
+ FileAddIcon
1577
+ FileAttachmentIcon
1578
+ FileAudioIcon
1579
+ FileBitcoinIcon
1580
+ FileBlockIcon
1581
+ FileBookmarkIcon
1582
+ FileCloudIcon
1583
+ FileCorruptIcon
1584
+ FileDollarIcon
1585
+ FileDownloadIcon
1586
+ FileEditIcon
1587
+ FileEmpty01Icon
1588
+ FileEmpty02Icon
1589
+ FileEuroIcon
1590
+ FileExportIcon
1591
+ FileFavouriteIcon
1592
+ FileImportIcon
1593
+ FileLinkIcon
1594
+ FileLockedIcon
1595
+ FileManagementIcon
1596
+ FileMinusIcon
1597
+ FileMusicIcon
1598
+ FileNotFoundIcon
1599
+ FilePasteIcon
1600
+ FilePinIcon
1601
+ FilePoundIcon
1602
+ FileRemoveIcon
1603
+ FileScriptIcon
1604
+ FileSearchIcon
1605
+ FileSecurityIcon
1606
+ FileShredderIcon
1607
+ FileStarIcon
1608
+ FileSyncIcon
1609
+ FileUnknownIcon
1610
+ FileUnlockedIcon
1611
+ FileUploadIcon
1612
+ FileValidationIcon
1613
+ FileVerifiedIcon
1614
+ FileVideoIcon
1615
+ FileViewIcon
1616
+ FileYenIcon
1617
+ FileZipIcon
1618
+ Files01Icon
1619
+ Files02Icon
1620
+ Film01Icon
1621
+ Film02Icon
1622
+ FilmRoll01Icon
1623
+ FilmRoll02Icon
1624
+ FilterAddIcon
1625
+ FilterEditIcon
1626
+ FilterHorizontalIcon
1627
+ FilterMailCircleIcon
1628
+ FilterMailSquareIcon
1629
+ FilterRemoveIcon
1630
+ FilterResetIcon
1631
+ FilterIcon
1632
+ FilterVerticalIcon
1633
+ FingerAccessIcon
1634
+ FingerPrintAddIcon
1635
+ FingerPrintCheckIcon
1636
+ FingerPrintMinusIcon
1637
+ FingerPrintRemoveIcon
1638
+ FingerPrintScanIcon
1639
+ FingerPrintIcon
1640
+ FinsIcon
1641
+ Fire02Icon
1642
+ Fire03Icon
1643
+ FirePitIcon
1644
+ FireSecurityIcon
1645
+ FireIcon
1646
+ FirewallIcon
1647
+ FireworksIcon
1648
+ FirstAidKitIcon
1649
+ FishFoodIcon
1650
+ FitToScreenIcon
1651
+ FiveCircleIcon
1652
+ FiveSquareIcon
1653
+ FiverrIcon
1654
+ Flag01Icon
1655
+ Flag02Icon
1656
+ Flag03Icon
1657
+ FlashOffIcon
1658
+ FlashIcon
1659
+ FlashlightIcon
1660
+ FlaticonIcon
1661
+ FlickrIcon
1662
+ FlimSlateIcon
1663
+ FlipBottomIcon
1664
+ FlipHorizontalIcon
1665
+ FlipLeftIcon
1666
+ FlipPhoneIcon
1667
+ FlipRightIcon
1668
+ FlipTopIcon
1669
+ FlipVerticalIcon
1670
+ FloorPlanIcon
1671
+ FloppyDiskIcon
1672
+ FlowCircleIcon
1673
+ FlowConnectionIcon
1674
+ FlowSquareIcon
1675
+ FlowIcon
1676
+ Flowchart01Icon
1677
+ Flowchart02Icon
1678
+ FlowerPotIcon
1679
+ FlowerIcon
1680
+ FlushedIcon
1681
+ FlyingHumanIcon
1682
+ FocusPointIcon
1683
+ Folder01Icon
1684
+ Folder02Icon
1685
+ Folder03Icon
1686
+ FolderAddIcon
1687
+ FolderAttachmentIcon
1688
+ FolderAudioIcon
1689
+ FolderBlockIcon
1690
+ FolderCheckIcon
1691
+ FolderCloudIcon
1692
+ FolderDetailsReferenceIcon
1693
+ FolderDetailsIcon
1694
+ FolderDownloadIcon
1695
+ FolderEditIcon
1696
+ FolderExportIcon
1697
+ FolderFavouriteIcon
1698
+ FolderFileStorageIcon
1699
+ FolderImportIcon
1700
+ FolderLibraryIcon
1701
+ FolderLinksIcon
1702
+ FolderLockedIcon
1703
+ FolderManagementIcon
1704
+ FolderMinusIcon
1705
+ FolderMusicIcon
1706
+ FolderOffIcon
1707
+ FolderOpenIcon
1708
+ FolderPinIcon
1709
+ FolderRemoveIcon
1710
+ FolderSearchIcon
1711
+ FolderSecurityIcon
1712
+ FolderShared01Icon
1713
+ FolderShared02Icon
1714
+ FolderShared03Icon
1715
+ FolderSyncIcon
1716
+ FolderTransferIcon
1717
+ FolderUnknownIcon
1718
+ FolderUnlockedIcon
1719
+ FolderUploadIcon
1720
+ FolderVideoIcon
1721
+ FolderViewIcon
1722
+ FolderZipIcon
1723
+ FoldersIcon
1724
+ FootballPitchIcon
1725
+ FootballIcon
1726
+ ForgotPasswordIcon
1727
+ ForkIcon
1728
+ ForrstIcon
1729
+ FortressIcon
1730
+ Forward01Icon
1731
+ Forward02Icon
1732
+ FourCircleIcon
1733
+ FourFinger02Icon
1734
+ FourFinger03Icon
1735
+ FourSquareIcon
1736
+ FramerIcon
1737
+ FrameworksIcon
1738
+ FrenchFries01Icon
1739
+ FrenchFries02Icon
1740
+ FridgeIcon
1741
+ FrisbeeIcon
1742
+ FryIcon
1743
+ Fuel01Icon
1744
+ Fuel02Icon
1745
+ FuelStationIcon
1746
+ FuelIcon
1747
+ FullScreenIcon
1748
+ FullSignalIcon
1749
+ FunctionCircleIcon
1750
+ FunctionOfXIcon
1751
+ FunctionSquareIcon
1752
+ FunctionIcon
1753
+ GalaxyIcon
1754
+ GameController01Icon
1755
+ GameController02Icon
1756
+ GameController03Icon
1757
+ GameIcon
1758
+ GameboyIcon
1759
+ GarageIcon
1760
+ GarbageTruckIcon
1761
+ GarlandsIcon
1762
+ GasPipeIcon
1763
+ GasStoveIcon
1764
+ GearsIcon
1765
+ GemIcon
1766
+ GeologyCrustIcon
1767
+ GeometricShapes01Icon
1768
+ GeometricShapes02Icon
1769
+ GibbousMoonIcon
1770
+ Gif01Icon
1771
+ Gif02Icon
1772
+ GiftCard02Icon
1773
+ GiftCardIcon
1774
+ GiftIcon
1775
+ GitBranchIcon
1776
+ GitCommitIcon
1777
+ GitCompareIcon
1778
+ GitForkIcon
1779
+ GitMergeIcon
1780
+ GitPullRequestClosedIcon
1781
+ GitPullRequestDraftIcon
1782
+ GitPullRequestIcon
1783
+ GitbookIcon
1784
+ Github01Icon
1785
+ GithubIcon
1786
+ GitlabIcon
1787
+ GiveBloodIcon
1788
+ GivePillIcon
1789
+ GlassesIcon
1790
+ GlobalEditingIcon
1791
+ GlobalEducationIcon
1792
+ GlobalRefreshIcon
1793
+ GlobalSearchIcon
1794
+ GlobalIcon
1795
+ Globe02Icon
1796
+ GlobeIcon
1797
+ GloveIcon
1798
+ GnomeIcon
1799
+ GoBackward10SecIcon
1800
+ GoBackward15SecIcon
1801
+ GoBackward30SecIcon
1802
+ GoBackward5SecIcon
1803
+ GoBackward60SecIcon
1804
+ GoForward10SecIcon
1805
+ GoForward15SecIcon
1806
+ GoForward30SecIcon
1807
+ GoForward5SecIcon
1808
+ GoForward60SecIcon
1809
+ GoldIngotsIcon
1810
+ GoldIcon
1811
+ GolfBallIcon
1812
+ GolfBatIcon
1813
+ GolfCartIcon
1814
+ GolfHoleIcon
1815
+ GoogleDocIcon
1816
+ GoogleDriveIcon
1817
+ GoogleGeminiIcon
1818
+ GoogleHomeIcon
1819
+ GoogleLensIcon
1820
+ GoogleMapsIcon
1821
+ GooglePhotosIcon
1822
+ GoogleSheetIcon
1823
+ GoogleIcon
1824
+ Gps01Icon
1825
+ Gps02Icon
1826
+ GpsDisconnectedIcon
1827
+ GpsOff01Icon
1828
+ GpsOff02Icon
1829
+ GpsSignal01Icon
1830
+ GpsSignal02Icon
1831
+ GpuIcon
1832
+ GraduateFemaleIcon
1833
+ GraduateMaleIcon
1834
+ GraduationScrollIcon
1835
+ GrapesIcon
1836
+ GravityIcon
1837
+ GreaterThanCircleIcon
1838
+ GreaterThanSquareIcon
1839
+ GreaterThanIcon
1840
+ GreekHelmetIcon
1841
+ GreenHouseIcon
1842
+ Grid02Icon
1843
+ GridOffIcon
1844
+ GridIcon
1845
+ GridTableIcon
1846
+ GridViewIcon
1847
+ GrimacingIcon
1848
+ GrinningIcon
1849
+ Grok02Icon
1850
+ GrokIcon
1851
+ Group01Icon
1852
+ GroupItemsIcon
1853
+ GroupLayersIcon
1854
+ GuestHouseIcon
1855
+ GunIcon
1856
+ GymnasticRingsIcon
1857
+ GymnasticIcon
1858
+ HackerrankIcon
1859
+ HairClipsIcon
1860
+ HairDryerIcon
1861
+ HajiIcon
1862
+ HalalLabIcon
1863
+ HalalIcon
1864
+ Hamburger01Icon
1865
+ Hamburger02Icon
1866
+ HandBag01Icon
1867
+ HandBag02Icon
1868
+ HandBeaterIcon
1869
+ HandGripIcon
1870
+ HandPointingDown01Icon
1871
+ HandPointingDown02Icon
1872
+ HandPointingDown03Icon
1873
+ HandPointingDown04Icon
1874
+ HandPointingLeft01Icon
1875
+ HandPointingLeft02Icon
1876
+ HandPointingLeft03Icon
1877
+ HandPointingLeft04Icon
1878
+ HandPointingRight01Icon
1879
+ HandPointingRight02Icon
1880
+ HandPointingRight03Icon
1881
+ HandPointingRight04Icon
1882
+ HandPrayerIcon
1883
+ HandSanitizerIcon
1884
+ HandcuffsIcon
1885
+ HangerIcon
1886
+ HangingClockIcon
1887
+ HangoutIcon
1888
+ Happy01Icon
1889
+ HappyIcon
1890
+ HardDriveIcon
1891
+ HatIcon
1892
+ HddIcon
1893
+ Hdr01Icon
1894
+ Hdr02Icon
1895
+ Heading01Icon
1896
+ Heading02Icon
1897
+ Heading03Icon
1898
+ Heading04Icon
1899
+ Heading05Icon
1900
+ Heading06Icon
1901
+ HeadingIcon
1902
+ HeadphoneMuteIcon
1903
+ HeadphonesIcon
1904
+ HeadsetConnectedIcon
1905
+ HeadsetOffIcon
1906
+ HeadsetIcon
1907
+ HealtcareIcon
1908
+ HealthIcon
1909
+ HeartAddIcon
1910
+ HeartCheckIcon
1911
+ HeartRemoveIcon
1912
+ HeartbreakIcon
1913
+ HelicopterIcon
1914
+ HelpCircleIcon
1915
+ HelpSquareIcon
1916
+ Hexagon01Icon
1917
+ HexagonIcon
1918
+ HierarchyCircle01Icon
1919
+ HierarchyCircle02Icon
1920
+ HierarchyCircle03Icon
1921
+ HierarchyFilesIcon
1922
+ HierarchySquare01Icon
1923
+ HierarchySquare02Icon
1924
+ HierarchySquare03Icon
1925
+ HierarchySquare04Icon
1926
+ HierarchySquare05Icon
1927
+ HierarchySquare06Icon
1928
+ HierarchySquare07Icon
1929
+ HierarchySquare08Icon
1930
+ HierarchySquare10Icon
1931
+ HierarchyIcon
1932
+ HighHeels01Icon
1933
+ HighHeels02Icon
1934
+ HighlighterIcon
1935
+ HijabIcon
1936
+ HockeyIcon
1937
+ Hold01Icon
1938
+ Hold02Icon
1939
+ Hold03Icon
1940
+ Hold04Icon
1941
+ Hold05Icon
1942
+ HoldLocked01Icon
1943
+ HoldLocked02Icon
1944
+ HoldPhoneIcon
1945
+ HologramIcon
1946
+ Home01Icon
1947
+ Home02Icon
1948
+ Home03Icon
1949
+ Home04Icon
1950
+ Home05Icon
1951
+ Home06Icon
1952
+ Home07Icon
1953
+ Home08Icon
1954
+ Home09Icon
1955
+ Home10Icon
1956
+ Home11Icon
1957
+ Home12Icon
1958
+ Home13Icon
1959
+ HomeWifiIcon
1960
+ Honey01Icon
1961
+ Honey02Icon
1962
+ HonorIcon
1963
+ HonourStarIcon
1964
+ HoodieIcon
1965
+ HorizonalScrollPointIcon
1966
+ HorizontalResizeIcon
1967
+ HorseHeadIcon
1968
+ HorseSaddleIcon
1969
+ HorseIcon
1970
+ Hospital01Icon
1971
+ Hospital02Icon
1972
+ HospitalBed01Icon
1973
+ HospitalBed02Icon
1974
+ HospitalLocationIcon
1975
+ HotAirBalloonIcon
1976
+ HotPriceIcon
1977
+ HotTubeIcon
1978
+ HotdogIcon
1979
+ Hotel01Icon
1980
+ Hotel02Icon
1981
+ HotelBellIcon
1982
+ HotspotOfflineIcon
1983
+ HotspotIcon
1984
+ HourglassOffIcon
1985
+ HourglassIcon
1986
+ House01Icon
1987
+ House02Icon
1988
+ House03Icon
1989
+ House04Icon
1990
+ House05Icon
1991
+ HouseSolarPanelIcon
1992
+ Html5Icon
1993
+ HtmlFile01Icon
1994
+ HtmlFile02Icon
1995
+ HugeiconsIcon
1996
+ HumidityIcon
1997
+ HutIcon
1998
+ HydroPowerIcon
1999
+ HyperboleIcon
2000
+ IceCream01Icon
2001
+ IceCream02Icon
2002
+ IceCream03Icon
2003
+ IceCream04Icon
2004
+ IceCubesIcon
2005
+ IceHockeyIcon
2006
+ IceSkatingIcon
2007
+ IcoIcon
2008
+ IconjarIcon
2009
+ IdNotVerifiedIcon
2010
+ IdIcon
2011
+ IdVerifiedIcon
2012
+ Idea01Icon
2013
+ IdeaIcon
2014
+ IdentificationIcon
2015
+ IdentityCardIcon
2016
+ Image01Icon
2017
+ Image02Icon
2018
+ Image03Icon
2019
+ ImageActualSizeIcon
2020
+ ImageAdd01Icon
2021
+ ImageAdd02Icon
2022
+ ImageCompositionOvalIcon
2023
+ ImageCompositionIcon
2024
+ ImageCounterClockwiseIcon
2025
+ ImageCropIcon
2026
+ ImageDelete01Icon
2027
+ ImageDelete02Icon
2028
+ ImageDone01Icon
2029
+ ImageDone02Icon
2030
+ ImageDownload02Icon
2031
+ ImageDownloadIcon
2032
+ ImageFlipVerticalIcon
2033
+ ImageNotFound01Icon
2034
+ ImageNotFound02Icon
2035
+ ImageRemove01Icon
2036
+ ImageRemove02Icon
2037
+ ImageRotationClockwiseIcon
2038
+ ImageUpload01Icon
2039
+ ImageUploadIcon
2040
+ ImoIcon
2041
+ ImportantBookIcon
2042
+ InLoveIcon
2043
+ InboxCheckIcon
2044
+ InboxDownloadIcon
2045
+ InboxIcon
2046
+ InboxUnreadIcon
2047
+ InboxUploadIcon
2048
+ IncognitoIcon
2049
+ IndiaGateIcon
2050
+ Inequality01Icon
2051
+ Inequality02Icon
2052
+ InequalityCircle01Icon
2053
+ InequalityCircle02Icon
2054
+ InequalitySquare01Icon
2055
+ InequalitySquare02Icon
2056
+ InfantIcon
2057
+ Infinity01Icon
2058
+ Infinity02Icon
2059
+ InfinityCircleIcon
2060
+ InfinitySquareIcon
2061
+ InformationCircleIcon
2062
+ InformationDiamondIcon
2063
+ InformationSquareIcon
2064
+ InjectionIcon
2065
+ InsertBottomImageIcon
2066
+ InsertCenterImageIcon
2067
+ InsertColumnLeftIcon
2068
+ InsertColumnRightIcon
2069
+ InsertColumnIcon
2070
+ InsertPiIcon
2071
+ InsertRowDownIcon
2072
+ InsertRowIcon
2073
+ InsertRowUpIcon
2074
+ InsertTopImageIcon
2075
+ InspectCodeIcon
2076
+ InstagramIcon
2077
+ InstallingUpdates01Icon
2078
+ InstallingUpdates02Icon
2079
+ InternetAntenna01Icon
2080
+ InternetAntenna02Icon
2081
+ InternetAntenna03Icon
2082
+ InternetAntenna04Icon
2083
+ InternetIcon
2084
+ InvestigationIcon
2085
+ Invoice01Icon
2086
+ Invoice02Icon
2087
+ Invoice03Icon
2088
+ Invoice04Icon
2089
+ InvoiceIcon
2090
+ IpodIcon
2091
+ IrisScanIcon
2092
+ IslandIcon
2093
+ JarIcon
2094
+ JavaScriptIcon
2095
+ JavaIcon
2096
+ JobLinkIcon
2097
+ JobSearchIcon
2098
+ JobShareIcon
2099
+ JoggerPantsIcon
2100
+ JoinBevelIcon
2101
+ JoinRoundIcon
2102
+ JoinStraightIcon
2103
+ JokerIcon
2104
+ Joystick01Icon
2105
+ Joystick02Icon
2106
+ Joystick03Icon
2107
+ Joystick04Icon
2108
+ Joystick05Icon
2109
+ Jpg01Icon
2110
+ Jpg02Icon
2111
+ Jsx01Icon
2112
+ Jsx02Icon
2113
+ Jsx03Icon
2114
+ JudgeIcon
2115
+ JumpersIcon
2116
+ JupiterIcon
2117
+ JusticeScale01Icon
2118
+ JusticeScale02Icon
2119
+ Kaaba01Icon
2120
+ Kaaba02Icon
2121
+ KanbanIcon
2122
+ KayakIcon
2123
+ KeffiyehIcon
2124
+ Kettle01Icon
2125
+ KettleIcon
2126
+ KettlebellIcon
2127
+ KetupatIcon
2128
+ Key01Icon
2129
+ Key02Icon
2130
+ KeyGeneratorFobIcon
2131
+ KeyboardIcon
2132
+ KeyframeAddIcon
2133
+ KeyframeAlignCenterIcon
2134
+ KeyframeAlignHorizontalIcon
2135
+ KeyframeAlignVerticalIcon
2136
+ KeyframeBottomIcon
2137
+ KeyframeLeftIcon
2138
+ KeyframeRemoveIcon
2139
+ KeyframeRightIcon
2140
+ KeyframeIcon
2141
+ KeyframeTopIcon
2142
+ KeyframesDoubleAddIcon
2143
+ KeyframesDoubleRemoveIcon
2144
+ KeyframesDoubleIcon
2145
+ KeyframesMultipleAddIcon
2146
+ KeyframesMultipleRemoveIcon
2147
+ KeyframesMultipleIcon
2148
+ Kickstarter01Icon
2149
+ Kickstarter02Icon
2150
+ KidIcon
2151
+ KidneysIcon
2152
+ KimiAiIcon
2153
+ KissingIcon
2154
+ KitchenUtensilsIcon
2155
+ KiteIcon
2156
+ KlarnaIcon
2157
+ Knife01Icon
2158
+ Knife02Icon
2159
+ KnifeBreadIcon
2160
+ KnightShieldIcon
2161
+ KnivesIcon
2162
+ Knowledge01Icon
2163
+ Knowledge02Icon
2164
+ KoFiIcon
2165
+ Kurta01Icon
2166
+ KurtaIcon
2167
+ LabelImportantIcon
2168
+ LabelIcon
2169
+ LaborIcon
2170
+ LabsIcon
2171
+ LakeIcon
2172
+ Lamp01Icon
2173
+ Lamp02Icon
2174
+ Lamp03Icon
2175
+ Lamp04Icon
2176
+ Lamp05Icon
2177
+ LampIcon
2178
+ LanguageCircleIcon
2179
+ LanguageSkillIcon
2180
+ LanguageSquareIcon
2181
+ LanternIcon
2182
+ LaptopAddIcon
2183
+ LaptopChargingIcon
2184
+ LaptopCheckIcon
2185
+ LaptopCloudIcon
2186
+ LaptopIssueIcon
2187
+ LaptopPerformanceIcon
2188
+ LaptopPhoneSyncIcon
2189
+ LaptopProgrammingIcon
2190
+ LaptopRemoveIcon
2191
+ LaptopSettingsIcon
2192
+ LaptopIcon
2193
+ LaptopVideoIcon
2194
+ LassoTool01Icon
2195
+ LassoTool02Icon
2196
+ LastFmIcon
2197
+ LatitudeIcon
2198
+ LaughingIcon
2199
+ LaurelWreath01Icon
2200
+ LaurelWreath02Icon
2201
+ LaurelWreathFirst01Icon
2202
+ LaurelWreathFirst02Icon
2203
+ LaurelWreathLeft01Icon
2204
+ LaurelWreathLeft02Icon
2205
+ LaurelWreathLeft03Icon
2206
+ LaurelWreathRight01Icon
2207
+ LaurelWreathRight02Icon
2208
+ LaurelWreathRight03Icon
2209
+ LayerAddIcon
2210
+ LayerBringForwardIcon
2211
+ LayerBringToFrontIcon
2212
+ LayerMask01Icon
2213
+ LayerMask02Icon
2214
+ LayerSendBackwardIcon
2215
+ LayerSendToBackIcon
2216
+ LayerIcon
2217
+ Layers01Icon
2218
+ Layers02Icon
2219
+ LayersLogoIcon
2220
+ Layout01Icon
2221
+ Layout02Icon
2222
+ Layout03Icon
2223
+ Layout04Icon
2224
+ Layout05Icon
2225
+ Layout06Icon
2226
+ Layout07Icon
2227
+ Layout2ColumnIcon
2228
+ Layout2RowIcon
2229
+ Layout3ColumnIcon
2230
+ Layout3RowIcon
2231
+ LayoutBottomIcon
2232
+ LayoutGridIcon
2233
+ LayoutLeftIcon
2234
+ LayoutRightIcon
2235
+ LayoutTable01Icon
2236
+ LayoutTable02Icon
2237
+ LayoutTopIcon
2238
+ Leaf01Icon
2239
+ Leaf02Icon
2240
+ Leaf03Icon
2241
+ Leaf04Icon
2242
+ LeavingGeoFenceIcon
2243
+ LeetcodeIcon
2244
+ LeftAngleIcon
2245
+ LeftToRightBlockQuoteIcon
2246
+ LeftToRightListBulletIcon
2247
+ LeftToRightListDashIcon
2248
+ LeftToRightListNumberIcon
2249
+ LeftToRightListStar01Icon
2250
+ LeftToRightListStarIcon
2251
+ LeftToRightListTriangleIcon
2252
+ LeftTriangleIcon
2253
+ Legal01Icon
2254
+ Legal02Icon
2255
+ LegalDocument01Icon
2256
+ LegalDocument02Icon
2257
+ LegalHammerIcon
2258
+ LessThanCircleIcon
2259
+ LessThanSquareIcon
2260
+ LessThanIcon
2261
+ LetterSpacingIcon
2262
+ LibrariesIcon
2263
+ LibraryIcon
2264
+ LicenseDraftIcon
2265
+ LicenseMaintenanceIcon
2266
+ LicenseNoIcon
2267
+ LicensePinIcon
2268
+ LicenseIcon
2269
+ LicenseThirdPartyIcon
2270
+ LifebuoyIcon
2271
+ LiftTruckIcon
2272
+ LighthouseIcon
2273
+ LimitOrderIcon
2274
+ LimitationIcon
2275
+ LineIcon
2276
+ LinerIcon
2277
+ Link01Icon
2278
+ Link02Icon
2279
+ Link03Icon
2280
+ Link04Icon
2281
+ Link05Icon
2282
+ Link06Icon
2283
+ LinkBackwardIcon
2284
+ LinkCircle02Icon
2285
+ LinkCircleIcon
2286
+ LinkForwardIcon
2287
+ LinkSquare01Icon
2288
+ LinkSquare02Icon
2289
+ Linkedin01Icon
2290
+ Linkedin02Icon
2291
+ ListSettingIcon
2292
+ ListViewIcon
2293
+ LitecoinIcon
2294
+ LiveStreaming01Icon
2295
+ LiveStreaming02Icon
2296
+ LiveStreaming03Icon
2297
+ LiverIcon
2298
+ Loading01Icon
2299
+ Loading02Icon
2300
+ Loading03Icon
2301
+ Loading04Icon
2302
+ Location01Icon
2303
+ Location02Icon
2304
+ Location03Icon
2305
+ Location04Icon
2306
+ Location05Icon
2307
+ Location06Icon
2308
+ Location07Icon
2309
+ Location08Icon
2310
+ Location09Icon
2311
+ Location10Icon
2312
+ LocationAdd01Icon
2313
+ LocationAdd02Icon
2314
+ LocationCheck01Icon
2315
+ LocationCheck02Icon
2316
+ LocationFavourite01Icon
2317
+ LocationFavourite02Icon
2318
+ LocationOffline01Icon
2319
+ LocationOffline02Icon
2320
+ LocationOffline03Icon
2321
+ LocationOffline04Icon
2322
+ LocationRemove01Icon
2323
+ LocationRemove02Icon
2324
+ LocationShare01Icon
2325
+ LocationShare02Icon
2326
+ LocationStar01Icon
2327
+ LocationStar02Icon
2328
+ LocationUpdate01Icon
2329
+ LocationUpdate02Icon
2330
+ LocationUser01Icon
2331
+ LocationUser02Icon
2332
+ LocationUser03Icon
2333
+ LocationUser04Icon
2334
+ LockComputerIcon
2335
+ LockKeyIcon
2336
+ LockPasswordIcon
2337
+ LockIcon
2338
+ LockSync01Icon
2339
+ LockSync02Icon
2340
+ LockedIcon
2341
+ Locker01Icon
2342
+ LockerIcon
2343
+ Login01Icon
2344
+ Login02Icon
2345
+ Login03Icon
2346
+ LoginCircle01Icon
2347
+ LoginCircle02Icon
2348
+ LoginMethodIcon
2349
+ LoginSquare01Icon
2350
+ LoginSquare02Icon
2351
+ Logout01Icon
2352
+ Logout02Icon
2353
+ Logout03Icon
2354
+ Logout04Icon
2355
+ Logout05Icon
2356
+ LogoutCircle01Icon
2357
+ LogoutCircle02Icon
2358
+ LogoutSquare01Icon
2359
+ LogoutSquare02Icon
2360
+ LollipopIcon
2361
+ LongSleeveShirtIcon
2362
+ LongitudeIcon
2363
+ LookBottomIcon
2364
+ LookLeftIcon
2365
+ LookRightIcon
2366
+ LookTopIcon
2367
+ LoomIcon
2368
+ LottiefilesIcon
2369
+ LoveKoreanFingerIcon
2370
+ LowSignalIcon
2371
+ LoyaltyCardIcon
2372
+ Luggage01Icon
2373
+ Luggage02Icon
2374
+ LungsIcon
2375
+ MachineRobotIcon
2376
+ MagicWand01Icon
2377
+ MagicWand02Icon
2378
+ MagicWand03Icon
2379
+ MagicWand04Icon
2380
+ MagicWand05Icon
2381
+ Magnet01Icon
2382
+ Magnet02Icon
2383
+ MagnetIcon
2384
+ Mail01Icon
2385
+ Mail02Icon
2386
+ MailAccount01Icon
2387
+ MailAccount02Icon
2388
+ MailAdd01Icon
2389
+ MailAdd02Icon
2390
+ MailAtSign01Icon
2391
+ MailAtSign02Icon
2392
+ MailBlock01Icon
2393
+ MailBlock02Icon
2394
+ MailDownload01Icon
2395
+ MailDownload02Icon
2396
+ MailEdit01Icon
2397
+ MailEdit02Icon
2398
+ MailLock01Icon
2399
+ MailLock02Icon
2400
+ MailLove01Icon
2401
+ MailLove02Icon
2402
+ MailMinus01Icon
2403
+ MailMinus02Icon
2404
+ MailOpen01Icon
2405
+ MailOpen02Icon
2406
+ MailOpenLoveIcon
2407
+ MailOpenIcon
2408
+ MailReceive01Icon
2409
+ MailReceive02Icon
2410
+ MailRemove01Icon
2411
+ MailRemove02Icon
2412
+ MailReply01Icon
2413
+ MailReply02Icon
2414
+ MailReplyAll01Icon
2415
+ MailReplyAll02Icon
2416
+ MailSearch01Icon
2417
+ MailSearch02Icon
2418
+ MailSecure01Icon
2419
+ MailSecure02Icon
2420
+ MailSend01Icon
2421
+ MailSend02Icon
2422
+ MailSetting01Icon
2423
+ MailSetting02Icon
2424
+ MailUnlock01Icon
2425
+ MailUnlock02Icon
2426
+ MailUpload01Icon
2427
+ MailUpload02Icon
2428
+ MailValidation01Icon
2429
+ MailValidation02Icon
2430
+ MailVoice01Icon
2431
+ MailVoice02Icon
2432
+ Mailbox01Icon
2433
+ MailboxIcon
2434
+ Male02Icon
2435
+ MaleSymbolIcon
2436
+ ManIcon
2437
+ ManWomanIcon
2438
+ ManagerIcon
2439
+ MapPinIcon
2440
+ MapPinpoint01Icon
2441
+ MapPinpoint02Icon
2442
+ MapingIcon
2443
+ MapsCircle01Icon
2444
+ MapsCircle02Icon
2445
+ MapsEditingIcon
2446
+ MapsGlobal01Icon
2447
+ MapsGlobal02Icon
2448
+ MapsLocation01Icon
2449
+ MapsLocation02Icon
2450
+ MapsOffIcon
2451
+ MapsRefreshIcon
2452
+ MapsSearchIcon
2453
+ MapsSquare01Icon
2454
+ MapsSquare02Icon
2455
+ MapsIcon
2456
+ MarketAnalysisIcon
2457
+ MarketOrderIcon
2458
+ MarketingIcon
2459
+ MaskLoveIcon
2460
+ MaskIcon
2461
+ MaskTheater01Icon
2462
+ MaskTheater02Icon
2463
+ MasterCardIcon
2464
+ MastodonIcon
2465
+ MatchesIcon
2466
+ MaterialAndTextureIcon
2467
+ MathIcon
2468
+ MatrixIcon
2469
+ Maximize01Icon
2470
+ Maximize02Icon
2471
+ Maximize03Icon
2472
+ Maximize04Icon
2473
+ MaximizeScreenIcon
2474
+ MayanPyramidIcon
2475
+ MazeIcon
2476
+ McpServerIcon
2477
+ Medal01Icon
2478
+ Medal02Icon
2479
+ Medal03Icon
2480
+ Medal04Icon
2481
+ Medal05Icon
2482
+ Medal06Icon
2483
+ Medal07Icon
2484
+ MedalFirstPlaceIcon
2485
+ MedalSecondPlaceIcon
2486
+ MedalThirdPlaceIcon
2487
+ MedicalFileIcon
2488
+ MedicalMaskIcon
2489
+ Medicine01Icon
2490
+ Medicine02Icon
2491
+ MedicineBottle01Icon
2492
+ MedicineBottle02Icon
2493
+ MedicineSyrupIcon
2494
+ MediumSignalIcon
2495
+ MediumSquareIcon
2496
+ MediumIcon
2497
+ MeetingRoomIcon
2498
+ Megaphone01Icon
2499
+ Megaphone02Icon
2500
+ Megaphone03Icon
2501
+ MehIcon
2502
+ MentorIcon
2503
+ MentoringIcon
2504
+ Menu01Icon
2505
+ Menu02Icon
2506
+ Menu03Icon
2507
+ Menu04Icon
2508
+ Menu05Icon
2509
+ Menu06Icon
2510
+ Menu07Icon
2511
+ Menu08Icon
2512
+ Menu09Icon
2513
+ Menu10Icon
2514
+ Menu11Icon
2515
+ MenuCircleIcon
2516
+ MenuCollapseIcon
2517
+ MenuRestaurantIcon
2518
+ MenuSquareIcon
2519
+ MenuTwoLineIcon
2520
+ Message01Icon
2521
+ Message02Icon
2522
+ MessageAdd01Icon
2523
+ MessageAdd02Icon
2524
+ MessageBlockedIcon
2525
+ MessageCancel01Icon
2526
+ MessageCancel02Icon
2527
+ MessageDelay01Icon
2528
+ MessageDelay02Icon
2529
+ MessageDone01Icon
2530
+ MessageDone02Icon
2531
+ MessageDownload01Icon
2532
+ MessageDownload02Icon
2533
+ MessageEdit01Icon
2534
+ MessageEdit02Icon
2535
+ MessageFavourite01Icon
2536
+ MessageFavourite02Icon
2537
+ MessageIncoming01Icon
2538
+ MessageIncoming02Icon
2539
+ MessageLock01Icon
2540
+ MessageLock02Icon
2541
+ MessageMultiple01Icon
2542
+ MessageMultiple02Icon
2543
+ MessageNotification01Icon
2544
+ MessageNotification02Icon
2545
+ MessageOutgoing01Icon
2546
+ MessageOutgoing02Icon
2547
+ MessagePreview01Icon
2548
+ MessagePreview02Icon
2549
+ MessageProgrammingIcon
2550
+ MessageQuestionIcon
2551
+ MessageSearch01Icon
2552
+ MessageSearch02Icon
2553
+ MessageSecure01Icon
2554
+ MessageSecure02Icon
2555
+ MessageTranslateIcon
2556
+ MessageUnlock01Icon
2557
+ MessageUnlock02Icon
2558
+ MessageUpload01Icon
2559
+ MessageUpload02Icon
2560
+ MessageUser01Icon
2561
+ MessageUser02Icon
2562
+ MessengerIcon
2563
+ MetaIcon
2564
+ MetroIcon
2565
+ Mic01Icon
2566
+ Mic02Icon
2567
+ MicOff01Icon
2568
+ MicOff02Icon
2569
+ MicroscopeIcon
2570
+ MicrosoftAdminIcon
2571
+ MicrosoftIcon
2572
+ MicrowaveIcon
2573
+ MilkBottleIcon
2574
+ MilkCartonIcon
2575
+ MilkCoconutIcon
2576
+ MilkOatIcon
2577
+ Minimize01Icon
2578
+ Minimize02Icon
2579
+ Minimize03Icon
2580
+ Minimize04Icon
2581
+ MinimizeScreenIcon
2582
+ Mining01Icon
2583
+ Mining02Icon
2584
+ Mining03Icon
2585
+ MinusPlus01Icon
2586
+ MinusPlus02Icon
2587
+ MinusPlusCircle01Icon
2588
+ MinusPlusCircle02Icon
2589
+ MinusPlusSquare01Icon
2590
+ MinusPlusSquare02Icon
2591
+ MinusSignCircleIcon
2592
+ MinusSignSquareIcon
2593
+ MinusSignIcon
2594
+ MirrorIcon
2595
+ MirroringScreenIcon
2596
+ MistralIcon
2597
+ MixerIcon
2598
+ MobileNavigator01Icon
2599
+ MobileNavigator02Icon
2600
+ MobileProgramming01Icon
2601
+ MobileProgramming02Icon
2602
+ MobileProtectionIcon
2603
+ MobileSecurityIcon
2604
+ MochiIcon
2605
+ ModernTvFourKIcon
2606
+ ModernTvIssueIcon
2607
+ ModernTvIcon
2608
+ MoleculesIcon
2609
+ MollieIcon
2610
+ MonasIcon
2611
+ Money01Icon
2612
+ Money02Icon
2613
+ Money03Icon
2614
+ Money04Icon
2615
+ MoneyAdd01Icon
2616
+ MoneyAdd02Icon
2617
+ MoneyBag01Icon
2618
+ MoneyBag02Icon
2619
+ MoneyExchange01Icon
2620
+ MoneyExchange02Icon
2621
+ MoneyExchange03Icon
2622
+ MoneyNotFound01Icon
2623
+ MoneyNotFound02Icon
2624
+ MoneyNotFound03Icon
2625
+ MoneyNotFound04Icon
2626
+ MoneyReceive01Icon
2627
+ MoneyReceive02Icon
2628
+ MoneyReceiveCircleIcon
2629
+ MoneyReceiveFlow01Icon
2630
+ MoneyReceiveFlow02Icon
2631
+ MoneyReceiveSquareIcon
2632
+ MoneyRemove01Icon
2633
+ MoneyRemove02Icon
2634
+ MoneySafeIcon
2635
+ MoneySavingJarIcon
2636
+ MoneySecurityIcon
2637
+ MoneySend01Icon
2638
+ MoneySend02Icon
2639
+ MoneySendCircleIcon
2640
+ MoneySendFlow01Icon
2641
+ MoneySendFlow02Icon
2642
+ MoneySendSquareIcon
2643
+ Monocle01Icon
2644
+ MonocleIcon
2645
+ MonsterIcon
2646
+ Moon01Icon
2647
+ Moon02Icon
2648
+ MoonAngledRainZapIcon
2649
+ MoonCloudAngledRainIcon
2650
+ MoonCloudAngledZapIcon
2651
+ MoonCloudBigRainIcon
2652
+ MoonCloudFastWindIcon
2653
+ MoonCloudHailstoneIcon
2654
+ MoonCloudLittleRainIcon
2655
+ MoonCloudLittleSnowIcon
2656
+ MoonCloudMidRainIcon
2657
+ MoonCloudMidSnowIcon
2658
+ MoonCloudSlowWindIcon
2659
+ MoonCloudSnowIcon
2660
+ MoonCloudIcon
2661
+ MoonEclipseIcon
2662
+ MoonFastWindIcon
2663
+ MoonLandingIcon
2664
+ MoonSlowWindIcon
2665
+ MoonIcon
2666
+ MoonsetIcon
2667
+ More01Icon
2668
+ More02Icon
2669
+ More03Icon
2670
+ MoreHorizontalCircle01Icon
2671
+ MoreHorizontalCircle02Icon
2672
+ MoreHorizontalSquare01Icon
2673
+ MoreHorizontalSquare02Icon
2674
+ MoreHorizontalIcon
2675
+ MoreOrLessCircleIcon
2676
+ MoreOrLessSquareIcon
2677
+ MoreOrLessIcon
2678
+ MoreIcon
2679
+ MoreVerticalCircle01Icon
2680
+ MoreVerticalCircle02Icon
2681
+ MoreVerticalSquare01Icon
2682
+ MoreVerticalSquare02Icon
2683
+ MoreVerticalIcon
2684
+ MortarIcon
2685
+ Mortarboard01Icon
2686
+ Mortarboard02Icon
2687
+ Mosque01Icon
2688
+ Mosque02Icon
2689
+ Mosque03Icon
2690
+ Mosque04Icon
2691
+ Mosque05Icon
2692
+ MosqueLocationIcon
2693
+ Motion01Icon
2694
+ Motion02Icon
2695
+ Motorbike01Icon
2696
+ Motorbike02Icon
2697
+ MountainIcon
2698
+ Mouse01Icon
2699
+ Mouse02Icon
2700
+ Mouse03Icon
2701
+ Mouse04Icon
2702
+ Mouse05Icon
2703
+ Mouse06Icon
2704
+ Mouse07Icon
2705
+ Mouse08Icon
2706
+ Mouse09Icon
2707
+ Mouse10Icon
2708
+ Mouse11Icon
2709
+ Mouse12Icon
2710
+ Mouse13Icon
2711
+ Mouse14Icon
2712
+ Mouse15Icon
2713
+ Mouse16Icon
2714
+ Mouse17Icon
2715
+ Mouse18Icon
2716
+ Mouse19Icon
2717
+ Mouse20Icon
2718
+ Mouse21Icon
2719
+ Mouse22Icon
2720
+ Mouse23Icon
2721
+ MouseLeftClick01Icon
2722
+ MouseLeftClick02Icon
2723
+ MouseLeftClick03Icon
2724
+ MouseLeftClick04Icon
2725
+ MouseLeftClick05Icon
2726
+ MouseLeftClick06Icon
2727
+ MouseRightClick01Icon
2728
+ MouseRightClick02Icon
2729
+ MouseRightClick03Icon
2730
+ MouseRightClick04Icon
2731
+ MouseRightClick05Icon
2732
+ MouseRightClick06Icon
2733
+ MouseScroll01Icon
2734
+ MouseScroll02Icon
2735
+ Move01Icon
2736
+ Move02Icon
2737
+ MoveBottomIcon
2738
+ MoveLeftIcon
2739
+ MoveRightIcon
2740
+ MoveIcon
2741
+ MoveToIcon
2742
+ MoveTopIcon
2743
+ Mp302Icon
2744
+ Mp401Icon
2745
+ Mp402Icon
2746
+ Mp301Icon
2747
+ MuhammadIcon
2748
+ MultiplicationSignCircleIcon
2749
+ MultiplicationSignSquareIcon
2750
+ MultiplicationSignIcon
2751
+ Mushroom01Icon
2752
+ MushroomIcon
2753
+ MusicNote01Icon
2754
+ MusicNote02Icon
2755
+ MusicNote03Icon
2756
+ MusicNote04Icon
2757
+ MusicNoteSquare01Icon
2758
+ MusicNoteSquare02Icon
2759
+ MuslimIcon
2760
+ MuteIcon
2761
+ MymindIcon
2762
+ NThRootCircleIcon
2763
+ NThRootSquareIcon
2764
+ NThRootIcon
2765
+ NanoTechnologyIcon
2766
+ Napkins01Icon
2767
+ Napkins02Icon
2768
+ NaturalFoodIcon
2769
+ Navigation01Icon
2770
+ Navigation02Icon
2771
+ Navigation03Icon
2772
+ Navigation04Icon
2773
+ Navigation05Icon
2774
+ Navigation06Icon
2775
+ Navigator01Icon
2776
+ Navigator02Icon
2777
+ NecklaceIcon
2778
+ NerdIcon
2779
+ NeuralNetworkIcon
2780
+ NeutralIcon
2781
+ NewJobIcon
2782
+ NewOfficeIcon
2783
+ NewReleasesIcon
2784
+ NewTwitterEllipseIcon
2785
+ NewTwitterRectangleIcon
2786
+ NewTwitterIcon
2787
+ News01Icon
2788
+ NewsIcon
2789
+ NextIcon
2790
+ NikeIcon
2791
+ NineCircleIcon
2792
+ NineSquareIcon
2793
+ NintendoIcon
2794
+ NintendoSwitchIcon
2795
+ NiqabIcon
2796
+ NoInternetIcon
2797
+ NoMeetingRoomIcon
2798
+ NoSignalIcon
2799
+ NodeAddIcon
2800
+ NodeEditIcon
2801
+ NodeMoveDownIcon
2802
+ NodeMoveUpIcon
2803
+ NodeRemoveIcon
2804
+ NoodlesIcon
2805
+ NoseIcon
2806
+ NotEqualSignCircleIcon
2807
+ NotEqualSignSquareIcon
2808
+ NotEqualSignIcon
2809
+ Note01Icon
2810
+ Note02Icon
2811
+ Note03Icon
2812
+ Note04Icon
2813
+ Note05Icon
2814
+ NoteAddIcon
2815
+ NoteDoneIcon
2816
+ NoteEditIcon
2817
+ NoteRemoveIcon
2818
+ NoteIcon
2819
+ Notebook01Icon
2820
+ Notebook02Icon
2821
+ NotebookIcon
2822
+ Notification01Icon
2823
+ Notification02Icon
2824
+ Notification03Icon
2825
+ NotificationBlock01Icon
2826
+ NotificationBlock02Icon
2827
+ NotificationBlock03Icon
2828
+ NotificationBubbleIcon
2829
+ NotificationCircleIcon
2830
+ NotificationOff01Icon
2831
+ NotificationOff02Icon
2832
+ NotificationOff03Icon
2833
+ NotificationSnooze01Icon
2834
+ NotificationSnooze02Icon
2835
+ NotificationSnooze03Icon
2836
+ NotificationSquareIcon
2837
+ Notion01Icon
2838
+ Notion02Icon
2839
+ NpmIcon
2840
+ NuclearPowerIcon
2841
+ NutIcon
2842
+ ObtuseIcon
2843
+ OctagonIcon
2844
+ OctopusIcon
2845
+ Office365Icon
2846
+ OfficeChairIcon
2847
+ OfficeIcon
2848
+ OilBarrelIcon
2849
+ OkFingerIcon
2850
+ OlympicTorchIcon
2851
+ OneCircleIcon
2852
+ OneSquareIcon
2853
+ OnlineLearning01Icon
2854
+ OnlineLearning02Icon
2855
+ OnlineLearning03Icon
2856
+ OnlineLearning04Icon
2857
+ OpenCaptionIcon
2858
+ OpenSourceIcon
2859
+ OptionIcon
2860
+ OrangeIcon
2861
+ Orbit01Icon
2862
+ Orbit02Icon
2863
+ OrganicFoodIcon
2864
+ OrthogonalEdgeIcon
2865
+ OvalIcon
2866
+ OvenIcon
2867
+ Package01Icon
2868
+ Package02Icon
2869
+ Package03Icon
2870
+ PackageAdd01Icon
2871
+ PackageAddIcon
2872
+ PackageDelivered01Icon
2873
+ PackageDeliveredIcon
2874
+ PackageDimensions01Icon
2875
+ PackageDimensions02Icon
2876
+ PackageMoving01Icon
2877
+ PackageMovingIcon
2878
+ PackageOpenIcon
2879
+ PackageOutOfStockIcon
2880
+ PackageProcess01Icon
2881
+ PackageProcessIcon
2882
+ PackageReceive01Icon
2883
+ PackageReceiveIcon
2884
+ PackageRemove01Icon
2885
+ PackageRemoveIcon
2886
+ PackageSearch01Icon
2887
+ PackageSearchIcon
2888
+ PackageSent01Icon
2889
+ PackageSentIcon
2890
+ PackageIcon
2891
+ PackagingIcon
2892
+ Pacman01Icon
2893
+ Pacman02Icon
2894
+ PaellaIcon
2895
+ PaintBoardIcon
2896
+ PaintBrush01Icon
2897
+ PaintBrush02Icon
2898
+ PaintBrush03Icon
2899
+ PaintBrush04Icon
2900
+ PaintBucketIcon
2901
+ Pan01Icon
2902
+ Pan02Icon
2903
+ Pan03Icon
2904
+ Parabola01Icon
2905
+ Parabola02Icon
2906
+ Parabola03Icon
2907
+ ParaglidingIcon
2908
+ ParagraphBulletsPoint01Icon
2909
+ ParagraphBulletsPoint02Icon
2910
+ ParagraphSpacingIcon
2911
+ ParagraphIcon
2912
+ ParallelogramIcon
2913
+ ParkingAreaCircleIcon
2914
+ ParkingAreaSquareIcon
2915
+ PartyIcon
2916
+ Passport01Icon
2917
+ PassportExpiredIcon
2918
+ PassportIcon
2919
+ PassportValidIcon
2920
+ PasswordValidationIcon
2921
+ PathIcon
2922
+ PathfinderCropIcon
2923
+ PathfinderDivideIcon
2924
+ PathfinderExcludeIcon
2925
+ PathfinderIntersectIcon
2926
+ PathfinderMergeIcon
2927
+ PathfinderMinusBackIcon
2928
+ PathfinderMinusFrontIcon
2929
+ PathfinderOutlineIcon
2930
+ PathfinderTrimIcon
2931
+ PathfinderUniteIcon
2932
+ PatientIcon
2933
+ PatioIcon
2934
+ PauseCircleIcon
2935
+ PauseIcon
2936
+ PavilonIcon
2937
+ PayByCheckIcon
2938
+ Payment01Icon
2939
+ Payment02Icon
2940
+ PaymentSuccess01Icon
2941
+ PaymentSuccess02Icon
2942
+ PayoneerIcon
2943
+ PaypalIcon
2944
+ Pdf01Icon
2945
+ Pdf02Icon
2946
+ PeerToPeer01Icon
2947
+ PeerToPeer02Icon
2948
+ PeerToPeer03Icon
2949
+ Pen01Icon
2950
+ Pen02Icon
2951
+ PenConnectBluetoothIcon
2952
+ PenConnectUsbIcon
2953
+ PenConnectWifiIcon
2954
+ PenTool01Icon
2955
+ PenTool02Icon
2956
+ PenTool03Icon
2957
+ PenToolAddIcon
2958
+ PenToolMinusIcon
2959
+ PencilEdit01Icon
2960
+ PencilEdit02Icon
2961
+ PencilIcon
2962
+ PendulumIcon
2963
+ PensiveIcon
2964
+ Pentagon01Icon
2965
+ PentagonIcon
2966
+ PercentCircleIcon
2967
+ PercentSquareIcon
2968
+ PercentIcon
2969
+ PerfumeIcon
2970
+ PeriscopeIcon
2971
+ PermanentJobIcon
2972
+ PerplexityAiIcon
2973
+ PerspectiveIcon
2974
+ PetrolPumpIcon
2975
+ PexelsIcon
2976
+ PhoneArrowDownIcon
2977
+ PhoneArrowUpIcon
2978
+ PhoneCheckIcon
2979
+ PhoneDeveloperModeIcon
2980
+ PhoneEraseIcon
2981
+ PhoneLockIcon
2982
+ PhoneOff01Icon
2983
+ PhoneOff02Icon
2984
+ PhpIcon
2985
+ PhysicsIcon
2986
+ PiCircleIcon
2987
+ PiSquareIcon
2988
+ PiIcon
2989
+ PicasaIcon
2990
+ Pickup01Icon
2991
+ Pickup02Icon
2992
+ PictureInPictureExitIcon
2993
+ PictureInPictureOnIcon
2994
+ PieChart01Icon
2995
+ PieChart02Icon
2996
+ PieChart03Icon
2997
+ PieChart04Icon
2998
+ PieChart05Icon
2999
+ PieChart06Icon
3000
+ PieChart07Icon
3001
+ PieChart08Icon
3002
+ PieChart09Icon
3003
+ PieChartSquareIcon
3004
+ PieChartIcon
3005
+ PieIcon
3006
+ PiggyBankIcon
3007
+ Pin02Icon
3008
+ PinCodeIcon
3009
+ PinLocation01Icon
3010
+ PinLocation02Icon
3011
+ PinLocation03Icon
3012
+ PinOffIcon
3013
+ PinIcon
3014
+ PineTreeIcon
3015
+ PinterestIcon
3016
+ PipelineIcon
3017
+ PisaTowerIcon
3018
+ PivotIcon
3019
+ Pizza01Icon
3020
+ Pizza02Icon
3021
+ Pizza03Icon
3022
+ Pizza04Icon
3023
+ PizzaCutterIcon
3024
+ PlaneIcon
3025
+ Plant01Icon
3026
+ Plant02Icon
3027
+ Plant03Icon
3028
+ Plant04Icon
3029
+ PlateIcon
3030
+ PlaxoIcon
3031
+ PlayCircle02Icon
3032
+ PlayCircleIcon
3033
+ PlayListAddIcon
3034
+ PlayListFavourite01Icon
3035
+ PlayListFavourite02Icon
3036
+ PlayListMinusIcon
3037
+ PlayListRemoveIcon
3038
+ PlayListIcon
3039
+ PlaySquareIcon
3040
+ PlayStoreIcon
3041
+ PlayIcon
3042
+ Playlist01Icon
3043
+ Playlist02Icon
3044
+ Playlist03Icon
3045
+ PlazaIcon
3046
+ Plug01Icon
3047
+ Plug02Icon
3048
+ PlugSocketIcon
3049
+ PlusMinus01Icon
3050
+ PlusMinus02Icon
3051
+ PlusMinusCircle01Icon
3052
+ PlusMinusCircle02Icon
3053
+ PlusMinusSquare01Icon
3054
+ PlusMinusSquare02Icon
3055
+ PlusMinusIcon
3056
+ PlusSignCircleIcon
3057
+ PlusSignSquareIcon
3058
+ PlusSignIcon
3059
+ Png01Icon
3060
+ Png02Icon
3061
+ PodcastIcon
3062
+ PodiumIcon
3063
+ PointingLeft01Icon
3064
+ PointingLeft02Icon
3065
+ PointingLeft03Icon
3066
+ PointingLeft04Icon
3067
+ PointingLeft05Icon
3068
+ PointingLeft06Icon
3069
+ PointingLeft07Icon
3070
+ PointingLeft08Icon
3071
+ PointingRight01Icon
3072
+ PointingRight02Icon
3073
+ PointingRight03Icon
3074
+ PointingRight04Icon
3075
+ PointingRight05Icon
3076
+ PointingRight06Icon
3077
+ PointingRight07Icon
3078
+ PointingRight08Icon
3079
+ PokeballIcon
3080
+ PokemonIcon
3081
+ PoliceBadgeIcon
3082
+ PoliceCapIcon
3083
+ PoliceCarIcon
3084
+ PoliceStationIcon
3085
+ PolicyIcon
3086
+ PolyTankIcon
3087
+ PolygonIcon
3088
+ PoolIcon
3089
+ PoolTableIcon
3090
+ PoopIcon
3091
+ PopcornIcon
3092
+ Pot01Icon
3093
+ Pot02Icon
3094
+ PotionIcon
3095
+ PoundCircleIcon
3096
+ PoundReceiveIcon
3097
+ PoundSendIcon
3098
+ PoundSquareIcon
3099
+ PoundIcon
3100
+ PowerServiceIcon
3101
+ PowerSocket01Icon
3102
+ PowerSocket02Icon
3103
+ Ppt01Icon
3104
+ Ppt02Icon
3105
+ PrawnIcon
3106
+ PrayerRug01Icon
3107
+ PrayerRug02Icon
3108
+ PreferenceHorizontalIcon
3109
+ PreferenceVerticalIcon
3110
+ PrescriptionIcon
3111
+ Presentation01Icon
3112
+ Presentation02Icon
3113
+ Presentation03Icon
3114
+ Presentation04Icon
3115
+ Presentation05Icon
3116
+ Presentation06Icon
3117
+ Presentation07Icon
3118
+ PresentationBarChart01Icon
3119
+ PresentationBarChart02Icon
3120
+ PresentationLineChart01Icon
3121
+ PresentationLineChart02Icon
3122
+ PresentationOnlineIcon
3123
+ PresentationPodiumIcon
3124
+ PreviousIcon
3125
+ PrinterThreeDIcon
3126
+ PrinterOffIcon
3127
+ PrinterIcon
3128
+ Prism01Icon
3129
+ PrismIcon
3130
+ PrisonGuardIcon
3131
+ PrisonIcon
3132
+ PrisonerIcon
3133
+ ProductLoadingIcon
3134
+ Profile02Icon
3135
+ ProfileIcon
3136
+ ProfitIcon
3137
+ ProgrammingFlagIcon
3138
+ Progress01Icon
3139
+ Progress02Icon
3140
+ Progress03Icon
3141
+ Progress04Icon
3142
+ ProgressIcon
3143
+ Projector01Icon
3144
+ ProjectorIcon
3145
+ PromotionIcon
3146
+ PropertyAddIcon
3147
+ PropertyDeleteIcon
3148
+ PropertyEditIcon
3149
+ PropertyNewIcon
3150
+ PropertySearchIcon
3151
+ PropertyViewIcon
3152
+ ProtectionMaskIcon
3153
+ PulleyIcon
3154
+ Pulse01Icon
3155
+ Pulse02Icon
3156
+ PulseRectangle01Icon
3157
+ PulseRectangle02Icon
3158
+ PumpkinIcon
3159
+ PunchIcon
3160
+ PunchingBall01Icon
3161
+ PunchingBall02Icon
3162
+ Purse01Icon
3163
+ PurseIcon
3164
+ PushUpBarIcon
3165
+ PuzzleIcon
3166
+ PyramidMaslowoIcon
3167
+ PyramidIcon
3168
+ PyramidStructure01Icon
3169
+ PyramidStructure02Icon
3170
+ PythonIcon
3171
+ QqPlotIcon
3172
+ QrCode01Icon
3173
+ QrCodeIcon
3174
+ QuestionIcon
3175
+ Queue01Icon
3176
+ Queue02Icon
3177
+ QuillWrite01Icon
3178
+ QuillWrite02Icon
3179
+ Quiz01Icon
3180
+ Quiz02Icon
3181
+ Quiz03Icon
3182
+ Quiz04Icon
3183
+ Quiz05Icon
3184
+ QuoraIcon
3185
+ QuoteDownCircleIcon
3186
+ QuoteDownSquareIcon
3187
+ QuoteDownIcon
3188
+ QuoteUpCircleIcon
3189
+ QuoteUpSquareIcon
3190
+ QuoteUpIcon
3191
+ QuotesIcon
3192
+ Quran01Icon
3193
+ Quran02Icon
3194
+ Quran03Icon
3195
+ QwenIcon
3196
+ RacingFlagIcon
3197
+ Radar01Icon
3198
+ Radar02Icon
3199
+ RadialIcon
3200
+ Radio01Icon
3201
+ Radio02Icon
3202
+ RadioButtonIcon
3203
+ RadioIcon
3204
+ RadioactiveAlertIcon
3205
+ RadiusIcon
3206
+ RainDoubleDropIcon
3207
+ RainDropIcon
3208
+ RainIcon
3209
+ RainbowIcon
3210
+ Ramadhan01Icon
3211
+ Ramadhan02Icon
3212
+ RamadhanMonthIcon
3213
+ RankingIcon
3214
+ Rar01Icon
3215
+ Rar02Icon
3216
+ Raw01Icon
3217
+ Raw02Icon
3218
+ ReIcon
3219
+ ReactIcon
3220
+ RealEstate01Icon
3221
+ RealEstate02Icon
3222
+ ReceiptDollarIcon
3223
+ RecordIcon
3224
+ RecoveryMailIcon
3225
+ Rectangular01Icon
3226
+ RectangularIcon
3227
+ Recycle01Icon
3228
+ Recycle02Icon
3229
+ Recycle03Icon
3230
+ RedditIcon
3231
+ Redo02Icon
3232
+ Redo03Icon
3233
+ RedoIcon
3234
+ ReflexIcon
3235
+ RefreshIcon
3236
+ RefrigeratorIcon
3237
+ RegisterIcon
3238
+ RegisteredIcon
3239
+ Relieved01Icon
3240
+ Relieved02Icon
3241
+ ReloadIcon
3242
+ ReminderIcon
3243
+ RemoteControlIcon
3244
+ Remove01Icon
3245
+ Remove02Icon
3246
+ RemoveCircleHalfDotIcon
3247
+ RemoveCircleIcon
3248
+ RemoveFemaleIcon
3249
+ RemoveMaleIcon
3250
+ RemovePiIcon
3251
+ RemoveSquareIcon
3252
+ RenewableEnergy01Icon
3253
+ RenewableEnergyIcon
3254
+ RepairIcon
3255
+ RepeatOffIcon
3256
+ RepeatOne01Icon
3257
+ RepeatOne02Icon
3258
+ RepeatIcon
3259
+ ReplayIcon
3260
+ ReplitIcon
3261
+ RepositoryIcon
3262
+ ResetPasswordIcon
3263
+ Resize01Icon
3264
+ Resize02Icon
3265
+ ResizeFieldRectangleIcon
3266
+ ResizeFieldIcon
3267
+ ResourcesAddIcon
3268
+ ResourcesRemoveIcon
3269
+ Restaurant01Icon
3270
+ Restaurant02Icon
3271
+ Restaurant03Icon
3272
+ RestaurantIcon
3273
+ RestaurantTableIcon
3274
+ RestoreBinIcon
3275
+ ReturnRequestIcon
3276
+ ReverseWithdrawal01Icon
3277
+ ReverseWithdrawal02Icon
3278
+ Rhombus01Icon
3279
+ RhombusIcon
3280
+ RiceBowl01Icon
3281
+ RiceBowl02Icon
3282
+ RightAngleIcon
3283
+ RightToLeftBlockQuoteIcon
3284
+ RightToLeftListBulletIcon
3285
+ RightToLeftListDashIcon
3286
+ RightToLeftListNumberIcon
3287
+ RightToLeftListTriangleIcon
3288
+ RightTriangleIcon
3289
+ RippleIcon
3290
+ RiyalRectangleIcon
3291
+ RiyalIcon
3292
+ Road01Icon
3293
+ Road02Icon
3294
+ RoadLocation01Icon
3295
+ RoadLocation02Icon
3296
+ RoadIcon
3297
+ RoadWaysideIcon
3298
+ Robot01Icon
3299
+ Robot02Icon
3300
+ RoboticIcon
3301
+ Rocket01Icon
3302
+ Rocket02Icon
3303
+ RocketIcon
3304
+ RockingChairIcon
3305
+ RockingHorseIcon
3306
+ RollerSkateIcon
3307
+ RollingPinIcon
3308
+ Root01Icon
3309
+ Root02Icon
3310
+ RootFirstBracketIcon
3311
+ RootSecondBracketIcon
3312
+ RootThirdBracketIcon
3313
+ RootCircleIcon
3314
+ Rotate01Icon
3315
+ Rotate02Icon
3316
+ Rotate360Icon
3317
+ RotateBottomLeftIcon
3318
+ RotateBottomRightIcon
3319
+ RotateClockwiseIcon
3320
+ RotateCropIcon
3321
+ RotateLeft01Icon
3322
+ RotateLeft02Icon
3323
+ RotateLeft03Icon
3324
+ RotateLeft04Icon
3325
+ RotateLeft05Icon
3326
+ RotateLeft06Icon
3327
+ RotateRight01Icon
3328
+ RotateRight02Icon
3329
+ RotateRight03Icon
3330
+ RotateRight04Icon
3331
+ RotateRight05Icon
3332
+ RotateRight06Icon
3333
+ RotateSquareIcon
3334
+ RotateTopLeftIcon
3335
+ RotateTopRightIcon
3336
+ Route01Icon
3337
+ Route02Icon
3338
+ Route03Icon
3339
+ RouteBlockIcon
3340
+ Router01Icon
3341
+ Router02Icon
3342
+ RouterIcon
3343
+ RowDeleteIcon
3344
+ RowInsertIcon
3345
+ RssConnected01Icon
3346
+ RssConnected02Icon
3347
+ RssErrorIcon
3348
+ RssLockedIcon
3349
+ RssIcon
3350
+ RssUnlockedIcon
3351
+ RubElHizbIcon
3352
+ RubberDuckIcon
3353
+ RubiksCubeIcon
3354
+ RukuIcon
3355
+ RulerIcon
3356
+ RunningShoesIcon
3357
+ Sad01Icon
3358
+ Sad02Icon
3359
+ SadDizzyIcon
3360
+ SafariIcon
3361
+ SafeDelivery01Icon
3362
+ SafeDelivery02Icon
3363
+ SafeIcon
3364
+ SafetyPin01Icon
3365
+ SafetyPin02Icon
3366
+ SailboatCoastalIcon
3367
+ SailboatOffshoreIcon
3368
+ SakuraIcon
3369
+ SalahIcon
3370
+ SalahTimeIcon
3371
+ SaleTag01Icon
3372
+ SaleTag02Icon
3373
+ SandalsIcon
3374
+ Satellite01Icon
3375
+ Satellite02Icon
3376
+ Satellite03Icon
3377
+ SatelliteIcon
3378
+ Saturn01Icon
3379
+ Saturn02Icon
3380
+ SaturnIcon
3381
+ SausageIcon
3382
+ SaveEnergy01Icon
3383
+ SaveEnergy02Icon
3384
+ SaveMoneyDollarIcon
3385
+ SaveMoneyEuroIcon
3386
+ SaveMoneyPoundIcon
3387
+ SaveMoneyYenIcon
3388
+ SavingsIcon
3389
+ SchemeIcon
3390
+ School01Icon
3391
+ SchoolBell01Icon
3392
+ SchoolBell02Icon
3393
+ SchoolBusIcon
3394
+ SchoolReportCardIcon
3395
+ SchoolIcon
3396
+ SchoolTieIcon
3397
+ Scissor01Icon
3398
+ ScissorRectangleIcon
3399
+ ScissorIcon
3400
+ Scooter01Icon
3401
+ Scooter02Icon
3402
+ Scooter03Icon
3403
+ Scooter04Icon
3404
+ ScooterElectricIcon
3405
+ ScratchCardIcon
3406
+ ScreenAddToHome02Icon
3407
+ ScreenAddToHomeIcon
3408
+ ScreenLockRotationIcon
3409
+ ScreenRotationIcon
3410
+ ScribdIcon
3411
+ ScrollHorizontalIcon
3412
+ ScrollIcon
3413
+ ScrollVerticalIcon
3414
+ SdCardIcon
3415
+ SealIcon
3416
+ Search01Icon
3417
+ Search02Icon
3418
+ SearchAddIcon
3419
+ SearchAreaIcon
3420
+ SearchCircleIcon
3421
+ SearchDollarIcon
3422
+ SearchFocusIcon
3423
+ SearchList01Icon
3424
+ SearchList02Icon
3425
+ SearchMinusIcon
3426
+ SearchRemoveIcon
3427
+ SearchReplaceIcon
3428
+ SearchSquareIcon
3429
+ SearchVisualIcon
3430
+ SearchingIcon
3431
+ SeatSelectorIcon
3432
+ SecuredNetworkIcon
3433
+ SecurityBlockIcon
3434
+ SecurityCheckIcon
3435
+ SecurityKeyUsbIcon
3436
+ SecurityLockIcon
3437
+ SecurityPasswordIcon
3438
+ SecurityIcon
3439
+ SecurityValidationIcon
3440
+ SecurityWifiIcon
3441
+ SeesawIcon
3442
+ SegmentIcon
3443
+ Select01Icon
3444
+ Select02Icon
3445
+ SelfTransferIcon
3446
+ SemiTruckIcon
3447
+ SendToMobile02Icon
3448
+ SendToMobileIcon
3449
+ SendingOrderIcon
3450
+ SenselessIcon
3451
+ Sent02Icon
3452
+ SentIcon
3453
+ SeoIcon
3454
+ ServerStack01Icon
3455
+ ServerStack02Icon
3456
+ ServerStack03Icon
3457
+ ServiceIcon
3458
+ ServingFoodIcon
3459
+ Setting06Icon
3460
+ Setting07Icon
3461
+ SettingDone01Icon
3462
+ SettingDone02Icon
3463
+ SettingDone03Icon
3464
+ SettingDone04Icon
3465
+ SettingError03Icon
3466
+ SettingError04Icon
3467
+ Settings01Icon
3468
+ Settings02Icon
3469
+ Settings03Icon
3470
+ Settings04Icon
3471
+ Settings05Icon
3472
+ SettingsError01Icon
3473
+ SettingsError02Icon
3474
+ Setup01Icon
3475
+ Setup02Icon
3476
+ SevenCircleIcon
3477
+ SevenSquareIcon
3478
+ Shaka01Icon
3479
+ Shaka02Icon
3480
+ Shaka03Icon
3481
+ Shaka04Icon
3482
+ ShampooIcon
3483
+ ShapeCollectionIcon
3484
+ ShapesIcon
3485
+ Share01Icon
3486
+ Share02Icon
3487
+ Share03Icon
3488
+ Share04Icon
3489
+ Share05Icon
3490
+ Share06Icon
3491
+ Share07Icon
3492
+ Share08Icon
3493
+ ShareKnowledgeIcon
3494
+ ShareLocation01Icon
3495
+ ShareLocation02Icon
3496
+ SharedDriveIcon
3497
+ SharedWifiIcon
3498
+ SharingIcon
3499
+ ShellfishIcon
3500
+ Sheriff01Icon
3501
+ Sheriff02Icon
3502
+ Shield01Icon
3503
+ Shield02Icon
3504
+ ShieldBlockchainIcon
3505
+ ShieldEnergyIcon
3506
+ ShieldKeyIcon
3507
+ ShieldUserIcon
3508
+ ShipmentTrackingIcon
3509
+ ShippingCenterIcon
3510
+ ShippingLoadingIcon
3511
+ ShippingTruck01Icon
3512
+ ShippingTruck02Icon
3513
+ Shirt01Icon
3514
+ ShockedIcon
3515
+ ShopSignIcon
3516
+ ShopifyIcon
3517
+ ShoppingBag01Icon
3518
+ ShoppingBag02Icon
3519
+ ShoppingBag03Icon
3520
+ ShoppingBagAddIcon
3521
+ ShoppingBagCheckIcon
3522
+ ShoppingBagFavoriteIcon
3523
+ ShoppingBagRemoveIcon
3524
+ ShoppingBasket01Icon
3525
+ ShoppingBasket02Icon
3526
+ ShoppingBasket03Icon
3527
+ ShoppingBasketAdd01Icon
3528
+ ShoppingBasketAdd02Icon
3529
+ ShoppingBasketAdd03Icon
3530
+ ShoppingBasketCheckIn01Icon
3531
+ ShoppingBasketCheckIn02Icon
3532
+ ShoppingBasketCheckIn03Icon
3533
+ ShoppingBasketCheckOut01Icon
3534
+ ShoppingBasketCheckOut02Icon
3535
+ ShoppingBasketCheckOut03Icon
3536
+ ShoppingBasketDone01Icon
3537
+ ShoppingBasketDone02Icon
3538
+ ShoppingBasketDone03Icon
3539
+ ShoppingBasketFavorite01Icon
3540
+ ShoppingBasketFavorite02Icon
3541
+ ShoppingBasketFavorite03Icon
3542
+ ShoppingBasketRemove01Icon
3543
+ ShoppingBasketRemove02Icon
3544
+ ShoppingBasketRemove03Icon
3545
+ ShoppingBasketSecure01Icon
3546
+ ShoppingBasketSecure02Icon
3547
+ ShoppingBasketSecure03Icon
3548
+ ShoppingCart01Icon
3549
+ ShoppingCart02Icon
3550
+ ShoppingCartAdd01Icon
3551
+ ShoppingCartAdd02Icon
3552
+ ShoppingCartCheck01Icon
3553
+ ShoppingCartCheck02Icon
3554
+ ShoppingCartCheckIn01Icon
3555
+ ShoppingCartCheckIn02Icon
3556
+ ShoppingCartCheckOut01Icon
3557
+ ShoppingCartCheckOut02Icon
3558
+ ShoppingCartFavorite01Icon
3559
+ ShoppingCartFavorite02Icon
3560
+ ShoppingCartRemove01Icon
3561
+ ShoppingCartRemove02Icon
3562
+ ShortsPantsIcon
3563
+ ShoulderIcon
3564
+ ShuffleSquareIcon
3565
+ ShuffleIcon
3566
+ ShutDownIcon
3567
+ ShutterstockIcon
3568
+ SidebarBottomIcon
3569
+ SidebarLeft01Icon
3570
+ SidebarLeftIcon
3571
+ SidebarRight01Icon
3572
+ SidebarRightIcon
3573
+ SidebarTopIcon
3574
+ SignLanguageCIcon
3575
+ SignalFull01Icon
3576
+ SignalFull02Icon
3577
+ SignalLow01Icon
3578
+ SignalLow02Icon
3579
+ SignalLowMediumIcon
3580
+ SignalMedium01Icon
3581
+ SignalMedium02Icon
3582
+ SignalNo01Icon
3583
+ SignalNo02Icon
3584
+ SignalIcon
3585
+ SignatureIcon
3586
+ SilenceIcon
3587
+ Simcard01Icon
3588
+ Simcard02Icon
3589
+ SimcardDualIcon
3590
+ SinIcon
3591
+ Sine01Icon
3592
+ Sine02Icon
3593
+ SingLeftIcon
3594
+ SingRightIcon
3595
+ Sink01Icon
3596
+ Sink02Icon
3597
+ SiriNewIcon
3598
+ SiriIcon
3599
+ SixCircleIcon
3600
+ SixSquareIcon
3601
+ SketchIcon
3602
+ SkewIcon
3603
+ SkiIcon
3604
+ SkippingRopeIcon
3605
+ SkoolIcon
3606
+ SkullIcon
3607
+ SkypeIcon
3608
+ SlackIcon
3609
+ SleepingIcon
3610
+ SleevelessIcon
3611
+ SlideIcon
3612
+ SlidersHorizontalIcon
3613
+ SlidersVerticalIcon
3614
+ SlideshareIcon
3615
+ SlowWindsIcon
3616
+ SmartAcIcon
3617
+ SmartPhone01Icon
3618
+ SmartPhone02Icon
3619
+ SmartPhone03Icon
3620
+ SmartPhone04Icon
3621
+ SmartPhoneLandscape02Icon
3622
+ SmartPhoneLandscapeIcon
3623
+ SmartIcon
3624
+ SmartWatch01Icon
3625
+ SmartWatch02Icon
3626
+ SmartWatch03Icon
3627
+ SmartWatch04Icon
3628
+ SmartphoneLostWifiIcon
3629
+ SmartphoneWifiIcon
3630
+ SmileDizzyIcon
3631
+ SmileIcon
3632
+ SmsCodeIcon
3633
+ SnailIcon
3634
+ SnapchatIcon
3635
+ SnowIcon
3636
+ SocksIcon
3637
+ SodaCanIcon
3638
+ Sofa01Icon
3639
+ Sofa02Icon
3640
+ Sofa03Icon
3641
+ SofaSingleIcon
3642
+ SoftDrink01Icon
3643
+ SoftDrink02Icon
3644
+ SoftwareLicenseIcon
3645
+ SoftwareIcon
3646
+ SoftwareUninstallIcon
3647
+ SoilMoistureFieldIcon
3648
+ SoilMoistureGlobalIcon
3649
+ SoilTemperatureFieldIcon
3650
+ SoilTemperatureGlobalIcon
3651
+ SolarEnergyIcon
3652
+ SolarPanel01Icon
3653
+ SolarPanel02Icon
3654
+ SolarPanel03Icon
3655
+ SolarPanel04Icon
3656
+ SolarPanel05Icon
3657
+ SolarPowerIcon
3658
+ SolarSystem01Icon
3659
+ SolarSystemIcon
3660
+ SolidLine01Icon
3661
+ SolidLine02Icon
3662
+ SortByDown01Icon
3663
+ SortByDown02Icon
3664
+ SortByUp01Icon
3665
+ SortByUp02Icon
3666
+ Sorting01Icon
3667
+ Sorting02Icon
3668
+ Sorting03Icon
3669
+ Sorting04Icon
3670
+ Sorting05Icon
3671
+ Sorting19Icon
3672
+ Sorting91Icon
3673
+ SortingAZ01Icon
3674
+ SortingAZ02Icon
3675
+ SortingDownIcon
3676
+ SortingUpIcon
3677
+ SortingZA01Icon
3678
+ SoundcloudIcon
3679
+ SourceCodeCircleIcon
3680
+ SourceCodeSquareIcon
3681
+ SourceCodeIcon
3682
+ SpaceshipIcon
3683
+ SpadesIcon
3684
+ SpaghettiIcon
3685
+ SpamIcon
3686
+ SparklesIcon
3687
+ SpartanHelmetIcon
3688
+ SpatulaIcon
3689
+ Speaker01Icon
3690
+ SpeakerIcon
3691
+ SpeechToTextIcon
3692
+ SpeedTrain01Icon
3693
+ SpeedTrain02Icon
3694
+ SpermIcon
3695
+ SphereIcon
3696
+ SpiralsIcon
3697
+ SpoonAndForkIcon
3698
+ SpoonAndKnifeIcon
3699
+ SpoonIcon
3700
+ SpotifyIcon
3701
+ SqlIcon
3702
+ Square01Icon
3703
+ SquareArrowDataTransferDiagonalIcon
3704
+ SquareArrowDataTransferHorizontalIcon
3705
+ SquareArrowDataTransferVerticalIcon
3706
+ SquareArrowDiagonal01Icon
3707
+ SquareArrowDiagonal02Icon
3708
+ SquareArrowDown01Icon
3709
+ SquareArrowDown02Icon
3710
+ SquareArrowDown03Icon
3711
+ SquareArrowDownDoubleIcon
3712
+ SquareArrowDownLeftIcon
3713
+ SquareArrowDownRightIcon
3714
+ SquareArrowExpand01Icon
3715
+ SquareArrowExpand02Icon
3716
+ SquareArrowHorizontalIcon
3717
+ SquareArrowLeft01Icon
3718
+ SquareArrowLeft02Icon
3719
+ SquareArrowLeft03Icon
3720
+ SquareArrowLeftDoubleIcon
3721
+ SquareArrowLeftRightIcon
3722
+ SquareArrowMoveDownLeftIcon
3723
+ SquareArrowMoveDownRightIcon
3724
+ SquareArrowMoveLeftDownIcon
3725
+ SquareArrowMoveLeftUpIcon
3726
+ SquareArrowMoveRightDownIcon
3727
+ SquareArrowMoveRightUpIcon
3728
+ SquareArrowReload01Icon
3729
+ SquareArrowReload02Icon
3730
+ SquareArrowRight01Icon
3731
+ SquareArrowRight02Icon
3732
+ SquareArrowRight03Icon
3733
+ SquareArrowRightDoubleIcon
3734
+ SquareArrowShrink01Icon
3735
+ SquareArrowShrink02Icon
3736
+ SquareArrowUp01Icon
3737
+ SquareArrowUp02Icon
3738
+ SquareArrowUp03Icon
3739
+ SquareArrowUpDoubleIcon
3740
+ SquareArrowUpDownIcon
3741
+ SquareArrowUpLeftIcon
3742
+ SquareArrowUpRight02Icon
3743
+ SquareArrowUpRightIcon
3744
+ SquareArrowVerticalIcon
3745
+ SquareCircleIcon
3746
+ SquareLock01Icon
3747
+ SquareLock02Icon
3748
+ SquareLockAdd01Icon
3749
+ SquareLockAdd02Icon
3750
+ SquareLockCheck01Icon
3751
+ SquareLockCheck02Icon
3752
+ SquareLockMinus01Icon
3753
+ SquareLockMinus02Icon
3754
+ SquareLockPasswordIcon
3755
+ SquareLockRemove01Icon
3756
+ SquareLockRemove02Icon
3757
+ SquareRootSquareIcon
3758
+ SquareSquareIcon
3759
+ SquareIcon
3760
+ SquareUnlock01Icon
3761
+ SquareUnlock02Icon
3762
+ StackStarIcon
3763
+ Stairs01Icon
3764
+ Stairs02Icon
3765
+ Stairs03Icon
3766
+ Stairs04Icon
3767
+ StakeIcon
3768
+ Stamp01Icon
3769
+ Stamp02Icon
3770
+ StampIcon
3771
+ StarAward01Icon
3772
+ StarAward02Icon
3773
+ StarCircleIcon
3774
+ StarFaceIcon
3775
+ StarHalfIcon
3776
+ StarOffIcon
3777
+ StarSquareIcon
3778
+ StarIcon
3779
+ StarsIcon
3780
+ StartUp01Icon
3781
+ StartUp02Icon
3782
+ StationeryIcon
3783
+ StatusIcon
3784
+ SteakIcon
3785
+ SteeringIcon
3786
+ StepIntoIcon
3787
+ StepOutIcon
3788
+ StepOverIcon
3789
+ Stethoscope02Icon
3790
+ StethoscopeIcon
3791
+ StickyNote01Icon
3792
+ StickyNote02Icon
3793
+ StickyNote03Icon
3794
+ StopCircleIcon
3795
+ StopLossOrderIcon
3796
+ StopIcon
3797
+ StopWatchIcon
3798
+ Store01Icon
3799
+ Store02Icon
3800
+ Store03Icon
3801
+ Store04Icon
3802
+ StoreAdd01Icon
3803
+ StoreAdd02Icon
3804
+ StoreLocation01Icon
3805
+ StoreLocation02Icon
3806
+ StoreManagement01Icon
3807
+ StoreManagement02Icon
3808
+ StoreRemove01Icon
3809
+ StoreRemove02Icon
3810
+ StoreVerified01Icon
3811
+ StoreVerified02Icon
3812
+ StraightEdgeIcon
3813
+ StrategyIcon
3814
+ StreeringWheelIcon
3815
+ StreetFoodIcon
3816
+ StripeIcon
3817
+ StrokeBottomIcon
3818
+ StrokeCenterIcon
3819
+ StrokeInsideIcon
3820
+ StrokeLeftIcon
3821
+ StrokeOutsideIcon
3822
+ StrokeRightIcon
3823
+ StrokeTopIcon
3824
+ Structure01Icon
3825
+ Structure02Icon
3826
+ Structure03Icon
3827
+ Structure04Icon
3828
+ Structure05Icon
3829
+ StructureAddIcon
3830
+ StructureCheckIcon
3831
+ StructureFailIcon
3832
+ StructureFolderCircleIcon
3833
+ StructureFolderIcon
3834
+ StudentCardIcon
3835
+ StudentIcon
3836
+ StudentsIcon
3837
+ StudyDeskIcon
3838
+ StudyLampIcon
3839
+ StumbleuponIcon
3840
+ SubmarineIcon
3841
+ SubmergeIcon
3842
+ SubnodeAddIcon
3843
+ SubnodeDeleteIcon
3844
+ SubpoenaIcon
3845
+ SubtitleIcon
3846
+ Suit01Icon
3847
+ Suit02Icon
3848
+ SujoodIcon
3849
+ Summation01Icon
3850
+ Summation02Icon
3851
+ SummationCircleIcon
3852
+ SummationSquareIcon
3853
+ Sun01Icon
3854
+ Sun02Icon
3855
+ Sun03Icon
3856
+ SunCloud01Icon
3857
+ SunCloud02Icon
3858
+ SunCloudAngledRain01Icon
3859
+ SunCloudAngledRain02Icon
3860
+ SunCloudAngledRainZap01Icon
3861
+ SunCloudAngledRainZap02Icon
3862
+ SunCloudAngledZap01Icon
3863
+ SunCloudAngledZap02Icon
3864
+ SunCloudBigRain01Icon
3865
+ SunCloudBigRain02Icon
3866
+ SunCloudFastWind01Icon
3867
+ SunCloudFastWind02Icon
3868
+ SunCloudHailstone01Icon
3869
+ SunCloudHailstone02Icon
3870
+ SunCloudLittleRain01Icon
3871
+ SunCloudLittleRain02Icon
3872
+ SunCloudLittleSnow01Icon
3873
+ SunCloudLittleSnow02Icon
3874
+ SunCloudMidRain01Icon
3875
+ SunCloudMidRain02Icon
3876
+ SunCloudMidSnow01Icon
3877
+ SunCloudMidSnow02Icon
3878
+ SunCloudSlowWind01Icon
3879
+ SunCloudSlowWind02Icon
3880
+ SunCloudSnow01Icon
3881
+ SunCloudSnow02Icon
3882
+ SunglassesIcon
3883
+ SunriseIcon
3884
+ SunsetIcon
3885
+ SuperMarioIcon
3886
+ SuperMarioToadIcon
3887
+ SurfboardIcon
3888
+ SurpriseIcon
3889
+ Sushi01Icon
3890
+ Sushi02Icon
3891
+ Sushi03Icon
3892
+ SuspiciousIcon
3893
+ SustainableEnergyIcon
3894
+ Svg01Icon
3895
+ Svg02Icon
3896
+ SwarmIcon
3897
+ SwatchIcon
3898
+ SwimmingCapIcon
3899
+ SwimmingIcon
3900
+ SwipeDown01Icon
3901
+ SwipeDown02Icon
3902
+ SwipeDown03Icon
3903
+ SwipeDown04Icon
3904
+ SwipeDown05Icon
3905
+ SwipeDown06Icon
3906
+ SwipeDown07Icon
3907
+ SwipeDown08Icon
3908
+ SwipeLeft01Icon
3909
+ SwipeLeft02Icon
3910
+ SwipeLeft03Icon
3911
+ SwipeLeft04Icon
3912
+ SwipeLeft05Icon
3913
+ SwipeLeft06Icon
3914
+ SwipeLeft07Icon
3915
+ SwipeLeft08Icon
3916
+ SwipeLeft09Icon
3917
+ SwipeRight01Icon
3918
+ SwipeRight02Icon
3919
+ SwipeRight03Icon
3920
+ SwipeRight04Icon
3921
+ SwipeRight05Icon
3922
+ SwipeRight06Icon
3923
+ SwipeRight07Icon
3924
+ SwipeRight08Icon
3925
+ SwipeRight09Icon
3926
+ SwipeUp01Icon
3927
+ SwipeUp02Icon
3928
+ SwipeUp03Icon
3929
+ SwipeUp04Icon
3930
+ SwipeUp05Icon
3931
+ SwipeUp06Icon
3932
+ SwipeUp07Icon
3933
+ SwipeUp08Icon
3934
+ Sword01Icon
3935
+ Sword02Icon
3936
+ Sword03Icon
3937
+ SystemUpdate01Icon
3938
+ SystemUpdate02Icon
3939
+ TShirtIcon
3940
+ Table01Icon
3941
+ Table02Icon
3942
+ Table03Icon
3943
+ TableLamp01Icon
3944
+ TableLamp02Icon
3945
+ TableRoundIcon
3946
+ TableIcon
3947
+ TableTennisBatIcon
3948
+ Tablet01Icon
3949
+ Tablet02Icon
3950
+ TabletConnectedBluetoothIcon
3951
+ TabletConnectedUsbIcon
3952
+ TabletConnectedWifiIcon
3953
+ TabletPenIcon
3954
+ Taco01Icon
3955
+ Taco02Icon
3956
+ Tag01Icon
3957
+ Tag02Icon
3958
+ TagsIcon
3959
+ TailwindcssIcon
3960
+ TajMahalIcon
3961
+ TanIcon
3962
+ TankTopIcon
3963
+ TankerTruckIcon
3964
+ Tap01Icon
3965
+ Tap02Icon
3966
+ Tap03Icon
3967
+ Tap04Icon
3968
+ Tap05Icon
3969
+ Tap06Icon
3970
+ Tap07Icon
3971
+ Tap08Icon
3972
+ TapeMeasureIcon
3973
+ Target01Icon
3974
+ Target02Icon
3975
+ Target03Icon
3976
+ TargetDollarIcon
3977
+ TasbihIcon
3978
+ Task01Icon
3979
+ Task02Icon
3980
+ TaskAdd01Icon
3981
+ TaskAdd02Icon
3982
+ TaskDaily01Icon
3983
+ TaskDaily02Icon
3984
+ TaskDone01Icon
3985
+ TaskDone02Icon
3986
+ TaskEdit01Icon
3987
+ TaskEdit02Icon
3988
+ TaskRemove01Icon
3989
+ TaskRemove02Icon
3990
+ TaxesIcon
3991
+ Taxi02Icon
3992
+ TaxiIcon
3993
+ TeaPodIcon
3994
+ TeaIcon
3995
+ TeacherIcon
3996
+ TeachingIcon
3997
+ TeamviewerIcon
3998
+ TelegramIcon
3999
+ TelephoneIcon
4000
+ Telescope01Icon
4001
+ Telescope02Icon
4002
+ TelevisionTableIcon
4003
+ TemperatureIcon
4004
+ TennisBallIcon
4005
+ TennisRacketIcon
4006
+ TerraceIcon
4007
+ TestTube01Icon
4008
+ TestTube02Icon
4009
+ TestTube03Icon
4010
+ TestTubeIcon
4011
+ TetrisIcon
4012
+ TextAlignCenterIcon
4013
+ TextAlignJustifyCenterIcon
4014
+ TextAlignJustifyLeftIcon
4015
+ TextAlignJustifyRightIcon
4016
+ TextAlignLeft01Icon
4017
+ TextAlignLeftIcon
4018
+ TextAlignRight01Icon
4019
+ TextAlignRightIcon
4020
+ TextAllCapsIcon
4021
+ TextBoldIcon
4022
+ TextCenterlineCenterTopIcon
4023
+ TextCenterlineLeftIcon
4024
+ TextCenterlineMiddleIcon
4025
+ TextCenterlineRightIcon
4026
+ TextCheckIcon
4027
+ TextCircleIcon
4028
+ TextClearIcon
4029
+ TextColorIcon
4030
+ TextCreationIcon
4031
+ TextFirstlineLeftIcon
4032
+ TextFirstlineRightIcon
4033
+ TextFontIcon
4034
+ TextFootnoteIcon
4035
+ TextIndent01Icon
4036
+ TextIndentLessIcon
4037
+ TextIndentMoreIcon
4038
+ TextIndentIcon
4039
+ TextItalicSlashIcon
4040
+ TextItalicIcon
4041
+ TextKerningIcon
4042
+ TextNumberSignIcon
4043
+ TextSelectionIcon
4044
+ TextSmallcapsIcon
4045
+ TextSquareIcon
4046
+ TextStrikethroughIcon
4047
+ TextIcon
4048
+ TextSubscriptIcon
4049
+ TextSuperscriptIcon
4050
+ TextTrackingIcon
4051
+ TextUnderlineIcon
4052
+ TextVariableFrontIcon
4053
+ TextVerticalAlignmentIcon
4054
+ TextWrapIcon
4055
+ TheProphetsMosqueIcon
4056
+ ThermometerColdIcon
4057
+ ThermometerIcon
4058
+ ThermometerWarmIcon
4059
+ ThreadIcon
4060
+ ThreadsEllipseIcon
4061
+ ThreadsRectangleIcon
4062
+ ThreadsIcon
4063
+ ThreeCircleIcon
4064
+ ThreeFinger01Icon
4065
+ ThreeFinger02Icon
4066
+ ThreeFinger03Icon
4067
+ ThreeFinger04Icon
4068
+ ThreeFinger05Icon
4069
+ ThreeSquareIcon
4070
+ ThumbsDownEllipseIcon
4071
+ ThumbsDownRectangleIcon
4072
+ ThumbsDownIcon
4073
+ ThumbsUpDownIcon
4074
+ ThumbsUpEllipseIcon
4075
+ ThumbsUpRectangleIcon
4076
+ ThumbsUpIcon
4077
+ TicTacToeIcon
4078
+ Tick01Icon
4079
+ Tick02Icon
4080
+ Tick03Icon
4081
+ Tick04Icon
4082
+ TickDouble01Icon
4083
+ TickDouble02Icon
4084
+ TickDouble03Icon
4085
+ TickDouble04Icon
4086
+ Ticket01Icon
4087
+ Ticket02Icon
4088
+ Ticket03Icon
4089
+ TicketStarIcon
4090
+ TieIcon
4091
+ Tiff01Icon
4092
+ Tiff02Icon
4093
+ TiktokIcon
4094
+ TiltifyIcon
4095
+ Time01Icon
4096
+ Time02Icon
4097
+ Time03Icon
4098
+ Time04Icon
4099
+ TimeHalfPassIcon
4100
+ TimeManagementCircleIcon
4101
+ TimeManagementIcon
4102
+ TimeQuarter02Icon
4103
+ TimeQuarterPassIcon
4104
+ TimeQuarterIcon
4105
+ TimeScheduleIcon
4106
+ TimeSetting01Icon
4107
+ TimeSetting02Icon
4108
+ TimeSetting03Icon
4109
+ Timer01Icon
4110
+ Timer02Icon
4111
+ TipsIcon
4112
+ TireIcon
4113
+ Tired01Icon
4114
+ Tired02Icon
4115
+ TissuePaperIcon
4116
+ ToggleOffIcon
4117
+ ToggleOnIcon
4118
+ Toilet01Icon
4119
+ Toilet02Icon
4120
+ TokenCircleIcon
4121
+ TokenSquareIcon
4122
+ Tongue01Icon
4123
+ TongueIcon
4124
+ TongueWinkLeftIcon
4125
+ TongueWinkRightIcon
4126
+ ToolsIcon
4127
+ Tornado01Icon
4128
+ Tornado02Icon
4129
+ TorriGateIcon
4130
+ Touch01Icon
4131
+ Touch02Icon
4132
+ Touch03Icon
4133
+ Touch04Icon
4134
+ Touch05Icon
4135
+ Touch06Icon
4136
+ Touch07Icon
4137
+ Touch08Icon
4138
+ Touch09Icon
4139
+ Touch10Icon
4140
+ TouchInteraction01Icon
4141
+ TouchInteraction02Icon
4142
+ TouchInteraction03Icon
4143
+ TouchInteraction04Icon
4144
+ TouchLocked01Icon
4145
+ TouchLocked02Icon
4146
+ TouchLocked03Icon
4147
+ TouchLocked04Icon
4148
+ Touchpad01Icon
4149
+ Touchpad02Icon
4150
+ Touchpad03Icon
4151
+ Touchpad04Icon
4152
+ TowTruckIcon
4153
+ TowelsIcon
4154
+ ToyTrainIcon
4155
+ TractorIcon
4156
+ TradeDownIcon
4157
+ TradeMarkIcon
4158
+ TradeUpIcon
4159
+ TrafficIncidentIcon
4160
+ TrafficJam01Icon
4161
+ TrafficJam02Icon
4162
+ TrafficLightIcon
4163
+ Train01Icon
4164
+ Train02Icon
4165
+ TramIcon
4166
+ TrampolineIcon
4167
+ TransactionHistoryIcon
4168
+ TransactionIcon
4169
+ TransitionBottomIcon
4170
+ TransitionLeftIcon
4171
+ TransitionRightIcon
4172
+ TransitionTopIcon
4173
+ TranslateIcon
4174
+ TranslationIcon
4175
+ TransmissionIcon
4176
+ TransparencyIcon
4177
+ TrapezoidLineHorizontalIcon
4178
+ TrapezoidLineVerticalIcon
4179
+ TravelBagIcon
4180
+ Treadmill01Icon
4181
+ Treadmill02Icon
4182
+ TreatmentIcon
4183
+ Tree01Icon
4184
+ Tree02Icon
4185
+ Tree03Icon
4186
+ Tree04Icon
4187
+ Tree05Icon
4188
+ Tree06Icon
4189
+ Tree07Icon
4190
+ TrelloIcon
4191
+ Triangle01Icon
4192
+ Triangle02Icon
4193
+ Triangle03Icon
4194
+ TriangleIcon
4195
+ Trolley01Icon
4196
+ Trolley02Icon
4197
+ TropicalStormIcon
4198
+ TropicalStormTracks01Icon
4199
+ TropicalStormTracks02Icon
4200
+ TruckDeliveryIcon
4201
+ TruckMonsterIcon
4202
+ TruckReturnIcon
4203
+ TruckIcon
4204
+ TrulliIcon
4205
+ TsunamiIcon
4206
+ TulipIcon
4207
+ TumblrIcon
4208
+ TurtleNeckIcon
4209
+ Tv01Icon
4210
+ Tv02Icon
4211
+ TvFixIcon
4212
+ TvIssueIcon
4213
+ TvSmartIcon
4214
+ TwinTowerIcon
4215
+ TwitchIcon
4216
+ TwitterSquareIcon
4217
+ TwitterIcon
4218
+ TwoCircleIcon
4219
+ TwoFactorAccessIcon
4220
+ TwoFinger01Icon
4221
+ TwoFinger02Icon
4222
+ TwoFinger03Icon
4223
+ TwoFinger04Icon
4224
+ TwoFinger05Icon
4225
+ TwoSquareIcon
4226
+ Txt01Icon
4227
+ Txt02Icon
4228
+ TypeCursorIcon
4229
+ Typescript01Icon
4230
+ Typescript02Icon
4231
+ Typescript03Icon
4232
+ UberIcon
4233
+ Ufo01Icon
4234
+ UfoIcon
4235
+ UmbrellaDollarIcon
4236
+ UmbrellaIcon
4237
+ UnamusedIcon
4238
+ Unarchive03Icon
4239
+ UnavailableIcon
4240
+ Underpants01Icon
4241
+ Underpants02Icon
4242
+ Underpants03Icon
4243
+ Undo02Icon
4244
+ Undo03Icon
4245
+ UndoIcon
4246
+ UnfoldLessIcon
4247
+ UnfoldMoreIcon
4248
+ UngroupItemsIcon
4249
+ UngroupLayersIcon
4250
+ UnhappyIcon
4251
+ UniversalAccessCircleIcon
4252
+ UniversalAccessIcon
4253
+ UniversityIcon
4254
+ Unlink01Icon
4255
+ Unlink02Icon
4256
+ Unlink03Icon
4257
+ Unlink04Icon
4258
+ Unlink05Icon
4259
+ Unlink06Icon
4260
+ UnsplashIcon
4261
+ Upload01Icon
4262
+ Upload02Icon
4263
+ Upload03Icon
4264
+ Upload04Icon
4265
+ Upload05Icon
4266
+ UploadCircle01Icon
4267
+ UploadCircle02Icon
4268
+ UploadSquare01Icon
4269
+ UploadSquare02Icon
4270
+ UpworkIcon
4271
+ UsbBugsIcon
4272
+ UsbConnected01Icon
4273
+ UsbConnected02Icon
4274
+ UsbConnected03Icon
4275
+ UsbErrorIcon
4276
+ UsbMemory01Icon
4277
+ UsbMemory02Icon
4278
+ UsbNotConnected01Icon
4279
+ UsbNotConnected02Icon
4280
+ UsbIcon
4281
+ UsdtIcon
4282
+ User02Icon
4283
+ User03Icon
4284
+ UserAccountIcon
4285
+ UserAdd01Icon
4286
+ UserAdd02Icon
4287
+ UserAiIcon
4288
+ UserArrowLeftRightIcon
4289
+ UserBlock01Icon
4290
+ UserBlock02Icon
4291
+ UserCheck01Icon
4292
+ UserCheck02Icon
4293
+ UserCircle02Icon
4294
+ UserCircleIcon
4295
+ UserEdit01Icon
4296
+ UserFullViewIcon
4297
+ UserGroup02Icon
4298
+ UserGroup03Icon
4299
+ UserGroupIcon
4300
+ UserIdVerificationIcon
4301
+ UserListIcon
4302
+ UserLock01Icon
4303
+ UserLock02Icon
4304
+ UserLove01Icon
4305
+ UserLove02Icon
4306
+ UserMinus01Icon
4307
+ UserMinus02Icon
4308
+ UserMultiple02Icon
4309
+ UserMultiple03Icon
4310
+ UserMultipleIcon
4311
+ UserQuestion01Icon
4312
+ UserQuestion02Icon
4313
+ UserRemove01Icon
4314
+ UserRemove02Icon
4315
+ UserRoadsideIcon
4316
+ UserSearch01Icon
4317
+ UserSearch02Icon
4318
+ UserSettings01Icon
4319
+ UserSettings02Icon
4320
+ UserSharingIcon
4321
+ UserShield01Icon
4322
+ UserShield02Icon
4323
+ UserSquareIcon
4324
+ UserStar01Icon
4325
+ UserStar02Icon
4326
+ UserStatusIcon
4327
+ UserStoryIcon
4328
+ UserIcon
4329
+ UserSwitchIcon
4330
+ UserTime01Icon
4331
+ UserTime02Icon
4332
+ UserTime03Icon
4333
+ UserUnlock01Icon
4334
+ UserUnlock02Icon
4335
+ UserWarning01Icon
4336
+ UserWarning02Icon
4337
+ UserWarning03Icon
4338
+ Uv01Icon
4339
+ Uv02Icon
4340
+ Uv03Icon
4341
+ VaccineIcon
4342
+ VacuumCleanerIcon
4343
+ ValidationApprovalIcon
4344
+ ValidationIcon
4345
+ VanIcon
4346
+ VariableIcon
4347
+ VegetarianFoodIcon
4348
+ VersusIcon
4349
+ VerticalResizeIcon
4350
+ VerticalScrollPointIcon
4351
+ VestIcon
4352
+ ViberIcon
4353
+ VictoryFinger01Icon
4354
+ VictoryFinger02Icon
4355
+ VictoryFinger03Icon
4356
+ Video01Icon
4357
+ Video02Icon
4358
+ VideoAiIcon
4359
+ VideoCameraAiIcon
4360
+ VideoConsoleIcon
4361
+ VideoOffIcon
4362
+ VideoReplayIcon
4363
+ ViewOffSlashIcon
4364
+ ViewOffIcon
4365
+ ViewIcon
4366
+ VimeoIcon
4367
+ VineSquareIcon
4368
+ VineIcon
4369
+ VintageClockIcon
4370
+ VirtualRealityVr01Icon
4371
+ VirtualRealityVr02Icon
4372
+ VisionIcon
4373
+ VisualStudioCodeIcon
4374
+ VkSquareIcon
4375
+ VkIcon
4376
+ VoiceIdIcon
4377
+ VoiceIcon
4378
+ VolleyballIcon
4379
+ VolumeHighIcon
4380
+ VolumeLowIcon
4381
+ VolumeMinusIcon
4382
+ VolumeMute01Icon
4383
+ VolumeMute02Icon
4384
+ VolumeOffIcon
4385
+ VolumeUpIcon
4386
+ VomitingIcon
4387
+ VoucherIcon
4388
+ VrGlassesIcon
4389
+ VrIcon
4390
+ Vynil01Icon
4391
+ Vynil02Icon
4392
+ Vynil03Icon
4393
+ W3SchoolsIcon
4394
+ WaiterIcon
4395
+ WaitersIcon
4396
+ WallLampIcon
4397
+ Wallet01Icon
4398
+ Wallet02Icon
4399
+ Wallet03Icon
4400
+ Wallet04Icon
4401
+ Wallet05Icon
4402
+ WalletAdd01Icon
4403
+ WalletAdd02Icon
4404
+ WalletDone01Icon
4405
+ WalletDone02Icon
4406
+ WalletNotFound01Icon
4407
+ WalletNotFound02Icon
4408
+ WalletRemove01Icon
4409
+ WalletRemove02Icon
4410
+ WantedIcon
4411
+ Wardrobe01Icon
4412
+ Wardrobe02Icon
4413
+ Wardrobe03Icon
4414
+ Wardrobe04Icon
4415
+ WarehouseIcon
4416
+ WashingtonMonumentIcon
4417
+ WasteRestoreIcon
4418
+ WasteIcon
4419
+ Watch01Icon
4420
+ Watch02Icon
4421
+ WaterEnergyIcon
4422
+ WaterPoloIcon
4423
+ WaterPumpIcon
4424
+ WaterfallDown01Icon
4425
+ WaterfallDown03Icon
4426
+ WaterfallUp01Icon
4427
+ WaterfallUp02Icon
4428
+ WatermelonIcon
4429
+ WattpadSquareIcon
4430
+ WattpadIcon
4431
+ Wav01Icon
4432
+ Wav02Icon
4433
+ WaveSquareIcon
4434
+ WaveIcon
4435
+ WaveTriangleIcon
4436
+ WavingHand01Icon
4437
+ WavingHand02Icon
4438
+ WazeIcon
4439
+ WebDesign01Icon
4440
+ WebDesign02Icon
4441
+ WebProgrammingIcon
4442
+ WebProtectionIcon
4443
+ WebSecurityIcon
4444
+ WebValidationIcon
4445
+ WebflowEllipseIcon
4446
+ WebflowRectangleIcon
4447
+ WebflowIcon
4448
+ WebhookIcon
4449
+ WechatIcon
4450
+ WeddingIcon
4451
+ WeightScale01Icon
4452
+ WeightScaleIcon
4453
+ WellnessIcon
4454
+ WhatsappBusinessIcon
4455
+ WhatsappIcon
4456
+ WheelchairIcon
4457
+ WhiskIcon
4458
+ WhistleIcon
4459
+ WhiteboardIcon
4460
+ Wifi01Icon
4461
+ Wifi02Icon
4462
+ WifiCircleIcon
4463
+ WifiConnected01Icon
4464
+ WifiConnected02Icon
4465
+ WifiConnected03Icon
4466
+ WifiDisconnected01Icon
4467
+ WifiDisconnected02Icon
4468
+ WifiDisconnected03Icon
4469
+ WifiDisconnected04Icon
4470
+ WifiError01Icon
4471
+ WifiError02Icon
4472
+ WifiFullSignalIcon
4473
+ WifiLocationIcon
4474
+ WifiLockIcon
4475
+ WifiLowSignalIcon
4476
+ WifiMediumSignalIcon
4477
+ WifiNoSignalIcon
4478
+ WifiOff01Icon
4479
+ WifiOff02Icon
4480
+ WifiSquareIcon
4481
+ WifiUnlockIcon
4482
+ WikipediaIcon
4483
+ WindPower01Icon
4484
+ WindPower02Icon
4485
+ WindPower03Icon
4486
+ WindPowerIcon
4487
+ WindSurfIcon
4488
+ WindTurbineIcon
4489
+ WindowsNewIcon
4490
+ WindowsOldIcon
4491
+ WinkIcon
4492
+ WinkingIcon
4493
+ WirelessCloudAccessIcon
4494
+ WirelessIcon
4495
+ WiseIcon
4496
+ WomanIcon
4497
+ WordpressIcon
4498
+ WorkAlertIcon
4499
+ WorkHistoryIcon
4500
+ WorkIcon
4501
+ WorkUpdateIcon
4502
+ WorkflowCircle01Icon
4503
+ WorkflowCircle02Icon
4504
+ WorkflowCircle03Icon
4505
+ WorkflowCircle04Icon
4506
+ WorkflowCircle05Icon
4507
+ WorkflowCircle06Icon
4508
+ WorkflowSquare01Icon
4509
+ WorkflowSquare02Icon
4510
+ WorkflowSquare03Icon
4511
+ WorkflowSquare04Icon
4512
+ WorkflowSquare05Icon
4513
+ WorkflowSquare06Icon
4514
+ WorkflowSquare07Icon
4515
+ WorkflowSquare08Icon
4516
+ WorkflowSquare09Icon
4517
+ WorkflowSquare10Icon
4518
+ WorkoutBattleRopesIcon
4519
+ WorkoutGymnasticsIcon
4520
+ WorkoutKickingIcon
4521
+ WorkoutRunIcon
4522
+ WorkoutSportIcon
4523
+ WorkoutSquatsIcon
4524
+ WorkoutStretchingIcon
4525
+ WorkoutWarmUpIcon
4526
+ WorryIcon
4527
+ WpsOfficeRectangleIcon
4528
+ WpsOfficeIcon
4529
+ Wrench01Icon
4530
+ Wrench02Icon
4531
+ WuduIcon
4532
+ XRayIcon
4533
+ XVariableCircleIcon
4534
+ XVariableSquareIcon
4535
+ XVariableIcon
4536
+ XingIcon
4537
+ Xls01Icon
4538
+ Xls02Icon
4539
+ Xml01Icon
4540
+ Xml02Icon
4541
+ Xsl01Icon
4542
+ Xsl02Icon
4543
+ YelpIcon
4544
+ YenCircleIcon
4545
+ YenReceiveIcon
4546
+ YenSendIcon
4547
+ YenSquareIcon
4548
+ YenIcon
4549
+ Yoga01Icon
4550
+ Yoga02Icon
4551
+ Yoga03Icon
4552
+ YogaBallIcon
4553
+ YogaMatIcon
4554
+ YogurtIcon
4555
+ YoutubeIcon
4556
+ YurtIcon
4557
+ ZakatIcon
4558
+ ZapIcon
4559
+ ZeppelinIcon
4560
+ ZeroCircleIcon
4561
+ ZeroSquareIcon
4562
+ Zip01Icon
4563
+ Zip02Icon
4564
+ ZoomCircleIcon
4565
+ ZoomInAreaIcon
4566
+ ZoomOutAreaIcon
4567
+ ZoomSquareIcon
4568
+ ZoomIcon
4569
+ ZshIcon
4570
+ ZzzIcon
4571
+
4572
+ }
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "hybrid-editor",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc && vite build",
9
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "@dnd-kit/core": "^6.1.0",
14
+ "@dnd-kit/sortable": "^8.0.0",
15
+ "@dnd-kit/utilities": "^3.2.2",
16
+ "@lexical/react": "^0.13.1",
17
+ "hugeicons-react": "latest",
18
+ "idb": "^8.0.0",
19
+ "lexical": "^0.13.1",
20
+ "react": "^18.2.0",
21
+ "react-dom": "^18.2.0",
22
+ "react-image-crop": "^11.0.5",
23
+ "uuid": "^9.0.1",
24
+ "zustand": "^4.5.2"
25
+ },
26
+ "devDependencies": {
27
+ "@types/react": "^18.2.66",
28
+ "@types/react-dom": "^18.2.22",
29
+ "@types/uuid": "^9.0.8",
30
+ "@vitejs/plugin-react": "^4.2.1",
31
+ "typescript": "^5.2.2",
32
+ "vite": "^5.2.0",
33
+ "vite-plugin-pwa": "^1.2.0",
34
+ "workbox-core": "^7.4.0",
35
+ "workbox-routing": "^7.4.0",
36
+ "workbox-strategies": "^7.4.0",
37
+ "workbox-window": "^7.4.0"
38
+ }
39
+ }
src/App.tsx ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useEffect, useState } from 'react';
2
+ import { getSettings, SettingsType, DEFAULT_SETTINGS, getBackgroundImage } from './lib/db';
3
+ import { useFileStore } from './stores/fileStore';
4
+ import TreeView from './components/Sidebar/TreeView';
5
+ import EditorCore from './components/Editor/EditorCore';
6
+ import SettingsModal from './components/Settings/SettingsModal';
7
+ import {
8
+ Settings01Icon, Download01Icon, BorderAll01Icon
9
+ } from 'hugeicons-react';
10
+
11
+ function App() {
12
+ const [settings, setSettings] = useState<SettingsType>(DEFAULT_SETTINGS);
13
+ const [bgImage, setBgImage] = useState<string | null>(null);
14
+ const [showSettings, setShowSettings] = useState(false);
15
+ const [showSidebar, setShowSidebar] = useState(true);
16
+
17
+ const { loadFiles } = useFileStore();
18
+
19
+ useEffect(() => {
20
+ // Initial data load
21
+ loadFiles();
22
+
23
+ // Load config from DB
24
+ getSettings().then(setSettings);
25
+ // Load background image
26
+ getBackgroundImage().then(blob => {
27
+ if (blob) {
28
+ if (blob instanceof Blob) {
29
+ setBgImage(URL.createObjectURL(blob));
30
+ } else {
31
+ setBgImage(blob);
32
+ }
33
+ }
34
+ });
35
+
36
+ // Entry/Exit Listener
37
+ const handleKeyDown = (e: KeyboardEvent) => {
38
+ if (e.key === 'Escape') {
39
+ setShowSettings(false);
40
+ }
41
+ };
42
+ window.addEventListener('keydown', handleKeyDown);
43
+ return () => window.removeEventListener('keydown', handleKeyDown);
44
+ }, []);
45
+
46
+ return (
47
+ <div
48
+ className={`app-container font-${settings.typography.replace(/\s+/g, '-').toLowerCase()}`}
49
+ style={{ '--bg-opacity': settings.bgOpacity, '--fg-opacity': settings.fgOpacity } as any}
50
+ >
51
+ {bgImage && (
52
+ <div
53
+ className="app-background"
54
+ style={{ backgroundImage: `url(${bgImage})` }}
55
+ />
56
+ )}
57
+
58
+ {showSettings && <SettingsModal onClose={() => setShowSettings(false)} />}
59
+
60
+ <aside className="mini-sidebar">
61
+ <button
62
+ className={`btn-icon ${showSidebar ? 'active' : ''}`}
63
+ onClick={() => setShowSidebar(!showSidebar)}
64
+ title="Toggle Sidebar"
65
+ style={{ padding: 8, background: showSidebar ? 'rgba(0,0,0,0.03)' : 'transparent' }}
66
+ >
67
+ <BorderAll01Icon size={20} color={showSidebar ? 'var(--text-primary)' : 'var(--text-secondary)'} />
68
+ </button>
69
+
70
+ <div style={{ flex: 1 }} />
71
+ <button className="btn-icon" onClick={() => setShowSettings(true)} title="Settings" style={{ padding: 8 }}>
72
+ <Settings01Icon size={20} color="var(--text-secondary)" />
73
+ </button>
74
+ <button
75
+ className="btn-icon"
76
+ onClick={async () => {
77
+ const { exportFullWorkspace } = await import('./lib/db');
78
+ const data = await exportFullWorkspace();
79
+ const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
80
+ const url = URL.createObjectURL(blob);
81
+ const a = document.createElement('a');
82
+ a.href = url;
83
+ a.download = `hybrid-workspace-${new Date().toISOString().split('T')[0]}.json`;
84
+ a.click();
85
+ }}
86
+ title="Download Workspace"
87
+ style={{ padding: 8 }}
88
+ >
89
+ <Download01Icon size={20} color="var(--text-secondary)" />
90
+ </button>
91
+ </aside>
92
+
93
+ {showSidebar && (
94
+ <aside className="sidebar-panel">
95
+ <div className="sidebar-header" style={{ padding: '4px 16px', display: 'flex', alignItems: 'center', height: '48px', borderBottom: '1px solid var(--border-color)' }}>
96
+ <span style={{ letterSpacing: '0.05em', textTransform: 'uppercase', fontSize: '10px', fontWeight: 700, opacity: 0.4 }}>WORKSPACE</span>
97
+ </div>
98
+ <TreeView />
99
+ </aside>
100
+ )}
101
+
102
+ <main className="editor-main">
103
+ <EditorCore />
104
+ </main>
105
+ </div>
106
+ );
107
+ }
108
+
109
+ export default App;
src/components/Editor/EditorCore.tsx ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useEffect, useState, useCallback, useRef } from 'react';
2
+ import { useFileStore } from '../../stores/fileStore';
3
+ import { LexicalComposer } from '@lexical/react/LexicalComposer';
4
+ import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
5
+ import { ContentEditable } from '@lexical/react/LexicalContentEditable';
6
+ import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
7
+ import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
8
+ import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary';
9
+
10
+ import LineNumbers from './LineNumberPlugin';
11
+ import HoverToolbar from './HoverToolbar';
12
+ import AutoHighlighterPlugin from '../../plugins/AutoHighlighterPlugin';
13
+ import { CloudSavingDone01Icon, Tick02Icon } from 'hugeicons-react';
14
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
15
+ import { INSERT_LINE_BREAK_COMMAND, COMMAND_PRIORITY_EDITOR, $createLineBreakNode, $getSelection, $isRangeSelection } from 'lexical';
16
+
17
+ // Premium Theme mapping for Lexical
18
+ const theme = {
19
+ paragraph: 'editor-paragraph',
20
+ text: {
21
+ bold: 'editor-text-bold',
22
+ italic: 'editor-text-italic',
23
+ strikethrough: 'editor-text-strikethrough',
24
+ underline: 'editor-text-underline',
25
+ },
26
+ };
27
+
28
+ export default function EditorCore() {
29
+ const { files, activeFileId, updateFileContent } = useFileStore();
30
+ const [editorKey, setEditorKey] = useState(0);
31
+ const [isSaving, setIsSaving] = useState(false);
32
+ const debounceRef = useRef<any>(null);
33
+
34
+ const ShiftEnterPlugin = () => {
35
+ const [editor] = useLexicalComposerContext();
36
+ useEffect(() => {
37
+ return editor.registerCommand(
38
+ INSERT_LINE_BREAK_COMMAND,
39
+ () => {
40
+ editor.update(() => {
41
+ const selection = $getSelection();
42
+ if ($isRangeSelection(selection)) {
43
+ selection.insertNodes([$createLineBreakNode()]);
44
+ }
45
+ });
46
+ return true;
47
+ },
48
+ COMMAND_PRIORITY_EDITOR
49
+ );
50
+ }, [editor]);
51
+ return null;
52
+ };
53
+
54
+ const activeFile = files.find(f => f.id === activeFileId && f.type === 'file');
55
+
56
+ // Ensure editor re-initializes exactly on file change
57
+ useEffect(() => {
58
+ setEditorKey(k => k + 1);
59
+ }, [activeFileId]);
60
+
61
+ // Clipboard Transformation (Emdash Prefix)
62
+ useEffect(() => {
63
+ const handleCopy = (e: ClipboardEvent) => {
64
+ const selection = window.getSelection();
65
+ if (!selection || selection.rangeCount === 0) return;
66
+
67
+ let text = selection.toString();
68
+ if (!text) return;
69
+
70
+ // SPEC: Emdash as very beginning of number line with content
71
+ // Logic: Prefix lines with content with "— " (emdash + space)
72
+ const lines = text.split('\n');
73
+ const transformed = lines.map(line => {
74
+ if (line.trim().length > 0) {
75
+ return `— ${line}`;
76
+ }
77
+ return line;
78
+ }).join('\n');
79
+
80
+ e.clipboardData?.setData('text/plain', transformed);
81
+ e.preventDefault();
82
+ };
83
+
84
+ document.addEventListener('copy', handleCopy);
85
+ return () => document.removeEventListener('copy', handleCopy);
86
+ }, []);
87
+
88
+ const handleOnChange = useCallback((editorState: any) => {
89
+ setIsSaving(true);
90
+ if (debounceRef.current) clearTimeout(debounceRef.current);
91
+
92
+ debounceRef.current = setTimeout(() => {
93
+ editorState.read(() => {
94
+ const jsonString = JSON.stringify(editorState.toJSON());
95
+ if (activeFileId) {
96
+ updateFileContent(activeFileId, jsonString).then(() => {
97
+ setIsSaving(false);
98
+ });
99
+ } else {
100
+ setIsSaving(false);
101
+ }
102
+ });
103
+ }, 300); // 300ms debounce for near-instant premium persistence
104
+ }, [activeFileId, updateFileContent]);
105
+
106
+ if (!activeFile) {
107
+ return (
108
+ <div className="editor-placeholder" style={{
109
+ display: 'flex', flexDirection: 'column', gap: '8px', opacity: 0.4,
110
+ fontFamily: 'var(--font-ibm-plex)'
111
+ }}>
112
+ <div style={{ fontSize: '14px', fontWeight: 500 }}>No active document</div>
113
+ <div style={{ fontSize: '11px' }}>Select a file from the sidebar to begin editing.</div>
114
+ </div>
115
+ );
116
+ }
117
+
118
+ const initialConfig = {
119
+ namespace: 'HybridDocEditor',
120
+ theme,
121
+ nodes: [],
122
+ onError(error: Error) {
123
+ console.error('Lexical Error:', error);
124
+ },
125
+ editorState: activeFile.content ? (
126
+ activeFile.content.includes('"root":{') ? activeFile.content : undefined
127
+ ) : undefined,
128
+ };
129
+
130
+ return (
131
+ <div key={`editor-${editorKey}`} className="editor-shell" style={{ display: 'flex', flexDirection: 'column', height: '100%', flex: 1 }}>
132
+ <LexicalComposer initialConfig={initialConfig}>
133
+ <div className="editor-scroller" style={{ flex: 1, overflowY: 'auto', display: 'flex', position: 'relative' }}>
134
+ <LineNumbers />
135
+ <div className="editor-input-container" style={{ flex: 1, padding: '24px 32px', position: 'relative' }}>
136
+ <RichTextPlugin
137
+ contentEditable={
138
+ <ContentEditable
139
+ className="ContentEditable"
140
+ spellCheck={true}
141
+ data-gramm="true"
142
+ data-gramm_editor="true"
143
+ data-enable-grammarly="true"
144
+ style={{
145
+ minHeight: '100%',
146
+ outline: 'none',
147
+ lineHeight: '1.5',
148
+ fontSize: '15px'
149
+ }}
150
+ />
151
+ }
152
+ placeholder={
153
+ <div className="editor-placeholder" style={{
154
+ position: 'absolute', top: 24, left: 32, pointerEvents: 'none', opacity: 0.3, fontSize: '15px'
155
+ }}>
156
+ Start your thinking here...
157
+ </div>
158
+ }
159
+ ErrorBoundary={LexicalErrorBoundary}
160
+ />
161
+ <HistoryPlugin />
162
+ <OnChangePlugin onChange={handleOnChange} ignoreSelectionChange />
163
+ <ShiftEnterPlugin />
164
+ <HoverToolbar />
165
+ <AutoHighlighterPlugin />
166
+
167
+ {/* Save Status Indicator */}
168
+ <div style={{
169
+ position: 'fixed',
170
+ bottom: '24px',
171
+ right: '24px',
172
+ display: 'flex',
173
+ alignItems: 'center',
174
+ gap: '8px',
175
+ padding: '6px 12px',
176
+ background: 'var(--bg-panel)',
177
+ border: '1px solid var(--border-color)',
178
+ borderRadius: '20px',
179
+ fontSize: '11px',
180
+ fontWeight: 600,
181
+ color: 'var(--text-secondary)',
182
+ opacity: isSaving ? 1 : 0.4,
183
+ transition: 'opacity 0.3s ease',
184
+ pointerEvents: 'none',
185
+ boxShadow: '0 4px 12px rgba(0,0,0,0.05)',
186
+ zIndex: 10
187
+ }}>
188
+ {isSaving ? <CloudSavingDone01Icon size={14} className="spin" /> : <Tick02Icon size={14} />}
189
+ {isSaving ? 'Syncing...' : 'Saved'}
190
+ </div>
191
+ </div>
192
+ </div>
193
+ </LexicalComposer>
194
+ </div>
195
+ );
196
+ }
src/components/Editor/HoverToolbar.tsx ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import {
4
+ FORMAT_TEXT_COMMAND,
5
+ $getSelection,
6
+ $isRangeSelection,
7
+ TextFormatType
8
+ } from 'lexical';
9
+ import {
10
+ TextBoldIcon,
11
+ TextItalicIcon,
12
+ TextStrikethroughIcon,
13
+ MagicWand01Icon,
14
+ PaintBucketIcon
15
+ } from 'hugeicons-react';
16
+ import { $patchStyleText, $getSelectionStyleValueForProperty } from '@lexical/selection';
17
+
18
+ export default function HoverToolbar() {
19
+ const [editor] = useLexicalComposerContext();
20
+ const [isBold, setIsBold] = useState(false);
21
+ const [isItalic, setIsItalic] = useState(false);
22
+ const [isStrikethrough, setIsStrikethrough] = useState(false);
23
+ const [position, setPosition] = useState({ top: -10000, left: -10000, visible: false });
24
+ const [showColorPicker, setShowColorPicker] = useState(false);
25
+
26
+ const colors = [
27
+ '#000000', '#FF0000', '#00FF00', '#0000FF',
28
+ '#FFA500', '#800080', '#008080', '#FF69B4'
29
+ ];
30
+
31
+ const updateToolbar = useCallback(() => {
32
+ editor.getEditorState().read(() => {
33
+ const selection = $getSelection();
34
+
35
+ if ($isRangeSelection(selection) && !selection.isCollapsed()) {
36
+ const nativeSelection = window.getSelection();
37
+ if (nativeSelection && nativeSelection.rangeCount > 0) {
38
+ const domRange = nativeSelection.getRangeAt(0);
39
+ const rect = domRange.getBoundingClientRect();
40
+
41
+ setPosition({
42
+ top: rect.top - 40,
43
+ left: rect.left + (rect.width / 2) - 80,
44
+ visible: true
45
+ });
46
+
47
+ setIsBold(selection.hasFormat('bold'));
48
+ setIsItalic(selection.hasFormat('italic'));
49
+ setIsStrikethrough(selection.hasFormat('strikethrough'));
50
+ }
51
+ } else {
52
+ setPosition(p => ({ ...p, visible: false }));
53
+ }
54
+ });
55
+ }, [editor]);
56
+
57
+ useEffect(() => {
58
+ const unregister = editor.registerUpdateListener(() => {
59
+ updateToolbar();
60
+ });
61
+ document.addEventListener('selectionchange', updateToolbar);
62
+ return () => {
63
+ unregister();
64
+ document.removeEventListener('selectionchange', updateToolbar);
65
+ };
66
+ }, [editor, updateToolbar]);
67
+
68
+ const applyFormat = (format: TextFormatType) => {
69
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, format);
70
+ };
71
+
72
+ const applyPixelize = () => {
73
+ editor.update(() => {
74
+ const selection = $getSelection();
75
+ if ($isRangeSelection(selection)) {
76
+ const currentFilter = $getSelectionStyleValueForProperty(selection, 'filter');
77
+ if (currentFilter === 'blur(3px)') {
78
+ $patchStyleText(selection, { 'filter': '' });
79
+ } else {
80
+ $patchStyleText(selection, { 'filter': 'blur(3px)' });
81
+ }
82
+ }
83
+ });
84
+ };
85
+
86
+ const applyColor = (color: string) => {
87
+ editor.update(() => {
88
+ const selection = $getSelection();
89
+ if ($isRangeSelection(selection)) {
90
+ $patchStyleText(selection, { 'color': color });
91
+ }
92
+ });
93
+ setShowColorPicker(false);
94
+ };
95
+
96
+ if (!position.visible) return null;
97
+
98
+ return (
99
+ <div
100
+ style={{
101
+ position: 'fixed',
102
+ top: position.top,
103
+ left: position.left,
104
+ backgroundColor: 'var(--bg-panel)',
105
+ border: '1px solid var(--border-color)',
106
+ borderRadius: '6px',
107
+ padding: '4px',
108
+ display: 'flex',
109
+ gap: '4px',
110
+ boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
111
+ zIndex: 1000,
112
+ alignItems: 'center'
113
+ }}
114
+ >
115
+ <button
116
+ style={{ padding: 4, background: isBold ? '#eee' : 'transparent', borderRadius: 4 }}
117
+ onClick={() => applyFormat('bold')}
118
+ >
119
+ <TextBoldIcon size={16} />
120
+ </button>
121
+ <button
122
+ style={{ padding: 4, background: isItalic ? '#eee' : 'transparent', borderRadius: 4 }}
123
+ onClick={() => applyFormat('italic')}
124
+ >
125
+ <TextItalicIcon size={16} />
126
+ </button>
127
+ <button
128
+ style={{ padding: 4, background: isStrikethrough ? '#eee' : 'transparent', borderRadius: 4 }}
129
+ onClick={() => applyFormat('strikethrough')}
130
+ >
131
+ <TextStrikethroughIcon size={16} />
132
+ </button>
133
+
134
+ <div style={{ width: 1, height: 16, backgroundColor: '#ddd', margin: '0 4px' }} />
135
+
136
+ <button
137
+ style={{ padding: 4, background: 'transparent', borderRadius: 4, display: 'flex', alignItems: 'center' }}
138
+ onClick={applyPixelize}
139
+ title="Pixelize / Blur"
140
+ >
141
+ <MagicWand01Icon size={16} />
142
+ </button>
143
+
144
+ <div style={{ position: 'relative', display: 'flex', alignItems: 'center' }}>
145
+ <button
146
+ onClick={() => setShowColorPicker(!showColorPicker)}
147
+ style={{ padding: 4, background: 'transparent', borderRadius: 4, display: 'flex', alignItems: 'center' }}
148
+ title="Text Color"
149
+ >
150
+ <PaintBucketIcon size={16} />
151
+ </button>
152
+
153
+ {showColorPicker && (
154
+ <div style={{
155
+ position: 'absolute', top: 32, left: 0, zIndex: 100,
156
+ background: 'var(--bg-panel)', border: '1px solid var(--border-color)',
157
+ borderRadius: '6px', padding: '12px', display: 'flex', flexDirection: 'column', gap: '8px',
158
+ boxShadow: '0 4px 12px rgba(0,0,0,0.1)', minWidth: 160
159
+ }}>
160
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: '4px' }}>
161
+ {colors.map(c => (
162
+ <div
163
+ key={c}
164
+ onClick={() => applyColor(c)}
165
+ style={{ width: 24, height: 24, background: c, borderRadius: '2px', cursor: 'pointer', border: '1px solid rgba(0,0,0,0.05)' }}
166
+ />
167
+ ))}
168
+ </div>
169
+
170
+ <div style={{ height: 1, backgroundColor: 'var(--border-color)', margin: '4px 0' }} />
171
+
172
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
173
+ <input
174
+ type="color"
175
+ onChange={(e) => applyColor(e.target.value)}
176
+ style={{ width: 32, height: 32, border: 'none', background: 'none', padding: 0, cursor: 'pointer' }}
177
+ />
178
+ <input
179
+ type="text"
180
+ placeholder="#000000"
181
+ style={{ flex: 1, fontSize: '11px', padding: '4px 8px', border: '1px solid var(--border-color)', borderRadius: '4px', outline: 'none' }}
182
+ onKeyDown={(e: any) => { if (e.key === 'Enter') applyColor(e.target.value); }}
183
+ />
184
+ </div>
185
+ <div style={{ fontSize: '9px', opacity: 0.5, textAlign: 'center' }}>Enter to apply Hex</div>
186
+ </div>
187
+ )}
188
+ </div>
189
+ </div>
190
+ );
191
+ }
src/components/Editor/LineNumberPlugin.tsx ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
2
+ import { useEffect, useState, useRef } from 'react';
3
+ import { $getRoot, $isParagraphNode } from 'lexical';
4
+ import { useFileStore } from '../../stores/fileStore';
5
+ import { Comment01Icon } from 'hugeicons-react';
6
+
7
+ export default function LineNumbers() {
8
+ const [editor] = useLexicalComposerContext();
9
+ const { activeFileId, files, setComment } = useFileStore();
10
+ const activeFile = files.find(f => f.id === activeFileId);
11
+ const [lines, setLines] = useState<{ id: string, top: number, height: number, index: number }[]>([]);
12
+ const [activeCommentLine, setActiveCommentLine] = useState<string | null>(null);
13
+ const [expandedComments, setExpandedComments] = useState<Set<string>>(new Set());
14
+ const [commentText, setCommentText] = useState('');
15
+ const containerRef = useRef<HTMLDivElement>(null);
16
+
17
+ useEffect(() => {
18
+ const updateLineNumbers = () => {
19
+ editor.getEditorState().read(() => {
20
+ const root = $getRoot();
21
+ const children = root.getChildren();
22
+ const newLines: any[] = [];
23
+
24
+ const containerElement = containerRef.current;
25
+ if (!containerElement) return;
26
+
27
+ const containerRect = containerElement.getBoundingClientRect();
28
+
29
+ let globalIndex = 1;
30
+ children.forEach((node) => {
31
+ if ($isParagraphNode(node)) {
32
+ const elm = editor.getElementByKey(node.getKey());
33
+ if (elm) {
34
+ const rect = elm.getBoundingClientRect();
35
+
36
+ const textContent = node.getTextContent();
37
+ const explicitLines = textContent.split('\n').length;
38
+ const computedLineHeight = 22.5; // 15px * 1.5
39
+
40
+ for (let i = 0; i < explicitLines; i++) {
41
+ const lineId = `${node.getKey()}${i > 0 ? '-' + i : ''}`;
42
+ newLines.push({
43
+ id: lineId,
44
+ rootId: node.getKey(),
45
+ top: (rect.top - containerRect.top) + (i * computedLineHeight),
46
+ height: computedLineHeight,
47
+ index: globalIndex++,
48
+ });
49
+ }
50
+ }
51
+ }
52
+ });
53
+ setLines(newLines);
54
+ });
55
+ };
56
+
57
+ const unregister = editor.registerUpdateListener(() => {
58
+ // Small delay to ensure DOM has reflowed
59
+ setTimeout(updateLineNumbers, 0);
60
+ });
61
+
62
+ // Initial and periodic syncs
63
+ updateLineNumbers();
64
+ const interval = setInterval(updateLineNumbers, 1000);
65
+
66
+ window.addEventListener('resize', updateLineNumbers);
67
+
68
+ return () => {
69
+ unregister();
70
+ clearInterval(interval);
71
+ window.removeEventListener('resize', updateLineNumbers);
72
+ };
73
+ }, [editor]);
74
+
75
+ return (
76
+ <div
77
+ ref={containerRef}
78
+ className="line-numbers-container"
79
+ style={{
80
+ position: 'relative',
81
+ width: 45,
82
+ minHeight: '100%',
83
+ borderRight: '1px solid rgba(0,0,0,0.05)',
84
+ marginRight: 0,
85
+ backgroundColor: 'transparent',
86
+ userSelect: 'none',
87
+ pointerEvents: 'none'
88
+ }}
89
+ >
90
+ {lines.map(line => (
91
+ <div
92
+ key={line.id}
93
+ className="line-number-item"
94
+ style={{
95
+ position: 'absolute',
96
+ top: line.top,
97
+ width: '100%',
98
+ textAlign: 'right',
99
+ paddingRight: 12,
100
+ color: 'var(--text-secondary)',
101
+ fontSize: '15px',
102
+ opacity: 0.3,
103
+ fontFamily: 'var(--font-ibm-plex)',
104
+ lineHeight: '1.5',
105
+ pointerEvents: 'auto',
106
+ cursor: 'pointer',
107
+ display: 'flex',
108
+ flexDirection: 'column',
109
+ alignItems: 'flex-end'
110
+ }}
111
+ onClick={(e) => {
112
+ e.stopPropagation();
113
+ setActiveCommentLine(line.id);
114
+ setCommentText(activeFile?.comments?.[line.id] || '');
115
+ }}
116
+ >
117
+ <div style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>
118
+ {activeFile?.comments?.[line.id] && (
119
+ <button
120
+ onClick={(e) => {
121
+ e.stopPropagation();
122
+ setExpandedComments(prev => {
123
+ const next = new Set(prev);
124
+ if (next.has(line.id)) next.delete(line.id);
125
+ else next.add(line.id);
126
+ return next;
127
+ });
128
+ }}
129
+ style={{
130
+ opacity: expandedComments.has(line.id) ? 1 : 0.4,
131
+ color: expandedComments.has(line.id) ? 'var(--accent-color)' : 'inherit',
132
+ display: 'flex', alignItems: 'center'
133
+ }}
134
+ title={expandedComments.has(line.id) ? "Minimize comment" : "Expand comment"}
135
+ >
136
+ <Comment01Icon size={12} />
137
+ </button>
138
+ )}
139
+ {line.index}
140
+ </div>
141
+
142
+ {/* Top-part comment UI */}
143
+ {activeCommentLine === line.id && (
144
+ <div
145
+ onClick={e => e.stopPropagation()}
146
+ style={{
147
+ position: 'fixed', left: 60, zIndex: 100,
148
+ background: 'var(--bg-panel)', border: '1px solid var(--border-color)',
149
+ borderRadius: '6px', padding: '12px', width: 220,
150
+ boxShadow: '0 10px 25px rgba(0,0,0,0.1)'
151
+ }}
152
+ >
153
+ <textarea
154
+ autoFocus
155
+ value={commentText}
156
+ onChange={e => setCommentText(e.target.value)}
157
+ placeholder="Line comment..."
158
+ style={{ width: '100%', height: 60, fontSize: '11px', border: 'none', outline: 'none', background: 'transparent', resize: 'none' }}
159
+ />
160
+ <div style={{ display: 'flex', justifyContent: 'flex-end', gap: '8px', marginTop: '8px' }}>
161
+ <button onClick={() => setActiveCommentLine(null)} style={{ fontSize: '10px', opacity: 0.5 }}>Cancel</button>
162
+ <button
163
+ onClick={() => {
164
+ if (activeFileId) setComment(activeFileId, line.id, commentText);
165
+ setActiveCommentLine(null);
166
+ }}
167
+ style={{ fontSize: '10px', fontWeight: 600, color: 'var(--accent-color)' }}
168
+ >Save</button>
169
+ </div>
170
+ </div>
171
+ )}
172
+
173
+ {activeFile?.comments?.[line.id] && activeCommentLine !== line.id && expandedComments.has(line.id) && (
174
+ <div
175
+ className="comment-bubble"
176
+ onClick={(e) => {
177
+ e.stopPropagation();
178
+ setExpandedComments(prev => {
179
+ const next = new Set(prev);
180
+ next.delete(line.id);
181
+ return next;
182
+ });
183
+ }}
184
+ title="Click to minimize"
185
+ style={{
186
+ marginTop: 4,
187
+ textAlign: 'left',
188
+ wordBreak: 'break-word',
189
+ userSelect: 'text',
190
+ cursor: 'pointer',
191
+ animation: 'fadeInSlide 0.2s ease forwards'
192
+ }}
193
+ >
194
+ {activeFile.comments[line.id]}
195
+ </div>
196
+ )}
197
+ </div>
198
+ ))}
199
+ </div>
200
+ );
201
+ }
src/components/Settings/SettingsModal.tsx ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useEffect, useRef } from 'react';
2
+ import {
3
+ getSettings, saveSettings, saveBackgroundImage,
4
+ SettingsType, HighlighterRule, exportFullWorkspace, importWorkspace,
5
+ resetBackgroundImage
6
+ } from '../../lib/db';
7
+ import ReactCrop, { Crop } from 'react-image-crop';
8
+ import 'react-image-crop/dist/ReactCrop.css';
9
+ import {
10
+ Settings01Icon, Add01Icon, Delete01Icon,
11
+ Download01Icon, Upload01Icon, Copy01Icon
12
+ } from 'hugeicons-react';
13
+
14
+ function extractTextFromLexical(jsonString?: string) {
15
+ if (!jsonString) return '';
16
+ try {
17
+ const root = JSON.parse(jsonString).root;
18
+ let text = '';
19
+ function traverse(node: any) {
20
+ if (node.type === 'text') text += node.text;
21
+ if (node.type === 'linebreak') text += '\n';
22
+ if (node.children) {
23
+ node.children.forEach(traverse);
24
+ if (node.type === 'paragraph') text += '\n'; // Add newline for paragraphs
25
+ }
26
+ }
27
+ traverse(root);
28
+ return text.trim();
29
+ } catch { return ''; }
30
+ }
31
+
32
+ export default function SettingsModal({ onClose }: { onClose: () => void }) {
33
+ const [settings, setSettings] = useState<SettingsType | null>(null);
34
+ const [imgSrc, setImgSrc] = useState('');
35
+ const [crop, setCrop] = useState<Crop>();
36
+ const [importText, setImportText] = useState('');
37
+ const [showImport, setShowImport] = useState(false);
38
+ const imgRef = useRef<HTMLImageElement>(null);
39
+
40
+ useEffect(() => {
41
+ getSettings().then(setSettings);
42
+ }, []);
43
+
44
+ const handleChangeCryptography = async (font: any) => {
45
+ if (!settings) return;
46
+ const newSettings = { ...settings, typography: font };
47
+ setSettings(newSettings);
48
+ await saveSettings(newSettings);
49
+ window.location.reload();
50
+ };
51
+
52
+ const handleChangeOpacity = async (field: 'bgOpacity' | 'fgOpacity', val: number) => {
53
+ if (!settings) return;
54
+ const newSettings = { ...settings, [field]: val };
55
+ setSettings(newSettings);
56
+ await saveSettings(newSettings);
57
+ document.documentElement.style.setProperty(`--${field === 'bgOpacity' ? 'bg' : 'fg'}-opacity`, val.toString());
58
+ };
59
+
60
+ const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
61
+ if (e.target.files && e.target.files.length > 0) {
62
+ const reader = new FileReader();
63
+ reader.addEventListener('load', () => setImgSrc(reader.result?.toString() || ''));
64
+ reader.readAsDataURL(e.target.files[0]);
65
+ }
66
+ };
67
+
68
+ const completeImageSave = async () => {
69
+ if (imgSrc && imgRef.current && crop) {
70
+ const canvas = document.createElement('canvas');
71
+ const scaleX = imgRef.current.naturalWidth / imgRef.current.width;
72
+ const scaleY = imgRef.current.naturalHeight / imgRef.current.height;
73
+ canvas.width = crop.width;
74
+ canvas.height = crop.height;
75
+ const ctx = canvas.getContext('2d');
76
+
77
+ if (ctx) {
78
+ ctx.drawImage(
79
+ imgRef.current,
80
+ crop.x * scaleX,
81
+ crop.y * scaleY,
82
+ crop.width * scaleX,
83
+ crop.height * scaleY,
84
+ 0,
85
+ 0,
86
+ crop.width,
87
+ crop.height
88
+ );
89
+ const base64Image = canvas.toDataURL('image/jpeg');
90
+ await saveBackgroundImage(base64Image);
91
+ window.location.reload();
92
+ }
93
+ } else if (imgSrc) {
94
+ await saveBackgroundImage(imgSrc);
95
+ window.location.reload();
96
+ }
97
+ };
98
+
99
+ const handleResetBackground = async () => {
100
+ await resetBackgroundImage();
101
+ window.location.reload();
102
+ };
103
+
104
+ const handleUpdateRule = async (id: string, updates: Partial<HighlighterRule>) => {
105
+ if (!settings) return;
106
+ const newRules = settings.highlighters.map(r => r.id === id ? { ...r, ...updates } : r);
107
+ const newSettings = { ...settings, highlighters: newRules };
108
+ setSettings(newSettings);
109
+ await saveSettings(newSettings);
110
+ };
111
+
112
+ const handleAddRule = async () => {
113
+ if (!settings) return;
114
+ const newRule: HighlighterRule = {
115
+ id: Math.random().toString(36).substring(2, 9),
116
+ openSymbol: '(', closeSymbol: ')', color: '#ffb3ba',
117
+ baseOpacity: 0.1, stackMode: 'larger-lighter'
118
+ };
119
+ const newSettings = { ...settings, highlighters: [...settings.highlighters, newRule] };
120
+ setSettings(newSettings);
121
+ await saveSettings(newSettings);
122
+ };
123
+
124
+ const handleDeleteRule = async (id: string) => {
125
+ if (!settings) return;
126
+ const newSettings = { ...settings, highlighters: settings.highlighters.filter(r => r.id !== id) };
127
+ setSettings(newSettings);
128
+ await saveSettings(newSettings);
129
+ };
130
+
131
+ const handleExport = async () => {
132
+ const data = await exportFullWorkspace();
133
+ const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
134
+ const url = URL.createObjectURL(blob);
135
+ const a = document.createElement('a');
136
+ a.href = url;
137
+ a.download = `workspace-backup-${new Date().toISOString().split('T')[0]}.json`;
138
+ a.click();
139
+ URL.revokeObjectURL(url);
140
+ };
141
+
142
+ const handleCopyCleanWorkspace = async () => {
143
+ const data = await exportFullWorkspace();
144
+ let textOut = '--- WORKSPACE EXPORT ---\n\n';
145
+ data.files.forEach(f => {
146
+ if (f.type === 'file') {
147
+ textOut += `[FILE: ${f.name}]\n`;
148
+ textOut += extractTextFromLexical(f.content);
149
+ textOut += '\n\n';
150
+ }
151
+ });
152
+ await navigator.clipboard.writeText(textOut);
153
+ alert('Clean textual workspace copied to clipboard!');
154
+ };
155
+
156
+ const handleImport = async () => {
157
+ try {
158
+ const data = JSON.parse(importText);
159
+ if (data.files && data.settings) {
160
+ await importWorkspace(data);
161
+ alert('Import successful! Reloading...');
162
+ window.location.reload();
163
+ } else {
164
+ alert('Invalid workspace JSON format.');
165
+ }
166
+ } catch (e) {
167
+ alert('Failed to parse JSON.');
168
+ }
169
+ };
170
+
171
+ if (!settings) return null;
172
+
173
+ return (
174
+ <div className="modal-overlay" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }} style={{
175
+ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0,
176
+ backgroundColor: 'rgba(0,0,0,0.4)', backdropFilter: 'blur(12px)', zIndex: 1000,
177
+ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '20px'
178
+ }}>
179
+ <div className="modal-content" style={{
180
+ background: 'rgba(255, 255, 255, 0.95)',
181
+ backdropFilter: 'blur(20px)',
182
+ padding: '36px',
183
+ borderRadius: 'var(--radius-sm)',
184
+ width: '100%', maxWidth: '640px',
185
+ maxHeight: '85vh', overflowY: 'auto',
186
+ boxShadow: '0 40px 80px rgba(0,0,0,0.15)',
187
+ border: '1px solid rgba(255,255,255,0.4)',
188
+ fontFamily: 'var(--font-ibm-plex)'
189
+ }}>
190
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '32px', borderBottom: '1px solid rgba(0,0,0,0.05)', paddingBottom: '16px' }}>
191
+ <h2 style={{ fontSize: '22px', fontWeight: 600, display: 'flex', alignItems: 'center', gap: '12px', letterSpacing: '-0.02em' }}>
192
+ <Settings01Icon size={28} /> System Settings
193
+ </h2>
194
+ <button onClick={onClose} style={{ opacity: 0.4, fontSize: '13px', background: 'rgba(0,0,0,0.05)', padding: '6px 12px', borderRadius: '4px' }}>ESC</button>
195
+ </div>
196
+
197
+ {/* Persistence Section */}
198
+ <div style={{ marginBottom: '40px' }}>
199
+ <h4 style={{ fontSize: '11px', fontWeight: 700, textTransform: 'uppercase', opacity: 0.4, marginBottom: '16px', letterSpacing: '0.05em' }}>Data Management</h4>
200
+ <div style={{ display: 'flex', gap: '8px' }}>
201
+ <button onClick={handleExport} style={{ flex: 1, padding: '12px', background: '#111', color: '#fff', borderRadius: '4px', fontSize: '13px', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px', border: '1px solid #111' }}>
202
+ <Download01Icon size={16} /> JSON Backup
203
+ </button>
204
+ <button onClick={handleCopyCleanWorkspace} style={{ flex: 1, padding: '12px', background: '#fff', color: '#111', borderRadius: '4px', fontSize: '13px', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px', border: '1px solid #ddd' }}>
205
+ <Copy01Icon size={16} /> Copy Clean Text
206
+ </button>
207
+ <button onClick={() => setShowImport(!showImport)} style={{ flex: 1, padding: '12px', background: 'transparent', border: '1px solid #ddd', borderRadius: '4px', fontSize: '13px', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: '8px' }}>
208
+ <Upload01Icon size={16} /> Import JSON
209
+ </button>
210
+ </div>
211
+ {showImport && (
212
+ <div style={{ marginTop: '12px' }}>
213
+ <textarea
214
+ placeholder="Paste workspace JSON here..."
215
+ value={importText}
216
+ onChange={e => setImportText(e.target.value)}
217
+ style={{ width: '100%', height: '120px', padding: '16px', borderRadius: '4px', border: '1px solid #ddd', fontSize: '12px', outline: 'none', background: '#fcfcfc', resize: 'vertical' }}
218
+ />
219
+ <button onClick={handleImport} style={{ marginTop: '8px', width: '100%', padding: '12px', background: 'var(--accent-color)', color: '#fff', borderRadius: '4px', fontSize: '14px', fontWeight: 500 }}>Restore Workspace</button>
220
+ </div>
221
+ )}
222
+ </div>
223
+
224
+ <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '24px', marginBottom: '40px' }}>
225
+ <div>
226
+ <h4 style={{ fontSize: '11px', fontWeight: 700, textTransform: 'uppercase', opacity: 0.4, marginBottom: '12px', letterSpacing: '0.05em' }}>Typography</h4>
227
+ <select
228
+ value={settings.typography}
229
+ onChange={e => handleChangeCryptography(e.target.value)}
230
+ style={{ padding: '12px 16px', width: '100%', border: '1px solid #ddd', borderRadius: '4px', outline: 'none', fontSize: '14px', background: '#fcfcfc', appearance: 'none' }}
231
+ >
232
+ <option value="IBM Plex Mono">IBM Plex Mono</option>
233
+ <option value="ClaudeSans">ClaudeSans (Inter)</option>
234
+ <option value="WixMadeForDisplay">WixMadeForDisplay</option>
235
+ <option value="CourierNew">CourierNew</option>
236
+ </select>
237
+ </div>
238
+
239
+ <div>
240
+ <h4 style={{ fontSize: '11px', fontWeight: 700, textTransform: 'uppercase', opacity: 0.4, marginBottom: '12px', letterSpacing: '0.05em' }}>Opacities</h4>
241
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
242
+ <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
243
+ <span style={{ fontSize: '12px', width: '90px' }}>Background</span>
244
+ <input type="range" min="0" max="1" step="0.05" value={settings.bgOpacity ?? 0.15} onChange={e => handleChangeOpacity('bgOpacity', parseFloat(e.target.value))} style={{ flex: 1 }} />
245
+ <span style={{ fontSize: '12px', opacity: 0.5, width: '30px', textAlign: 'right' }}>{Math.round((settings.bgOpacity ?? 0.15) * 100)}%</span>
246
+ </div>
247
+ <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
248
+ <span style={{ fontSize: '12px', width: '90px' }}>Foreground</span>
249
+ <input type="range" min="0" max="1" step="0.05" value={settings.fgOpacity ?? 1} onChange={e => handleChangeOpacity('fgOpacity', parseFloat(e.target.value))} style={{ flex: 1 }} />
250
+ <span style={{ fontSize: '12px', opacity: 0.5, width: '30px', textAlign: 'right' }}>{Math.round((settings.fgOpacity ?? 1) * 100)}%</span>
251
+ </div>
252
+ </div>
253
+ </div>
254
+ </div>
255
+
256
+ <div style={{ marginBottom: '40px' }}>
257
+ <h4 style={{ fontSize: '11px', fontWeight: 700, textTransform: 'uppercase', opacity: 0.4, marginBottom: '16px', letterSpacing: '0.05em' }}>Visual Background</h4>
258
+ <div style={{ background: '#fcfcfc', padding: '24px', borderRadius: '4px', border: '1px solid #ddd' }}>
259
+ <input type="file" accept="image/*" onChange={handleImageUpload} style={{ fontSize: '13px', marginBottom: '16px' }} />
260
+ {imgSrc && (
261
+ <ReactCrop crop={crop} onChange={c => setCrop(c)}>
262
+ <img ref={imgRef} src={imgSrc} style={{ width: '100%', borderRadius: '4px', display: 'block' }} alt="Background preview" />
263
+ </ReactCrop>
264
+ )}
265
+ <div style={{ display: 'flex', gap: '8px', marginTop: imgSrc ? '16px' : '0' }}>
266
+ <button onClick={completeImageSave} style={{ flex: 2, padding: '10px', background: '#111', color: '#fff', borderRadius: '4px', fontSize: '13px' }}>Set Background</button>
267
+ <button onClick={handleResetBackground} style={{ flex: 1, padding: '10px', background: 'transparent', border: '1px solid #ddd', borderRadius: '4px', fontSize: '13px' }}>Clear</button>
268
+ </div>
269
+ </div>
270
+ </div>
271
+
272
+ <div>
273
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
274
+ <h4 style={{ fontSize: '11px', fontWeight: 700, textTransform: 'uppercase', opacity: 0.4, letterSpacing: '0.05em' }}>Auto-Highlighter Rules</h4>
275
+ <button onClick={handleAddRule} style={{ fontSize: '12px', background: '#111', color: '#fff', padding: '6px 12px', borderRadius: '4px', display: 'flex', alignItems: 'center', gap: '6px' }}>
276
+ <Add01Icon size={14} /> Add Pattern
277
+ </button>
278
+ </div>
279
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
280
+ {settings.highlighters.map(hl => (
281
+ <div key={hl.id} style={{
282
+ padding: '16px', background: '#fcfcfc',
283
+ borderRadius: '4px', border: '1px solid #eee',
284
+ display: 'grid', gridTemplateColumns: 'minmax(0, 1.5fr) minmax(0, 1.5fr) minmax(0, 2fr) auto', gap: '16px', alignItems: 'end'
285
+ }}>
286
+ <div>
287
+ <label style={{ fontSize: '10px', fontWeight: 600, opacity: 0.4, display: 'block', marginBottom: '6px' }}>SYMBOLS</label>
288
+ <div style={{ display: 'flex', alignItems: 'center', background: '#fff', border: '1px solid #ddd', borderRadius: '4px', padding: '4px 8px' }}>
289
+ <input value={hl.openSymbol} onChange={e => handleUpdateRule(hl.id, { openSymbol: e.target.value })} style={{ width: '100%', textAlign: 'center', border: 'none', background: 'transparent', outline: 'none', fontSize: '13px' }} placeholder="Open" />
290
+ <span style={{ opacity: 0.2 }}>|</span>
291
+ <input value={hl.closeSymbol} onChange={e => handleUpdateRule(hl.id, { closeSymbol: e.target.value })} style={{ width: '100%', textAlign: 'center', border: 'none', background: 'transparent', outline: 'none', fontSize: '13px' }} placeholder="Close" />
292
+ </div>
293
+ </div>
294
+ <div>
295
+ <label style={{ fontSize: '10px', fontWeight: 600, opacity: 0.4, display: 'block', marginBottom: '6px' }}>COLOR & OPACITY</label>
296
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px', background: '#fff', border: '1px solid #ddd', borderRadius: '4px', padding: '2px 8px' }}>
297
+ <input type="color" value={hl.color} onChange={e => handleUpdateRule(hl.id, { color: e.target.value })} style={{ width: '24px', height: '24px', border: 'none', padding: 0, background: 'none' }} />
298
+ <div style={{ width: '1px', height: '16px', background: '#ddd' }} />
299
+ <input type="number" min="1" max="100" value={Math.round(hl.baseOpacity * 100)} onChange={e => handleUpdateRule(hl.id, { baseOpacity: parseInt(e.target.value)/100 })} style={{ width: '100%', border: 'none', background: 'transparent', outline: 'none', fontSize: '13px' }} />
300
+ <span style={{ fontSize: '11px', opacity: 0.4 }}>%</span>
301
+ </div>
302
+ </div>
303
+ <div>
304
+ <label style={{ fontSize: '10px', fontWeight: 600, opacity: 0.4, display: 'block', marginBottom: '6px' }}>NESTING LOGIC</label>
305
+ <select value={hl.stackMode} onChange={e => handleUpdateRule(hl.id, { stackMode: e.target.value as any })} style={{ width: '100%', padding: '6px 8px', borderRadius: '4px', border: '1px solid #ddd', background: '#fff', outline: 'none', fontSize: '12px' }}>
306
+ <option value="larger-lighter">Reverse Direction (Larger = Lighter)</option>
307
+ <option value="smaller-lighter">Default Direction (Smaller = Lighter)</option>
308
+ </select>
309
+ </div>
310
+ <button onClick={() => handleDeleteRule(hl.id)} style={{ padding: '8px', color: '#ff4d4f', background: 'rgba(255, 77, 79, 0.1)', borderRadius: '4px', display: 'flex' }}>
311
+ <Delete01Icon size={16} />
312
+ </button>
313
+ </div>
314
+ ))}
315
+ </div>
316
+ </div>
317
+ </div>
318
+ </div>
319
+ );
320
+ }
src/components/Sidebar/IconPicker.tsx ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState } from 'react';
2
+ import * as HugeIcons from 'hugeicons-react';
3
+ import iconNames from '../../utils/icon_names.json';
4
+
5
+ interface IconPickerProps {
6
+ onSelect: (iconName: string, color?: string) => void;
7
+ onClose: () => void;
8
+ }
9
+
10
+ export default function IconPicker({ onSelect, onClose }: IconPickerProps) {
11
+ const [search, setSearch] = useState('');
12
+ const [selectedColor, setSelectedColor] = useState<string | undefined>(undefined);
13
+
14
+ const COLORS = [
15
+ '#2e6ff2', '#e11d48', '#d97706', '#16a34a',
16
+ '#9333ea', '#db2777', '#0891b2', '#475569',
17
+ '#111111'
18
+ ];
19
+
20
+ const filteredIcons = iconNames.filter(name =>
21
+ name.toLowerCase().includes(search.toLowerCase())
22
+ ).slice(0, 100); // Limit results for performance
23
+
24
+ return (
25
+ <div className="icon-picker-overlay" onClick={onClose} style={{
26
+ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0,
27
+ zIndex: 2000, display: 'flex', alignItems: 'center', justifyContent: 'center',
28
+ backgroundColor: 'rgba(0,0,0,0.2)'
29
+ }}>
30
+ <div className="icon-picker" onClick={e => e.stopPropagation()} style={{
31
+ background: 'var(--bg-panel)', padding: '16px', borderRadius: '8px',
32
+ boxShadow: '0 8px 32px rgba(0,0,0,0.15)', width: '400px', maxHeight: '500px',
33
+ display: 'flex', flexDirection: 'column', border: '1px solid var(--border-color)'
34
+ }}>
35
+ <input
36
+ autoFocus
37
+ placeholder="Search icons..."
38
+ value={search}
39
+ onChange={e => setSearch(e.target.value)}
40
+ style={{
41
+ width: '100%', padding: '10px', marginBottom: '12px',
42
+ border: '1px solid var(--border-color)', borderRadius: '4px',
43
+ outline: 'none', fontSize: '14px'
44
+ }}
45
+ />
46
+
47
+ <div className="icon-grid" style={{
48
+ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)',
49
+ gap: '8px', overflowY: 'auto', flex: 1, padding: '4px'
50
+ }}>
51
+ {filteredIcons.map(name => {
52
+ const Icon = (HugeIcons as any)[name];
53
+ if (!Icon) return null;
54
+ return (
55
+ <button
56
+ key={name}
57
+ onClick={() => { onSelect(name, selectedColor); onClose(); }}
58
+ title={name}
59
+ style={{
60
+ display: 'flex', alignItems: 'center', justifyContent: 'center',
61
+ padding: '8px', borderRadius: '4px', background: 'transparent',
62
+ border: '1px solid transparent', cursor: 'pointer', transition: 'var(--transition-smooth)'
63
+ }}
64
+ onMouseEnter={e => e.currentTarget.style.background = 'rgba(0,0,0,0.05)'}
65
+ onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
66
+ >
67
+ <Icon size={20} color={selectedColor || "var(--text-primary)"} />
68
+ </button>
69
+ );
70
+ })}
71
+ </div>
72
+
73
+ <div style={{ marginTop: '12px', borderTop: '1px solid var(--border-color)', paddingTop: '12px', display: 'flex', gap: '8px', justifyContent: 'center' }}>
74
+ {COLORS.map(c => (
75
+ <div
76
+ key={c}
77
+ onClick={() => setSelectedColor(c)}
78
+ style={{
79
+ width: '20px', height: '20px', borderRadius: '50%', backgroundColor: c,
80
+ cursor: 'pointer', border: selectedColor === c ? '2px solid var(--text-primary)' : '2px solid transparent',
81
+ boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
82
+ }}
83
+ />
84
+ ))}
85
+ <div
86
+ onClick={() => setSelectedColor(undefined)}
87
+ style={{
88
+ width: '20px', height: '20px', borderRadius: '50%', border: '1px dashed var(--text-secondary)',
89
+ cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '10px'
90
+ }}
91
+ >
92
+ x
93
+ </div>
94
+ </div>
95
+
96
+ {filteredIcons.length === 0 && (
97
+ <div style={{ textAlign: 'center', padding: '20px', color: 'var(--text-secondary)' }}>
98
+ No icons found
99
+ </div>
100
+ )}
101
+ </div>
102
+ </div>
103
+ );
104
+ }
src/components/Sidebar/TreeView.tsx ADDED
@@ -0,0 +1,458 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useFileStore } from '../../stores/fileStore';
2
+ import { FileNode } from '../../lib/db';
3
+ import { useState, useMemo, useEffect, useRef } from 'react';
4
+ import {
5
+ Folder01Icon,
6
+ File01Icon,
7
+ MoreVerticalIcon,
8
+ FolderAddIcon,
9
+ FileAddIcon,
10
+ ArrowDown01Icon,
11
+ ArrowRight01Icon,
12
+ DragDropVerticalIcon,
13
+ Copy01Icon
14
+ } from 'hugeicons-react';
15
+ import * as HugeIcons from 'hugeicons-react';
16
+ import IconPicker from './IconPicker';
17
+
18
+ import {
19
+ DndContext,
20
+ closestCenter,
21
+ KeyboardSensor,
22
+ PointerSensor,
23
+ useSensor,
24
+ useSensors,
25
+ DragEndEvent,
26
+ } from '@dnd-kit/core';
27
+ import {
28
+ SortableContext,
29
+ sortableKeyboardCoordinates,
30
+ verticalListSortingStrategy,
31
+ useSortable,
32
+ } from '@dnd-kit/sortable';
33
+ import { CSS } from '@dnd-kit/utilities';
34
+
35
+ export default function TreeView() {
36
+ const { files, loadFiles, createNode, reorderNodes, moveNode, copySelectedContents } = useFileStore();
37
+
38
+ const sensors = useSensors(
39
+ useSensor(PointerSensor),
40
+ useSensor(KeyboardSensor, {
41
+ coordinateGetter: sortableKeyboardCoordinates,
42
+ })
43
+ );
44
+
45
+ // Pre-calculate tree structure for O(N) rendering instead of O(N^2)
46
+ const rootNodes = useMemo(() => files.filter(f => !f.parentId).sort((a,b) => a.orderIndex - b.orderIndex), [files]);
47
+ const childrenMap = useMemo(() => {
48
+ const map: Record<string, FileNode[]> = {};
49
+ files.forEach(f => {
50
+ if (f.parentId) {
51
+ if (!map[f.parentId]) map[f.parentId] = [];
52
+ map[f.parentId].push(f);
53
+ }
54
+ });
55
+ // Sort each child group
56
+ Object.keys(map).forEach(key => {
57
+ map[key].sort((a,b) => a.orderIndex - b.orderIndex);
58
+ });
59
+ return map;
60
+ }, [files]);
61
+
62
+ const handleDragEnd = async (event: DragEndEvent) => {
63
+ const { active, over } = event;
64
+ if (!over || active.id === over.id) return;
65
+
66
+ if (over.id.toString().startsWith('empty-')) {
67
+ const targetId = over.id.toString().replace('empty-', '');
68
+
69
+ let currentId: string | null = targetId;
70
+ while (currentId) {
71
+ if (currentId === active.id) return;
72
+ const p = files.find(f => f.id === currentId);
73
+ currentId = p?.parentId || null;
74
+ }
75
+
76
+ await moveNode(active.id.toString(), targetId);
77
+ await loadFiles();
78
+ return;
79
+ }
80
+
81
+ const overNode = files.find(f => f.id === over.id);
82
+ if (!overNode) return;
83
+
84
+ let targetParentId = overNode.parentId || null;
85
+ let currentId = targetParentId;
86
+ while (currentId) {
87
+ if (currentId === active.id) return;
88
+ const p = files.find(f => f.id === currentId);
89
+ currentId = p?.parentId || null;
90
+ }
91
+
92
+ await reorderNodes(active.id.toString(), over.id.toString(), targetParentId);
93
+ await loadFiles();
94
+ };
95
+
96
+ const handleCopyAll = () => {
97
+ const text = copySelectedContents();
98
+ if (text) {
99
+ navigator.clipboard.writeText(text);
100
+ }
101
+ };
102
+
103
+ const handleAdd = async (type: 'file' | 'folder') => {
104
+ await createNode(type === 'file' ? 'New file' : 'New folder', type, null);
105
+ await loadFiles();
106
+ };
107
+
108
+ return (
109
+ <div className="tree-view" style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
110
+ <div className="tree-actions" style={{
111
+ padding: '12px 16px',
112
+ display: 'flex',
113
+ justifyContent: 'space-between',
114
+ alignItems: 'center',
115
+ borderBottom: '1px solid rgba(0,0,0,0.03)'
116
+ }}>
117
+ <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
118
+ <span style={{ fontSize: '10px', fontWeight: 700, opacity: 0.3, textTransform: 'uppercase' }}>Structure</span>
119
+ <button
120
+ className="btn-icon-sm"
121
+ onClick={handleCopyAll}
122
+ title="Copy all selected contents"
123
+ style={{ opacity: 0.5, cursor: 'pointer', border: 'none', background: 'transparent', padding: 0 }}
124
+ >
125
+ <Copy01Icon size={12} />
126
+ </button>
127
+ </div>
128
+ <div style={{ display: 'flex', gap: '4px' }}>
129
+ <button className="btn-icon-sm" onClick={() => handleAdd('file')} title="Add File">
130
+ <FileAddIcon size={14} />
131
+ </button>
132
+ <button className="btn-icon-sm" onClick={() => handleAdd('folder')} title="Add Folder">
133
+ <FolderAddIcon size={14} />
134
+ </button>
135
+ </div>
136
+ </div>
137
+ <div className="tree-scrollable" style={{ flex: 1, overflowY: 'auto', padding: '8px 0' }}>
138
+ <DndContext
139
+ sensors={sensors}
140
+ collisionDetection={closestCenter}
141
+ onDragEnd={handleDragEnd}
142
+ >
143
+ <SortableContext
144
+ items={rootNodes.map(n => n.id)}
145
+ strategy={verticalListSortingStrategy}
146
+ >
147
+ {rootNodes.map(node => (
148
+ <SidebarItem
149
+ key={node.id}
150
+ node={node}
151
+ level={0}
152
+ childrenMap={childrenMap}
153
+ />
154
+ ))}
155
+ </SortableContext>
156
+ </DndContext>
157
+ </div>
158
+ </div>
159
+ );
160
+ }
161
+
162
+ function SidebarItem({
163
+ node,
164
+ level,
165
+ childrenMap
166
+ }: {
167
+ node: FileNode;
168
+ level: number;
169
+ childrenMap: Record<string, FileNode[]>
170
+ }) {
171
+ const {
172
+ activeFileId, selectedIds,
173
+ toggleSelect, renameNode, deleteNode, duplicateNode, createNode, loadFiles, setNodeIcon, setNodeColor, copyNodeContents
174
+ } = useFileStore();
175
+
176
+ const [isExpanded, setIsExpanded] = useState(true);
177
+ const [isEditing, setIsEditing] = useState(false);
178
+ const [editName, setEditName] = useState(node.name);
179
+ const [showMenu, setShowMenu] = useState(false);
180
+ const [showIconPicker, setShowIconPicker] = useState(false);
181
+ const containerRef = useRef<HTMLDivElement>(null);
182
+
183
+ const {
184
+ attributes,
185
+ listeners,
186
+ setNodeRef,
187
+ transform,
188
+ transition,
189
+ isDragging
190
+ } = useSortable({ id: node.id });
191
+
192
+ const style = {
193
+ transform: CSS.Transform.toString(transform),
194
+ transition,
195
+ opacity: isDragging ? 0.5 : 1,
196
+ };
197
+
198
+ useEffect(() => {
199
+ if (!showMenu && !showIconPicker) return;
200
+
201
+ const handleEvents = (e: any) => {
202
+ // Close on Escape
203
+ if (e.key === 'Escape') {
204
+ setShowMenu(false);
205
+ setShowIconPicker(false);
206
+ }
207
+ // Close on Outside Click
208
+ if (e.type === 'mousedown' && containerRef.current && !containerRef.current.contains(e.target as Node)) {
209
+ setShowMenu(false);
210
+ setShowIconPicker(false);
211
+ }
212
+ };
213
+
214
+ document.addEventListener('keydown', handleEvents);
215
+ document.addEventListener('mousedown', handleEvents);
216
+ return () => {
217
+ document.removeEventListener('keydown', handleEvents);
218
+ document.removeEventListener('mousedown', handleEvents);
219
+ };
220
+ }, [showMenu, showIconPicker]);
221
+
222
+ const children = childrenMap[node.id] || [];
223
+ const isSelected = selectedIds.includes(node.id);
224
+ const isActive = activeFileId === node.id;
225
+
226
+ const handleClick = (e: any) => {
227
+ e.stopPropagation();
228
+ if (node.type === 'folder') {
229
+ setIsExpanded(!isExpanded);
230
+ }
231
+ toggleSelect(node.id, e.ctrlKey || e.metaKey || e.shiftKey);
232
+ };
233
+
234
+ const handleRename = async () => {
235
+ if (editName.trim() !== '' && editName !== node.name) {
236
+ await renameNode(node.id, editName);
237
+ }
238
+ setIsEditing(false);
239
+ };
240
+
241
+ const handleMenuAction = async (action: string, e: any) => {
242
+ e.stopPropagation();
243
+ setShowMenu(false);
244
+
245
+ switch (action) {
246
+ case 'addFile':
247
+ setIsExpanded(true);
248
+ await createNode('New file', 'file', node.id);
249
+ break;
250
+ case 'addFolder':
251
+ setIsExpanded(true);
252
+ await createNode('New folder', 'folder', node.id);
253
+ break;
254
+ case 'rename':
255
+ setIsEditing(true);
256
+ break;
257
+ case 'duplicate':
258
+ await duplicateNode(node.id);
259
+ break;
260
+ case 'delete':
261
+ await deleteNode(node.id);
262
+ break;
263
+ case 'changeIcon':
264
+ setShowIconPicker(true);
265
+ break;
266
+ case 'copyContents':
267
+ const text = copyNodeContents(node.id);
268
+ navigator.clipboard.writeText(text);
269
+ break;
270
+ }
271
+ await loadFiles();
272
+ };
273
+
274
+ return (
275
+ <div
276
+ ref={(nodeEl) => {
277
+ setNodeRef(nodeEl);
278
+ (containerRef as any).current = nodeEl;
279
+ }}
280
+ className="tree-item-wrapper"
281
+ style={{ ...style, display: 'flex', flexDirection: 'column' }}
282
+ {...attributes}
283
+ >
284
+ <div
285
+ className={`tree-item ${isSelected ? 'selected' : ''} ${isActive ? 'active' : ''}`}
286
+ style={{
287
+ paddingLeft: `${16 + level * 12}px`,
288
+ display: 'flex',
289
+ alignItems: 'center',
290
+ paddingTop: '4px',
291
+ paddingBottom: '4px',
292
+ paddingRight: '12px',
293
+ cursor: 'pointer',
294
+ position: 'relative',
295
+ transition: 'all 0.2s ease',
296
+ backgroundColor: isActive ? 'rgba(0,0,0,0.04)' : isSelected ? 'rgba(0,0,0,0.02)' : 'transparent',
297
+ borderLeft: isActive ? '2px solid var(--accent-color)' : '2px solid transparent',
298
+ }}
299
+ onClick={handleClick}
300
+ >
301
+ <div
302
+ className="drag-handle"
303
+ {...listeners}
304
+ style={{ cursor: 'grab', opacity: 0.2, marginRight: 4, display: 'flex' }}
305
+ >
306
+ <DragDropVerticalIcon size={14} />
307
+ </div>
308
+
309
+ {node.type === 'folder' && (
310
+ <div style={{ marginRight: 4, display: 'flex', opacity: 0.4 }}>
311
+ {isExpanded ? <ArrowDown01Icon size={12} /> : <ArrowRight01Icon size={12} />}
312
+ </div>
313
+ )}
314
+
315
+ <div style={{ marginRight: 8, display: 'flex', color: node.color ? node.color : (isActive ? 'var(--text-primary)' : 'var(--text-secondary)') }}>
316
+ {node.icon && (HugeIcons as any)[node.icon] ? (
317
+ (() => {
318
+ const CustomIcon = (HugeIcons as any)[node.icon];
319
+ return <CustomIcon size={16} />;
320
+ })()
321
+ ) : (
322
+ node.type === 'folder' ? <Folder01Icon size={16} /> : <File01Icon size={16} />
323
+ )}
324
+ </div>
325
+
326
+ {isEditing ? (
327
+ <input
328
+ autoFocus
329
+ value={editName}
330
+ onChange={e => setEditName(e.target.value)}
331
+ onBlur={handleRename}
332
+ onKeyDown={e => { if (e.key === 'Enter') handleRename(); }}
333
+ style={{
334
+ border: 'none',
335
+ outline: 'none',
336
+ background: 'rgba(0,0,0,0.03)',
337
+ flex: 1,
338
+ fontFamily: 'inherit',
339
+ fontSize: '13px',
340
+ padding: '2px 4px',
341
+ borderRadius: '2px'
342
+ }}
343
+ />
344
+ ) : (
345
+ <span style={{
346
+ flex: 1,
347
+ fontSize: '13px',
348
+ userSelect: 'none',
349
+ whiteSpace: 'nowrap',
350
+ overflow: 'hidden',
351
+ textOverflow: 'ellipsis',
352
+ opacity: isActive ? 1 : 0.8
353
+ }}>
354
+ {node.name}
355
+ </span>
356
+ )}
357
+
358
+ <div className="item-actions" style={{ display: 'flex', alignItems: 'center', gap: '4px' }}>
359
+ <button
360
+ className="more-btn"
361
+ onClick={(e: any) => { e.stopPropagation(); setShowMenu(!showMenu); }}
362
+ style={{ padding: '4px', opacity: 0, transition: 'opacity 0.2s ease' }}
363
+ >
364
+ <MoreVerticalIcon size={14} />
365
+ </button>
366
+ </div>
367
+
368
+ {showMenu && (
369
+ <div className="context-menu" style={{
370
+ position: 'absolute', right: 8, top: 28, zIndex: 100,
371
+ background: 'var(--bg-panel)', border: '1px solid var(--border-color)',
372
+ borderRadius: '6px', boxShadow: '0 10px 25px rgba(0,0,0,0.1)',
373
+ display: 'flex', flexDirection: 'column', minWidth: 140, padding: 4
374
+ }}>
375
+ {node.type === 'folder' && <MenuButton onClick={(e: any) => handleMenuAction('addFile', e)}>New File</MenuButton>}
376
+ {node.type === 'folder' && <MenuButton onClick={(e: any) => handleMenuAction('addFolder', e)}>New Folder</MenuButton>}
377
+ <MenuButton onClick={(e: any) => handleMenuAction('rename', e)}>Rename</MenuButton>
378
+ <MenuButton onClick={(e: any) => handleMenuAction('changeIcon', e)}>Change Icon</MenuButton>
379
+ <MenuButton onClick={(e: any) => handleMenuAction('duplicate', e)}>Duplicate</MenuButton>
380
+ <MenuButton onClick={(e: any) => handleMenuAction('copyContents', e)}>Copy Contents</MenuButton>
381
+ <MenuButton onClick={(e: any) => handleMenuAction('delete', e)} danger>Delete</MenuButton>
382
+ </div>
383
+ )}
384
+ </div>
385
+
386
+ {node.type === 'folder' && isExpanded && children.length > 0 && (
387
+ <div className="tree-children" style={{ borderLeft: '1px solid rgba(0,0,0,0.03)', marginLeft: `${18 + level * 12}px` }}>
388
+ <SortableContext
389
+ items={children.map(c => c.id)}
390
+ strategy={verticalListSortingStrategy}
391
+ >
392
+ {children.map(child => (
393
+ <SidebarItem
394
+ key={child.id}
395
+ node={child}
396
+ level={level + 1}
397
+ childrenMap={childrenMap}
398
+ />
399
+ ))}
400
+ </SortableContext>
401
+ </div>
402
+ )}
403
+
404
+ {node.type === 'folder' && isExpanded && children.length === 0 && (
405
+ <div className="tree-children" style={{ borderLeft: '1px solid rgba(0,0,0,0.03)', marginLeft: `${18 + level * 12}px` }}>
406
+ <SortableContext
407
+ items={[`empty-${node.id}`]}
408
+ strategy={verticalListSortingStrategy}
409
+ >
410
+ <EmptyDropZone id={`empty-${node.id}`} />
411
+ </SortableContext>
412
+ </div>
413
+ )}
414
+
415
+ {showIconPicker && (
416
+ <IconPicker
417
+ onSelect={async (iconName, color) => {
418
+ await setNodeIcon(node.id, iconName);
419
+ if (color) {
420
+ await setNodeColor(node.id, color);
421
+ }
422
+ }}
423
+ onClose={() => setShowIconPicker(false)}
424
+ />
425
+ )}
426
+ </div>
427
+ );
428
+ }
429
+
430
+ function EmptyDropZone({ id }: { id: string }) {
431
+ const { setNodeRef } = useSortable({ id });
432
+ return (
433
+ <div
434
+ ref={setNodeRef}
435
+ style={{ padding: '4px 16px', fontSize: '11px', opacity: 0.4, fontStyle: 'italic', display: 'flex', alignItems: 'center', height: '24px' }}
436
+ >
437
+ Drop files here...
438
+ </div>
439
+ );
440
+ }
441
+
442
+ function MenuButton({ children, onClick, danger }: { children: any, onClick: any, danger?: boolean }) {
443
+ return (
444
+ <button
445
+ onClick={onClick}
446
+ style={{
447
+ padding: '6px 10px', textAlign: 'left', fontSize: '12px',
448
+ borderRadius: '4px', color: danger ? '#ff4d4f' : 'inherit',
449
+ transition: 'background 0.2s ease',
450
+ width: '100%'
451
+ }}
452
+ onMouseEnter={e => e.currentTarget.style.background = 'rgba(0,0,0,0.03)'}
453
+ onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
454
+ >
455
+ {children}
456
+ </button>
457
+ );
458
+ }
src/index.css ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ * {
2
+ box-sizing: border-box;
3
+ margin: 0;
4
+ padding: 0;
5
+ border-radius: 2px !important; /* Specification: Extremely-less-curved edges */
6
+ }
7
+
8
+ :root {
9
+ --bg-color: #f7f7f7;
10
+ --bg-panel: #ffffff;
11
+ --text-primary: #111111;
12
+ --text-secondary: #666666;
13
+ --border-color: #eeeeee;
14
+ --accent-color: #2e6ff2;
15
+ --font-ibm-plex: 'IBM Plex Mono', monospace;
16
+ --font-claude-sans: 'Inter', system-ui, sans-serif;
17
+ --font-wix-display: 'Wix Madefor Display', sans-serif;
18
+ --font-courier-new: 'Courier New', Courier, monospace;
19
+
20
+ --radius-sm: 2px;
21
+ --radius-md: 2px;
22
+
23
+ --bg-opacity: 0.15;
24
+ --fg-opacity: 1;
25
+
26
+ --transition-smooth: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
27
+ }
28
+
29
+ html, body {
30
+ height: 100%;
31
+ width: 100%;
32
+ }
33
+
34
+ body {
35
+ background-color: var(--bg-color);
36
+ color: var(--text-primary);
37
+ font-family: var(--font-ibm-plex);
38
+ overflow: hidden; /* App takes full screen */
39
+ }
40
+
41
+ /* Typography Classes */
42
+ .font-ibm-plex-mono { font-family: var(--font-ibm-plex); }
43
+ .font-claudesans { font-family: var(--font-claude-sans); }
44
+ .font-wixmadefordisplay { font-family: var(--font-wix-display); }
45
+ .font-couriernew { font-family: var(--font-courier-new); }
46
+
47
+ /* Layout Shell */
48
+ .app-container {
49
+ display: flex;
50
+ height: 100vh;
51
+ width: 100vw;
52
+ position: relative;
53
+ overflow: hidden;
54
+ }
55
+
56
+ .app-background {
57
+ position: absolute;
58
+ top: 0; left: 0; right: 0; bottom: 0;
59
+ background-size: cover;
60
+ background-position: center;
61
+ z-index: -1;
62
+ opacity: var(--bg-opacity);
63
+ }
64
+
65
+ .mini-sidebar {
66
+ width: 48px;
67
+ background-color: var(--bg-panel);
68
+ border-right: 1px solid var(--border-color);
69
+ display: flex;
70
+ flex-direction: column;
71
+ align-items: center;
72
+ padding: 12px 0;
73
+ gap: 16px;
74
+ z-index: 10;
75
+ }
76
+
77
+ .sidebar-panel {
78
+ width: 260px;
79
+ background-color: rgba(255, 255, 255, 0.85); /* Glassmorphism leaning */
80
+ backdrop-filter: blur(10px);
81
+ border-right: 1px solid var(--border-color);
82
+ display: flex;
83
+ flex-direction: column;
84
+ z-index: 10;
85
+ transition: width 0.3s ease;
86
+ }
87
+
88
+ .sidebar-header {
89
+ height: 48px;
90
+ padding: 0 16px;
91
+ display: flex;
92
+ align-items: center;
93
+ border-bottom: 1px solid var(--border-color);
94
+ font-weight: 500;
95
+ font-size: 14px;
96
+ }
97
+
98
+ .editor-main {
99
+ flex: 1;
100
+ background-color: transparent;
101
+ position: relative;
102
+ display: flex;
103
+ flex-direction: column;
104
+ overflow: hidden;
105
+ }
106
+
107
+ .editor-placeholder {
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ height: 100%;
112
+ color: var(--text-secondary);
113
+ }
114
+
115
+ /* Reusable buttons component logic will be added here */
116
+ button {
117
+ all: unset;
118
+ cursor: pointer;
119
+ border-radius: var(--radius-sm);
120
+ transition: var(--transition-smooth);
121
+ }
122
+
123
+ /* Tree View Styling UPDATED */
124
+ .tree-view {
125
+ padding-bottom: 20px;
126
+ }
127
+
128
+ .tree-children {
129
+ position: relative;
130
+ transition: all 0.3s ease;
131
+ }
132
+
133
+ /* Vertical line for the branch refine */
134
+ .tree-children::before {
135
+ content: "";
136
+ position: absolute;
137
+ top: 0;
138
+ left: 0;
139
+ bottom: 0;
140
+ width: 1px;
141
+ background-color: rgba(0,0,0,0.03);
142
+ }
143
+
144
+ .tree-item-wrapper {
145
+ position: relative;
146
+ }
147
+
148
+ .tree-item {
149
+ transition: background-color 0.15s ease, border-left 0.1s ease;
150
+ }
151
+
152
+ .tree-item:hover {
153
+ background-color: rgba(0, 0, 0, 0.02);
154
+ }
155
+
156
+ .tree-item:hover .more-btn {
157
+ opacity: 0.6 !important;
158
+ }
159
+
160
+ .tree-item .more-btn:hover {
161
+ opacity: 1 !important;
162
+ background-color: rgba(0, 0, 0, 0.05);
163
+ }
164
+
165
+ .tree-item.active {
166
+ background-color: rgba(0, 0, 0, 0.04) !important;
167
+ font-weight: 500;
168
+ }
169
+
170
+ .btn-icon-sm {
171
+ all: unset;
172
+ cursor: pointer;
173
+ padding: 4px;
174
+ border-radius: 4px;
175
+ display: flex;
176
+ align-items: center;
177
+ justify-content: center;
178
+ transition: all 0.2s ease;
179
+ color: var(--text-secondary);
180
+ opacity: 0.6;
181
+ }
182
+
183
+ .btn-icon-sm:hover {
184
+ background-color: rgba(0, 0, 0, 0.05);
185
+ opacity: 1;
186
+ color: var(--text-primary);
187
+ }
188
+
189
+ .context-menu button {
190
+ all: unset;
191
+ cursor: pointer;
192
+ font-family: var(--font-ibm-plex);
193
+ }
194
+
195
+ @keyframes spin {
196
+ from { transform: rotate(0deg); }
197
+ to { transform: rotate(360deg); }
198
+ }
199
+ .spin {
200
+ animation: spin 1s linear infinite;
201
+ }
202
+
203
+ .pixilize {
204
+ filter: blur(5px) grayscale(0.5);
205
+ transition: filter 0.3s ease;
206
+ user-select: none;
207
+ }
208
+ .pixilize:hover {
209
+ filter: none;
210
+ }
211
+
212
+ .ContentEditable {
213
+ flex: 1;
214
+ outline: none;
215
+ padding: 0px 24px 100px 24px;
216
+ font-size: 14px;
217
+ line-height: 1.5;
218
+ color: var(--text-primary);
219
+ tab-size: 4;
220
+ white-space: pre-wrap;
221
+ word-break: break-word;
222
+ overflow-wrap: break-word;
223
+ }
224
+
225
+ .editor-paragraph {
226
+ margin: 0;
227
+ position: relative;
228
+ }
229
+
230
+ .comment-bubble {
231
+ background: var(--bg-panel);
232
+ border: 1px solid var(--border-color);
233
+ border-radius: 4px;
234
+ padding: 8px 12px;
235
+ font-size: 11px;
236
+ box-shadow: 0 4px 12px rgba(0,0,0,0.05);
237
+ margin-bottom: 8px;
238
+ color: var(--text-primary);
239
+ max-width: 250px;
240
+ line-height: 1.4;
241
+ }
242
+
243
+ .comment-toggle {
244
+ opacity: 0.1;
245
+ transition: opacity 0.2s ease;
246
+ }
247
+ .tree-item-wrapper:hover .comment-toggle,
248
+ .line-numbers-container:hover .comment-toggle,
249
+ .comment-toggle.active {
250
+ opacity: 1;
251
+ }
252
+
253
+ .editor-text-bold { font-weight: bold; }
254
+ .editor-text-italic { font-style: italic; }
255
+ .editor-text-strikethrough { text-decoration: line-through; }
256
+ .editor-text-underline { text-decoration: underline; }
257
+
258
+ @keyframes fadeInSlide {
259
+ from { opacity: 0; transform: translateY(-5px); }
260
+ to { opacity: 1; transform: translateY(0); }
261
+ }
src/lib/db.ts ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { openDB, DBSchema, IDBPDatabase } from 'idb';
2
+
3
+ export interface FileNode {
4
+ id: string;
5
+ name: string;
6
+ type: 'file' | 'folder';
7
+ parentId: string | null;
8
+ content?: string; // Lexical JSON string or plain text
9
+ icon?: string;
10
+ color?: string;
11
+ orderIndex: number;
12
+ comments?: Record<string, string>; // Line-based comments: { "line-1": "comment text" }
13
+ }
14
+
15
+ export interface SettingsType {
16
+ typography: 'IBM Plex Mono' | 'ClaudeSans' | 'WixMadeForDisplay' | 'CourierNew';
17
+ theme: string;
18
+ highlighters: HighlighterRule[];
19
+ bgOpacity: number;
20
+ fgOpacity: number;
21
+ }
22
+
23
+ export interface HighlighterRule {
24
+ id: string;
25
+ openSymbol: string;
26
+ closeSymbol: string;
27
+ color: string;
28
+ baseOpacity: number; // 0.1 for 10%
29
+ stackMode: 'smaller-lighter' | 'larger-lighter';
30
+ }
31
+
32
+ export const DEFAULT_HIGHLIGHTERS: HighlighterRule[] = [
33
+ { id: '1', openSymbol: '(', closeSymbol: ')', color: '#ffb3ba', baseOpacity: 0.6, stackMode: 'larger-lighter' },
34
+ { id: '2', openSymbol: '[', closeSymbol: ']', color: '#baffc9', baseOpacity: 0.6, stackMode: 'larger-lighter' },
35
+ { id: '3', openSymbol: '{', closeSymbol: '}', color: '#ffdfba', baseOpacity: 0.6, stackMode: 'larger-lighter' },
36
+ { id: '4', openSymbol: '<', closeSymbol: '>', color: '#bae1ff', baseOpacity: 0.6, stackMode: 'larger-lighter' },
37
+ { id: '5', openSymbol: "'", closeSymbol: "'", color: '#ffffba', baseOpacity: 0.6, stackMode: 'larger-lighter' },
38
+ { id: '6', openSymbol: '"', closeSymbol: '"', color: '#e0bbff', baseOpacity: 0.6, stackMode: 'larger-lighter' },
39
+ { id: '7', openSymbol: '`', closeSymbol: '`', color: '#c7f9cc', baseOpacity: 0.6, stackMode: 'larger-lighter' },
40
+ { id: '8', openSymbol: '*', closeSymbol: '*', color: '#f9dcc4', baseOpacity: 0.6, stackMode: 'larger-lighter' },
41
+ { id: '9', openSymbol: '**', closeSymbol: '**', color: '#f9bcc4', baseOpacity: 0.6, stackMode: 'larger-lighter' },
42
+ { id: '10', openSymbol: '~~', closeSymbol: '~~', color: '#d9ed92', baseOpacity: 0.6, stackMode: 'larger-lighter' },
43
+ { id: '11', openSymbol: '$$', closeSymbol: '$$', color: '#99d98c', baseOpacity: 0.6, stackMode: 'larger-lighter' },
44
+ ];
45
+
46
+ export const DEFAULT_SETTINGS: SettingsType = {
47
+ typography: 'IBM Plex Mono',
48
+ theme: 'minimal-light',
49
+ highlighters: DEFAULT_HIGHLIGHTERS,
50
+ bgOpacity: 0.15,
51
+ fgOpacity: 1.0,
52
+ };
53
+
54
+ interface EditorDB extends DBSchema {
55
+ files: {
56
+ key: string;
57
+ value: FileNode;
58
+ indexes: { 'by-parent': string };
59
+ };
60
+ config: {
61
+ key: string;
62
+ value: any;
63
+ };
64
+ images: {
65
+ key: string;
66
+ value: { id: string; blob: Blob | string };
67
+ };
68
+ }
69
+
70
+ let dbPromise: Promise<IDBPDatabase<EditorDB>>;
71
+
72
+ export function initDB() {
73
+ if (!dbPromise) {
74
+ dbPromise = openDB<EditorDB>('HybridEditorDB', 1, {
75
+ upgrade(db) {
76
+ const fileStore = db.createObjectStore('files', { keyPath: 'id' });
77
+ fileStore.createIndex('by-parent', 'parentId');
78
+
79
+ db.createObjectStore('config');
80
+ db.createObjectStore('images', { keyPath: 'id' });
81
+ },
82
+ });
83
+ }
84
+ return dbPromise;
85
+ }
86
+
87
+ export async function getFiles(): Promise<FileNode[]> {
88
+ const db = await initDB();
89
+ return db.getAll('files');
90
+ }
91
+
92
+ export async function saveFile(file: FileNode): Promise<string> {
93
+ const db = await initDB();
94
+ await db.put('files', file);
95
+ return file.id;
96
+ }
97
+
98
+ export async function deleteFile(id: string): Promise<void> {
99
+ const db = await initDB();
100
+ await db.delete('files', id);
101
+ }
102
+
103
+ export async function getSettings(): Promise<SettingsType> {
104
+ const db = await initDB();
105
+ const settings = await db.get('config', 'settings');
106
+ return { ...DEFAULT_SETTINGS, ...(settings || {}) };
107
+ }
108
+
109
+ export async function saveSettings(settings: SettingsType): Promise<void> {
110
+ const db = await initDB();
111
+ await db.put('config', settings, 'settings');
112
+ }
113
+
114
+ export async function getBackgroundImage(): Promise<Blob | string | undefined> {
115
+ const db = await initDB();
116
+ const res = await db.get('images', 'background');
117
+ return res?.blob;
118
+ }
119
+
120
+ export async function saveBackgroundImage(blob: Blob | string): Promise<void> {
121
+ const db = await initDB();
122
+ await db.put('images', { id: 'background', blob });
123
+ }
124
+
125
+ export async function resetBackgroundImage(): Promise<void> {
126
+ const db = await initDB();
127
+ await db.delete('images', 'background');
128
+ }
129
+
130
+ /**
131
+ * EXPORT/IMPORT Logic for local JSON persistence
132
+ */
133
+
134
+ export interface WorkspaceExport {
135
+ files: FileNode[];
136
+ settings: SettingsType;
137
+ lastUpdated: string;
138
+ }
139
+
140
+ export async function exportFullWorkspace(): Promise<WorkspaceExport> {
141
+ const files = await getFiles();
142
+ const settings = await getSettings();
143
+ return {
144
+ files,
145
+ settings,
146
+ lastUpdated: new Date().toISOString()
147
+ };
148
+ }
149
+
150
+ export async function importWorkspace(data: WorkspaceExport): Promise<void> {
151
+ const db = await initDB();
152
+
153
+ // Clear existing (optional, but safer for full recovery)
154
+ await db.clear('files');
155
+
156
+ const tx = db.transaction(['files', 'config'], 'readwrite');
157
+ for (const file of data.files) {
158
+ await tx.objectStore('files').put(file);
159
+ }
160
+ await tx.objectStore('config').put(data.settings, 'settings');
161
+ await tx.done;
162
+ }
src/lib/persistence.ts ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { exportFullWorkspace, importWorkspace, WorkspaceExport } from './db';
2
+
3
+ /**
4
+ * Persistence Bridge
5
+ *
6
+ * In a standard web environment, we can't directly write to the filesystem.
7
+ * However, we can trigger a download or, in this agentic environment,
8
+ * provide a hook for the agent to sync the state.
9
+ */
10
+
11
+ export async function syncToJSON(): Promise<WorkspaceExport> {
12
+ const data = await exportFullWorkspace();
13
+ console.log('SYNC_REQUIRED', JSON.stringify(data));
14
+ // We log this so the agent/system can pick it up if watching logs,
15
+ // or the user can copy-paste.
16
+ return data;
17
+ }
18
+
19
+ export async function loadFromJSON(data: WorkspaceExport): Promise<void> {
20
+ await importWorkspace(data);
21
+ }
src/main.tsx ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom/client'
3
+ import App from './App.tsx'
4
+ import './index.css'
5
+
6
+ ReactDOM.createRoot(document.getElementById('root')!).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>,
10
+ )
src/plugins/AutoHighlighterPlugin.tsx ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useEffect } from 'react';
2
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
3
+ import { $getRoot, $isTextNode, $isElementNode, TextNode } from 'lexical';
4
+ import { getSettings, HighlighterRule } from '../lib/db';
5
+
6
+ const CONJUNCTIONS = ['and', 'or', 'but', 'yet', 'so', 'in addition', 'therefore'];
7
+
8
+ function setNodeBackgroundColor(node: TextNode, bg: string | undefined): boolean {
9
+ let style = node.getStyle() || '';
10
+ style = style.replace(/background(?:-color)?:\s*[^;]+;?/g, '').trim();
11
+ if (bg) {
12
+ const prop = bg.includes('gradient') ? 'background' : 'background-color';
13
+ style = style + (style && !style.endsWith(';') ? ';' : '') + `${prop}: ${bg};`;
14
+ }
15
+ if (node.getStyle() !== style) {
16
+ node.setStyle(style);
17
+ return true;
18
+ }
19
+ return false;
20
+ }
21
+
22
+ function calculateBgColor(rule: HighlighterRule, depth: number): string | undefined {
23
+ if (depth <= 0) return undefined;
24
+ const hex = rule.color.replace('#', '');
25
+ const r = parseInt(hex.substring(0, 2), 16) || 255;
26
+ const g = parseInt(hex.substring(2, 4), 16) || 255;
27
+ const b = parseInt(hex.substring(4, 6), 16) || 255;
28
+
29
+ let opacity = rule.baseOpacity || 0.6;
30
+ if (rule.stackMode === 'larger-lighter') {
31
+ // larger means outer. depth=1 is outer. Outer is lighter. So as depth increases, opacity increases (darker).
32
+ opacity = Math.min(0.95, opacity + ((depth - 1) * 0.15));
33
+ } else {
34
+ // smaller means inner. Outer is darker. As depth increases, opacity decreases (lighter).
35
+ opacity = Math.max(0.05, opacity - ((depth - 1) * 0.15));
36
+ }
37
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
38
+ }
39
+
40
+ export default function AutoHighlighterPlugin() {
41
+ const [editor] = useLexicalComposerContext();
42
+
43
+ useEffect(() => {
44
+ let rules: HighlighterRule[] = [];
45
+ getSettings().then(s => { rules = s.highlighters || []; });
46
+
47
+ const removeUpdateListener = editor.registerUpdateListener(({ dirtyElements, dirtyLeaves }) => {
48
+ if (dirtyElements.size === 0 && dirtyLeaves.size === 0) return;
49
+
50
+ editor.update(() => {
51
+ const root = $getRoot();
52
+ const firstChild = root.getFirstChild();
53
+ if (!firstChild) return;
54
+
55
+ const blocks = root.getChildren();
56
+
57
+ for (const block of blocks) {
58
+ if (!$isElementNode(block)) continue;
59
+
60
+ const text = block.getTextContent();
61
+ if (!text) {
62
+ // ensure no leftover background styles in empty blocks
63
+ block.getChildren().forEach(c => {
64
+ if ($isTextNode(c)) setNodeBackgroundColor(c, undefined);
65
+ });
66
+ continue;
67
+ }
68
+
69
+ const sortedRules = [...rules].sort((a, b) => b.openSymbol.length - a.openSymbol.length);
70
+ const tokens: any[] = [];
71
+
72
+ // 1. Lexer
73
+ for (let i = 0; i < text.length; i++) {
74
+ let matchedConj = false;
75
+ for (const c of CONJUNCTIONS) {
76
+ if (text.startsWith(c, i)) {
77
+ const before = i === 0 || !/[a-zA-Z]/.test(text[i-1]);
78
+ const after = i + c.length >= text.length || !/[a-zA-Z]/.test(text[i+c.length]);
79
+ if (before && after) {
80
+ tokens.push({ index: i, length: c.length, type: 'conj' });
81
+ i += c.length - 1;
82
+ matchedConj = true;
83
+ break;
84
+ }
85
+ }
86
+ }
87
+ if (matchedConj) continue;
88
+
89
+ for (const rule of sortedRules) {
90
+ const isOpenSame = rule.openSymbol === rule.closeSymbol;
91
+ if (text.startsWith(rule.closeSymbol, i)) { // Always check close first
92
+ tokens.push({ index: i, length: rule.closeSymbol.length, type: isOpenSame ? 'same' : 'close', rule });
93
+ i += rule.closeSymbol.length - 1;
94
+ break;
95
+ } else if (text.startsWith(rule.openSymbol, i)) {
96
+ tokens.push({ index: i, length: rule.openSymbol.length, type: 'open', rule });
97
+ i += rule.openSymbol.length - 1;
98
+ break;
99
+ }
100
+ }
101
+ }
102
+
103
+ // 2. Parser
104
+ const pairs: { start: number, end: number, rule: HighlighterRule }[] = [];
105
+ const stack: { token: any, rule: HighlighterRule }[] = [];
106
+
107
+ for (const tk of tokens) {
108
+ if (tk.type === 'conj') continue; // handled later
109
+
110
+ if (tk.type === 'open') {
111
+ stack.push({ token: tk, rule: tk.rule });
112
+ } else if (tk.type === 'close') {
113
+ let foundIdx = -1;
114
+ for (let j = stack.length - 1; j >= 0; j--) {
115
+ if (stack[j].rule.id === tk.rule.id && stack[j].token.type === 'open') {
116
+ foundIdx = j;
117
+ break;
118
+ }
119
+ }
120
+ if (foundIdx !== -1) {
121
+ const openTk = stack.splice(foundIdx, 1)[0];
122
+ pairs.push({ start: openTk.token.index, end: tk.index + tk.length, rule: openTk.rule });
123
+ }
124
+ } else if (tk.type === 'same') {
125
+ let foundIdx = -1;
126
+ for (let j = stack.length - 1; j >= 0; j--) {
127
+ if (stack[j].rule.id === tk.rule.id && stack[j].token.type === 'same') {
128
+ foundIdx = j;
129
+ break;
130
+ }
131
+ }
132
+ if (foundIdx !== -1) {
133
+ const openTk = stack.splice(foundIdx, 1)[0];
134
+ pairs.push({ start: openTk.token.index, end: tk.index + tk.length, rule: openTk.rule });
135
+ } else {
136
+ stack.push({ token: tk, rule: tk.rule });
137
+ }
138
+ }
139
+ }
140
+
141
+ const charColors = new Array(text.length).fill(undefined);
142
+
143
+ for (let i = 0; i < text.length; i++) {
144
+ let activePairs = [];
145
+ for (const p of pairs) {
146
+ if (i >= p.start && i < p.end) {
147
+ activePairs.push(p);
148
+ }
149
+ }
150
+ if (activePairs.length > 0) {
151
+ // Outermost first (longest span)
152
+ activePairs.sort((a, b) => (b.end - b.start) - (a.end - a.start));
153
+
154
+ if (activePairs.length === 1) {
155
+ charColors[i] = calculateBgColor(activePairs[0].rule, 1);
156
+ } else {
157
+ const gradients: string[] = [];
158
+ for (let d = activePairs.length - 1; d >= 0; d--) {
159
+ const base = calculateBgColor(activePairs[d].rule, 1);
160
+ gradients.push(`linear-gradient(${base}, ${base})`);
161
+ }
162
+ charColors[i] = gradients.join(', ');
163
+ }
164
+ }
165
+ }
166
+
167
+ // Conjunction override
168
+ for (let i = 0; i < text.length; i++) {
169
+ for (const c of CONJUNCTIONS) {
170
+ if (text.startsWith(c, i)) {
171
+ const before = i === 0 || !/[a-zA-Z]/.test(text[i-1]);
172
+ const after = i + c.length >= text.length || !/[a-zA-Z]/.test(text[i+c.length]);
173
+ if (before && after) {
174
+ const color = 'rgba(234, 179, 8, 0.4)';
175
+ for(let j=0; j<c.length; j++) charColors[i+j] = color;
176
+ i += c.length - 1;
177
+ break;
178
+ }
179
+ }
180
+ }
181
+ }
182
+
183
+ // 3. Modulator
184
+ // Cleanly apply regions to Lexical DOM
185
+ let currentOffset = 0;
186
+ let child = block.getFirstChild();
187
+
188
+ while (child !== null) {
189
+ if (!$isTextNode(child)) {
190
+ currentOffset += child.getTextContent().length;
191
+ child = child.getNextSibling();
192
+ continue;
193
+ }
194
+
195
+ const textContent = child.getTextContent();
196
+ const len = textContent.length;
197
+ if (len === 0) {
198
+ child = child.getNextSibling();
199
+ continue;
200
+ }
201
+
202
+ let targetBg = charColors[currentOffset];
203
+ let splitNeededOffset = -1;
204
+
205
+ for (let c = 1; c < len; c++) {
206
+ if (charColors[currentOffset + c] !== targetBg) {
207
+ splitNeededOffset = c;
208
+ break;
209
+ }
210
+ }
211
+
212
+ let style = child.getStyle() || '';
213
+ let currentBgMatch = style.match(/background(?:-color)?:\s*([^;]+)/);
214
+ let currentBg = currentBgMatch ? currentBgMatch[1].trim() : undefined;
215
+ let normalizedCurrent = currentBg ? currentBg.replace(/\s+/g, '') : undefined;
216
+ let normalizedTarget = targetBg ? targetBg.replace(/\s+/g, '') : undefined;
217
+
218
+ if (splitNeededOffset !== -1) {
219
+ const [, rightNode] = child.splitText(splitNeededOffset);
220
+ if (normalizedCurrent !== normalizedTarget) {
221
+ setNodeBackgroundColor(child, targetBg);
222
+ }
223
+ currentOffset += splitNeededOffset;
224
+ child = rightNode;
225
+ } else {
226
+ if (normalizedCurrent !== normalizedTarget) {
227
+ setNodeBackgroundColor(child, targetBg);
228
+ }
229
+ currentOffset += len;
230
+
231
+ // Optimisation: Merge adjacent nodes with the same formats & styles to prevent Lexical fragmentation
232
+ let next = child.getNextSibling();
233
+ if (next && $isTextNode(next) && next.getStyle() === child.getStyle() && next.getFormat() === child.getFormat()) {
234
+ child.setTextContent(child.getTextContent() + next.getTextContent());
235
+ next.remove();
236
+ // Don't advance offset, re-process this larger node on next pass if needed, or
237
+ // actually we know targetBg covers `len`, but what about the rest?
238
+ // It's safer to just let the overall update pass handle it or let Lexical normalize.
239
+ // Actually, Lexical internal text node normalization runs automatically if not prevented!
240
+ }
241
+ child = child.getNextSibling();
242
+ }
243
+ }
244
+ }
245
+ });
246
+ });
247
+
248
+ return removeUpdateListener;
249
+ }, [editor]);
250
+
251
+ return null;
252
+ }
src/stores/fileStore.ts ADDED
@@ -0,0 +1,327 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { create } from 'zustand';
2
+ import { v4 as uuidv4 } from 'uuid';
3
+ import { FileNode, getFiles, saveFile, deleteFile } from '../lib/db';
4
+ import { arrayMove } from '@dnd-kit/sortable';
5
+
6
+ interface FileStore {
7
+ files: FileNode[];
8
+ activeFileId: string | null;
9
+ selectedIds: string[];
10
+
11
+ loadFiles: () => Promise<void>;
12
+ setActiveFile: (id: string | null, skipHistory?: boolean) => void;
13
+ navigationHistory: string[];
14
+ historyIndex: number;
15
+ goBack: () => void;
16
+ goForward: () => void;
17
+ toggleSelect: (id: string, multi: boolean) => void;
18
+ clearSelection: () => void;
19
+
20
+ createNode: (name: string, type: 'file' | 'folder', parentId: string | null) => Promise<string>;
21
+ renameNode: (id: string, newName: string) => Promise<void>;
22
+ deleteNode: (id: string) => Promise<void>;
23
+ duplicateNode: (id: string) => Promise<void>;
24
+ updateFileContent: (id: string, content: string) => Promise<void>;
25
+ moveNode: (id: string, newParentId: string | null) => Promise<void>;
26
+ reorderNodes: (activeId: string, overId: string, newParentId: string | null) => Promise<void>;
27
+ setNodeIcon: (id: string, icon: string) => Promise<void>;
28
+ setNodeColor: (id: string, color: string) => Promise<void>;
29
+ setComment: (fileId: string, lineId: string, comment: string) => Promise<void>;
30
+ copySelectedContents: () => string;
31
+ copyNodeContents: (id: string) => string;
32
+ }
33
+
34
+ export const useFileStore = create<FileStore>((set, get) => ({
35
+ files: [],
36
+ activeFileId: null,
37
+ selectedIds: [],
38
+ navigationHistory: [],
39
+ historyIndex: -1,
40
+
41
+ loadFiles: async () => {
42
+ const data = await getFiles();
43
+ // Sort all files by orderIndex initially
44
+ const sorted = [...data].sort((a, b) => a.orderIndex - b.orderIndex);
45
+ set({ files: sorted });
46
+ },
47
+
48
+ setActiveFile: (id, skipHistory = false) => {
49
+ const { navigationHistory, historyIndex } = get();
50
+ if (id && !skipHistory) {
51
+ const newHistory = navigationHistory.slice(0, historyIndex + 1);
52
+ // Only push if it's different from current
53
+ if (newHistory[newHistory.length - 1] !== id) {
54
+ newHistory.push(id);
55
+ // Limit history to 50 items
56
+ if (newHistory.length > 50) newHistory.shift();
57
+ set({
58
+ activeFileId: id,
59
+ selectedIds: [id],
60
+ navigationHistory: newHistory,
61
+ historyIndex: newHistory.length - 1
62
+ });
63
+ return;
64
+ }
65
+ }
66
+ set({ activeFileId: id, selectedIds: id ? [id] : [] });
67
+ },
68
+
69
+ goBack: () => {
70
+ const { navigationHistory, historyIndex, setActiveFile } = get();
71
+ if (historyIndex > 0) {
72
+ const newIndex = historyIndex - 1;
73
+ set({ historyIndex: newIndex });
74
+ setActiveFile(navigationHistory[newIndex], true);
75
+ }
76
+ },
77
+
78
+ goForward: () => {
79
+ const { navigationHistory, historyIndex, setActiveFile } = get();
80
+ if (historyIndex < navigationHistory.length - 1) {
81
+ const newIndex = historyIndex + 1;
82
+ set({ historyIndex: newIndex });
83
+ setActiveFile(navigationHistory[newIndex], true);
84
+ }
85
+ },
86
+
87
+ toggleSelect: (id, multi) => {
88
+ const { selectedIds } = get();
89
+ if (multi) {
90
+ set({ selectedIds: selectedIds.includes(id)
91
+ ? selectedIds.filter(i => i !== id)
92
+ : [...selectedIds, id]
93
+ });
94
+ } else {
95
+ set({ selectedIds: [id], activeFileId: id });
96
+ }
97
+ },
98
+
99
+ clearSelection: () => set({ selectedIds: [] }),
100
+
101
+ createNode: async (name, type, parentId) => {
102
+ const { files } = get();
103
+ // Find max orderIndex in current parent
104
+ const peerIndices = files.filter(f => f.parentId === parentId).map(f => f.orderIndex);
105
+ const nextIndex = peerIndices.length > 0 ? Math.max(...peerIndices) + 1 : 0;
106
+
107
+ const newNode: FileNode = {
108
+ id: uuidv4(),
109
+ name,
110
+ type,
111
+ parentId,
112
+ content: type === 'file' ? '' : undefined,
113
+ orderIndex: nextIndex
114
+ };
115
+ await saveFile(newNode);
116
+ set(state => ({ files: [...state.files, newNode] }));
117
+ return newNode.id;
118
+ },
119
+
120
+ renameNode: async (id, newName) => {
121
+ const { files } = get();
122
+ const node = files.find(f => f.id === id);
123
+ if (!node) return;
124
+ const updated = { ...node, name: newName };
125
+ await saveFile(updated);
126
+ set(state => ({ files: state.files.map(f => f.id === id ? updated : f) }));
127
+ },
128
+
129
+ deleteNode: async (id) => {
130
+ const { files, activeFileId, selectedIds } = get();
131
+
132
+ // Recursive delete logic
133
+ const toDelete = new Set<string>();
134
+ const findChildren = (nodeId: string) => {
135
+ toDelete.add(nodeId);
136
+ files.forEach(f => {
137
+ if (f.parentId === nodeId) findChildren(f.id);
138
+ });
139
+ };
140
+ findChildren(id);
141
+
142
+ // DB delete
143
+ for (const delId of toDelete) {
144
+ await deleteFile(delId);
145
+ }
146
+
147
+ set(state => ({
148
+ files: state.files.filter(f => !toDelete.has(f.id)),
149
+ activeFileId: activeFileId && toDelete.has(activeFileId) ? null : state.activeFileId,
150
+ selectedIds: selectedIds.filter(sid => !toDelete.has(sid)),
151
+ }));
152
+ },
153
+
154
+ duplicateNode: async (id) => {
155
+ const { files, createNode } = get();
156
+ const node = files.find(f => f.id === id);
157
+ if (!node) return;
158
+ await createNode(`${node.name} (copy)`, node.type, node.parentId);
159
+ },
160
+
161
+ // Write queue for updating contents to prevent rapid IDB transaction crashes
162
+ updateFileContent: (() => {
163
+ let writeQueue = Promise.resolve();
164
+ return async (id: string, content: string) => {
165
+ writeQueue = writeQueue.then(async () => {
166
+ const { files } = get();
167
+ const node = files.find(f => f.id === id);
168
+ if (!node) return;
169
+ const updated = { ...node, content };
170
+ await saveFile(updated);
171
+ set(state => ({ files: state.files.map(f => f.id === id ? updated : f) }));
172
+ }).catch(console.error);
173
+ return writeQueue;
174
+ };
175
+ })(),
176
+
177
+ moveNode: async (id, newParentId) => {
178
+ const { files } = get();
179
+ const node = files.find(f => f.id === id);
180
+ if (!node) return;
181
+
182
+ // Auto-calculate new index at end of target parent
183
+ const peerIndices = files.filter(f => f.parentId === newParentId).map(f => f.orderIndex);
184
+ const nextIndex = peerIndices.length > 0 ? Math.max(...peerIndices) + 1 : 0;
185
+
186
+ const updated = { ...node, parentId: newParentId, orderIndex: nextIndex };
187
+ await saveFile(updated);
188
+ set(state => ({ files: state.files.map(f => f.id === id ? updated : f) }));
189
+ },
190
+
191
+ reorderNodes: async (activeId, overId, newParentId) => {
192
+ const { files } = get();
193
+ const activeNode = files.find(f => f.id === activeId);
194
+ if (!activeNode) return;
195
+
196
+ const peerNodes = files.filter(f => f.parentId === newParentId).sort((a,b) => a.orderIndex - b.orderIndex);
197
+ const oldIndex = peerNodes.findIndex(n => n.id === activeId);
198
+ const newIndex = peerNodes.findIndex(n => n.id === overId);
199
+
200
+ if (oldIndex !== -1 && newIndex !== -1) {
201
+ const newOrder = arrayMove(peerNodes, oldIndex, newIndex);
202
+ // Batch update all peer indices
203
+ const updates = newOrder.map((node, idx) => ({ ...node, orderIndex: idx, parentId: newParentId }));
204
+
205
+ for (const updated of updates) {
206
+ await saveFile(updated);
207
+ }
208
+
209
+ set(state => ({
210
+ files: state.files.map(f => {
211
+ const match = updates.find(u => u.id === f.id);
212
+ return match || f;
213
+ })
214
+ }));
215
+ } else if (activeNode.parentId !== newParentId) {
216
+ // Different parent move
217
+ await get().moveNode(activeId, newParentId);
218
+ }
219
+ },
220
+
221
+ copySelectedContents: () => {
222
+ const { files, selectedIds } = get();
223
+ const contents: string[] = [];
224
+
225
+ const addNodeContent = (id: string, depth = 0) => {
226
+ const node = files.find(f => f.id === id);
227
+ if (!node) return;
228
+
229
+ if (node.type === 'folder') {
230
+ files.filter(f => f.parentId === id)
231
+ .sort((a,b) => a.orderIndex - b.orderIndex)
232
+ .forEach(child => addNodeContent(child.id, depth + 1));
233
+ } else {
234
+ try {
235
+ const parsed = JSON.parse(node.content || '{}');
236
+ const extractText = (nodes: any[]): string => {
237
+ return nodes?.map(n => {
238
+ if (n.type === 'linebreak') return '\n';
239
+ if (n.children) return extractText(n.children) + (n.type === 'paragraph' ? '\n' : '');
240
+ return n.text || '';
241
+ }).join('') || '';
242
+ };
243
+ const plainText = extractText(parsed.root?.children || []);
244
+ const prefixed = plainText.split('\n').map(line => line.trim().length > 0 ? `— ${line.trim()}` : line).join('\n');
245
+ if (prefixed) contents.push(prefixed);
246
+ } catch {
247
+ if (node.content && node.content.trim().length > 0) {
248
+ const prefixed = node.content.split('\n').map(line => line.trim().length > 0 ? `— ${line.trim()}` : line).join('\n');
249
+ contents.push(prefixed);
250
+ }
251
+ }
252
+ }
253
+ };
254
+
255
+ selectedIds.forEach(id => addNodeContent(id));
256
+ return contents.join('\n');
257
+ },
258
+
259
+ copyNodeContents: (id) => {
260
+ const { files } = get();
261
+ const contents: string[] = [];
262
+
263
+ const addNodeContent = (nodeId: string, depth = 0) => {
264
+ const node = files.find(f => f.id === nodeId);
265
+ if (!node) return;
266
+
267
+ if (node.type === 'folder') {
268
+ files.filter(f => f.parentId === nodeId)
269
+ .sort((a,b) => a.orderIndex - b.orderIndex)
270
+ .forEach(child => addNodeContent(child.id, depth + 1));
271
+ } else {
272
+ try {
273
+ const parsed = JSON.parse(node.content || '{}');
274
+ const extractText = (nodes: any[]): string => {
275
+ return nodes?.map(n => {
276
+ if (n.type === 'linebreak') return '\n';
277
+ if (n.children) return extractText(n.children) + (n.type === 'paragraph' ? '\n' : '');
278
+ return n.text || '';
279
+ }).join('') || '';
280
+ };
281
+ const plainText = extractText(parsed.root?.children || []);
282
+ const prefixed = plainText.split('\n').map(line => line.trim().length > 0 ? `— ${line.trim()}` : line).join('\n');
283
+ if (prefixed) contents.push(prefixed);
284
+ } catch {
285
+ if (node.content && node.content.trim().length > 0) {
286
+ const prefixed = node.content.split('\n').map(line => line.trim().length > 0 ? `— ${line.trim()}` : line).join('\n');
287
+ contents.push(prefixed);
288
+ }
289
+ }
290
+ }
291
+ };
292
+
293
+ addNodeContent(id);
294
+ return contents.join('\n');
295
+ },
296
+
297
+ setNodeIcon: async (id, icon) => {
298
+ const { files } = get();
299
+ const node = files.find(f => f.id === id);
300
+ if (!node) return;
301
+ const updated = { ...node, icon };
302
+ await saveFile(updated);
303
+ set(state => ({ files: state.files.map(f => f.id === id ? updated : f) }));
304
+ },
305
+
306
+ setNodeColor: async (id, color) => {
307
+ const { files } = get();
308
+ const node = files.find(f => f.id === id);
309
+ if (!node) return;
310
+ const updated = { ...node, color };
311
+ await saveFile(updated);
312
+ set(state => ({ files: state.files.map(f => f.id === id ? updated : f) }));
313
+ },
314
+
315
+ setComment: async (fileId, lineId, comment) => {
316
+ const { files } = get();
317
+ const node = files.find(f => f.id === fileId);
318
+ if (!node) return;
319
+
320
+ const newComments = { ...node.comments, [lineId]: comment };
321
+ if (!comment) delete newComments[lineId];
322
+
323
+ const updated = { ...node, comments: newComments };
324
+ await saveFile(updated);
325
+ set(state => ({ files: state.files.map(f => f.id === fileId ? updated : f) }));
326
+ }
327
+ }));
src/utils/exportUtils.ts ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { FileNode } from '../lib/db';
2
+
3
+ /**
4
+ * Extracts raw text from Lexical JSON payload if necessary,
5
+ * then prepends emdash '— ' to each non-empty text line.
6
+ */
7
+ export function formatContentForCopy(content: string): string {
8
+ if (!content) return '';
9
+
10
+ let rawText = content;
11
+ // If content is a Lexical JSON string
12
+ try {
13
+ const parsed = JSON.parse(content);
14
+ if (parsed.root && parsed.root.children) {
15
+ // Very basic extraction of paragraphs for copy buffer
16
+ // In reality, you'd use Lexical's @lexical/text plugin or simple tree iteration
17
+ rawText = parsed.root.children
18
+ .map((p: any) => p.children?.map((n: any) => n.text).join('') || '')
19
+ .join('\n');
20
+ }
21
+ } catch (e) {
22
+ // not JSON, fallback to rawText as is
23
+ }
24
+
25
+ const lines = rawText.split('\n');
26
+ const formattedLines = lines.map(line => {
27
+ if (line.trim().length > 0) {
28
+ return `— ${line}`;
29
+ }
30
+ return line; // Leave empty lines untouched
31
+ });
32
+
33
+ return formattedLines.join('\n');
34
+ }
35
+
36
+ export async function copyFilesContentToClipboard(files: FileNode[], idsToCopy: string[]) {
37
+ const contentArray: string[] = [];
38
+
39
+ const addContentRecursive = (nodeId: string) => {
40
+ const node = files.find(f => f.id === nodeId);
41
+ if (!node) return;
42
+
43
+ if (node.type === 'file' && node.content) {
44
+ contentArray.push(formatContentForCopy(node.content));
45
+ }
46
+
47
+ const children = files.filter(f => f.parentId === nodeId);
48
+ children.forEach(c => addContentRecursive(c.id));
49
+ };
50
+
51
+ for (const id of idsToCopy) {
52
+ addContentRecursive(id);
53
+ }
54
+
55
+ if (contentArray.length > 0) {
56
+ const combined = contentArray.join('\n\n');
57
+ await navigator.clipboard.writeText(combined);
58
+ }
59
+ }
src/utils/iconUtils.ts ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export function getIconNames(): string[] {
2
+ return [
3
+ "FirstBracketCircleIcon", "FirstBracketSquareIcon", "FirstBracketIcon",
4
+ "Add01Icon", "FolderAddIcon", "FileAddIcon", "Settings01Icon", "Download01Icon", "GridIcon"
5
+ ];
6
+ }
src/utils/icon_names.json ADDED
The diff for this file is too large to render. See raw diff
 
tsconfig.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true,
15
+ "jsx": "react-jsx",
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true,
22
+
23
+ "baseUrl": ".",
24
+ "paths": {
25
+ "@/*": ["./src/*"]
26
+ }
27
+ },
28
+ "include": ["src"],
29
+ "references": [{ "path": "./tsconfig.node.json" }]
30
+ }
tsconfig.node.json ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "skipLibCheck": true,
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "allowSyntheticDefaultImports": true
8
+ },
9
+ "include": ["vite.config.ts"]
10
+ }
vite.config.ts ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import { VitePWA } from 'vite-plugin-pwa'
4
+ import path from 'path'
5
+
6
+ // https://vitejs.dev/config/
7
+ export default defineConfig({
8
+ plugins: [
9
+ react(),
10
+ VitePWA({
11
+ registerType: 'autoUpdate',
12
+ manifest: {
13
+ name: 'Hybrid Editor',
14
+ short_name: 'HyEditor',
15
+ theme_color: '#ffffff',
16
+ icons: [
17
+ {
18
+ src: '/vite.svg',
19
+ sizes: '192x192',
20
+ type: 'image/svg+xml'
21
+ }
22
+ ]
23
+ }
24
+ })
25
+ ],
26
+ resolve: {
27
+ alias: {
28
+ '@': path.resolve(__dirname, './src'),
29
+ },
30
+ },
31
+ })
workspace_db.json ADDED
Binary file (3.27 kB). View file