Upload 31 files
Browse files- dist/assets/index-CEnsgmh2.js +0 -0
- dist/assets/index-OrJvPUH_.css +1 -0
- dist/index.html +16 -0
- dist/manifest.webmanifest +1 -0
- dist/registerSW.js +1 -0
- dist/sw.js +1 -0
- dist/workbox-8c29f6e4.js +1 -0
- index.html +15 -0
- keys.txt +4572 -0
- package-lock.json +0 -0
- package.json +39 -0
- src/App.tsx +109 -0
- src/components/Editor/EditorCore.tsx +196 -0
- src/components/Editor/HoverToolbar.tsx +191 -0
- src/components/Editor/LineNumberPlugin.tsx +201 -0
- src/components/Settings/SettingsModal.tsx +320 -0
- src/components/Sidebar/IconPicker.tsx +104 -0
- src/components/Sidebar/TreeView.tsx +458 -0
- src/index.css +261 -0
- src/lib/db.ts +162 -0
- src/lib/persistence.ts +21 -0
- src/main.tsx +10 -0
- src/plugins/AutoHighlighterPlugin.tsx +252 -0
- src/stores/fileStore.ts +327 -0
- src/utils/exportUtils.ts +59 -0
- src/utils/iconUtils.ts +6 -0
- src/utils/icon_names.json +0 -0
- tsconfig.json +30 -0
- tsconfig.node.json +10 -0
- vite.config.ts +31 -0
- workspace_db.json +0 -0
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
|
|
|