love-ui 1.2.7 → 1.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/index.js +6 -6
  2. package/dist/mcp-server.js +1 -1
  3. package/package.json +1 -1
  4. package/packages/code-block/README.md +62 -0
  5. package/packages/code-block/components.json +21 -0
  6. package/packages/code-block/package.json +46 -22
  7. package/packages/code-block/src/components/code-block/blocks/copy-with-select-package-manager.tsx +146 -0
  8. package/packages/code-block/src/components/code-block/blocks/copy-with-tabs-package-manager.tsx +110 -0
  9. package/packages/code-block/src/components/code-block/blocks/inline-code.tsx +28 -0
  10. package/packages/code-block/src/components/code-block/blocks/multi-tabs.tsx +118 -0
  11. package/packages/code-block/src/components/code-block/client/shiki.tsx +139 -0
  12. package/packages/code-block/src/components/code-block/client/sugar-high.tsx +38 -0
  13. package/packages/code-block/src/components/code-block/code-block.tsx +113 -0
  14. package/packages/code-block/src/components/code-block/copy-button.tsx +59 -0
  15. package/packages/code-block/src/components/code-block/mdx/pre-shiki.tsx +42 -0
  16. package/packages/code-block/src/components/code-block/mdx/pre-sugar-high.tsx +37 -0
  17. package/packages/code-block/src/components/ui/dropdown-menu.tsx +103 -0
  18. package/packages/code-block/src/components/ui/tabs.tsx +84 -0
  19. package/packages/code-block/src/index.ts +35 -0
  20. package/packages/code-block/src/stores/packageManager.ts +24 -0
  21. package/packages/code-block/src/styles/globals.css +79 -0
  22. package/packages/code-block/src/styles/shiki.css +95 -0
  23. package/packages/code-block/src/styles/sugar-high.css +48 -0
  24. package/packages/code-block/src/utils/cn.ts +6 -0
  25. package/packages/code-block/src/utils/copy.ts +9 -0
  26. package/packages/code-block/src/utils/react-to-text.ts +34 -0
  27. package/packages/code-block/src/utils/shiki/highlight.ts +47 -0
  28. package/packages/code-block/src/utils/sugar-high/highlight.ts +12 -0
  29. package/packages/code-block/tsconfig.json +13 -9
  30. package/packages/gooey-toast/package.json +28 -0
  31. package/packages/gooey-toast/src/gooey.tsx +614 -0
  32. package/packages/gooey-toast/src/icons.tsx +68 -0
  33. package/packages/gooey-toast/src/index.ts +10 -0
  34. package/packages/gooey-toast/src/styles.css +511 -0
  35. package/packages/gooey-toast/src/toast.tsx +444 -0
  36. package/packages/gooey-toast/src/types.ts +45 -0
  37. package/packages/gooey-toast/tsconfig.json +13 -0
  38. package/packages/gradient-mesh/index.tsx +236 -0
  39. package/packages/gradient-mesh/package.json +62 -0
  40. package/packages/gradient-mesh/tsconfig.json +10 -0
  41. package/packages/love-ui/src/components/site-header.tsx +3 -1
  42. package/packages/love-ui/src/hooks/use-media.tsx +22 -0
  43. package/packages/love-ui/src/styles/globals.css +1 -1
  44. package/packages/love-ui/src/ui/button.tsx +22 -4
  45. package/packages/love-ui/src/ui/card.tsx +25 -5
  46. package/packages/love-ui/src/ui/chart.tsx +353 -0
  47. package/packages/love-ui/src/ui/kbd.tsx +26 -0
  48. package/packages/patterns/combobox/rich-content/combobox-rich-content-4.tsx +1 -1
  49. package/packages/patterns/item/interactive/item-interactive-2.tsx +1 -1
  50. package/packages/patterns/scroll-area/layout/scroll-area-layout-3.tsx +1 -1
  51. package/packages/patterns/table/standard/table-standard-1.tsx +1 -1
  52. package/packages/patterns/table/standard/table-standard-2.tsx +1 -1
  53. package/packages/shadcn-ui/components/ui/card.tsx +25 -5
  54. package/packages/shader-ripple/index.tsx +303 -0
  55. package/packages/shader-ripple/package.json +60 -0
  56. package/packages/shader-ripple/tsconfig.json +18 -0
  57. package/packages/silk/types.d.ts +16 -6
  58. package/packages/code-block/index.tsx +0 -638
  59. package/packages/code-block/server.tsx +0 -63
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import{spawnSync as I}from"child_process";import{existsSync as P}from"fs";import{mkdir as U,readdir as z,readFile as $,writeFile as S}from"fs/promises";import a from"path";import{pathToFileURL as J,fileURLToPath as B}from"url";var M=a.dirname(B(import.meta.url)),X=a.resolve(M,".."),C=a.join(X,"packages"),H=new Set([".ts",".tsx",".cts",".mts",".js",".jsx",".css",".scss",".sass",".mdx",".md"]),V=new Set(["node_modules","dist",".turbo",".next","build",".cache"]),A=new Set(["accordion","alert","alert-dialog","autocomplete","avatar","badge","breadcrumb","button","card","checkbox","checkbox-group","collapsible","combobox","command","dialog","empty","field","fieldset","form","frame","group","input","label","menu","meter","number-field","pagination","popover","preview-card","progress","radio-group","scroll-area","select","separator","sheet","skeleton","slider","switch","table","tabs","textarea","toast","toggle","toggle-group","toolbar","tooltip"]);function _(e){if(!e)return e;let t=e.split("/");return t[t.length-1]||e}function Y(e){let t=e.trim();return t&&((t.startsWith("@/")||t.startsWith("~/"))&&(t=`src/${t.slice(2)}`),t.startsWith("/")&&(t=t.slice(1)),t=t.replace(/^\.\//,""),t=t.replace(/\/+$/,""),t)}function N(e){let t=_(e);return t==="ui"?"love-ui":t}function q(e){let t=e.loveui??{},n=typeof t.target=="string"?t.target.trim():"",s=t.category;if(n){let i=typeof t.includePackageName=="boolean"?t.includePackageName:!1;return{base:n.replace(/\/+$/,""),includePackageName:i}}return s==="feature"?{base:"components",includePackageName:!0}:s==="block"?{base:"components/blocks",includePackageName:!0}:{base:"components/ui",includePackageName:!0}}function G(e,t,n){let s=e.startsWith("src/")?e.slice(4):e;if(!t.includePackageName){let g=t.base.split("/").filter(Boolean),p=g[g.length-1];p&&s.startsWith(`${p}/`)&&(s=s.slice(p.length+1))}let l=`${(t.includePackageName?`${t.base}/${n}`:t.base).replace(/\/+/g,"/")}/${s}`.replace(/\/+/g,"/");return{cleanedPath:s,target:l}}async function K(e){let t=a.join(e,"components.json");try{let n=await $(t,"utf8"),i=JSON.parse(n).aliases?.components;return i?Y(i):null}catch{return null}}async function Q(e){let t=["tsconfig.json","jsconfig.json"].map(n=>a.join(e,n)).find(n=>P(n));if(t)try{let n=await $(t,"utf8"),i=JSON.parse(n).compilerOptions?.paths;if(i&&typeof i=="object")for(let r of Object.keys(i)){let l=i[r];if(r==="@/*"&&Array.isArray(l)&&l.some(g=>g.startsWith("src/")||g.startsWith("./src/")))return"src/components";if(r==="@/*"&&Array.isArray(l)&&l.some(g=>g.startsWith("app/")||g.startsWith("./app/")))return"app/components"}}catch{}return P(a.join(e,"src"))?"src/components":P(a.join(e,"app"))?"app/components":"components"}function E(e,t,n){let s=r=>{let l=r.startsWith("/"),g=r.endsWith("/"),p=r.split("/").filter(Boolean),u=[];for(let w of p)u[u.length-1]!==w&&u.push(w);let d=u.join("/");return`${l?"/":""}${d}${g?"/":""}`};if(n)return s(e);let i=t.replace(/\/+$/,"");if(e.startsWith("components/")){let r=e.slice(10);return s(`${i}${r}`.replace(/^\//,""))}if(e.startsWith("lib/")){if(i.startsWith("src/"))return s(`src/${e}`);if(i.startsWith("app/"))return s(`app/${e}`)}return e.startsWith("ui/")?s(`${i}/${e}`):s(e)}async function T(e,t){let n=a.dirname(a.join(t,e));await U(n,{recursive:!0})}async function Z(e,t){let n=a.join(e,"package.json"),s={};try{let p=await $(n,"utf8");s=JSON.parse(p)}catch{}let i=q(s),r=_(t),l=[];async function g(p,u){let d=await z(p,{withFileTypes:!0});for(let w of d){if(V.has(w.name))continue;let j=a.join(p,w.name);if(w.isDirectory()){await g(j,u);continue}let F=a.extname(w.name);if(!H.has(F)||w.name==="package.json")continue;let R=a.relative(u,j).split(a.sep).join("/"),{target:x}=G(R,i,r),v=await $(j,"utf8");l.push({path:R,target:x,content:v})}}return await g(e,e),l}async function ee(e){let t=a.join(C,"love-ui"),n=a.join(t,"src","ui",`${e}.tsx`);if(!P(n))return null;try{let s=[],i=await $(n,"utf8");i=i.replace(/from\s+["']@loveui\/ui\/lib\/utils["']/g,'from "@/lib/utils"'),s.push({path:`src/ui/${e}.tsx`,target:`components/ui/${e}.tsx`,content:i});let r=a.join(t,"src","lib","utils.ts");if(P(r)){let l=await $(r,"utf8");s.push({path:"src/lib/utils.ts",target:"lib/utils.ts",content:l})}return s}catch(s){return console.warn(`Warning: unable to read ${e} component`,s),null}}async function te(e){if(A.has(e))return await ee(e);let t=N(e),n=a.join(C,t);if(!P(n))return null;try{return await Z(n,e)}catch(s){return console.warn(`Warning: unable to read bundled sources for ${e}`,s),null}}var ne={"@base-ui-components/react":"1.0.0-beta.4","class-variance-authority":"^0.7.1",clsx:"^2.1.1","tailwind-merge":"^3.3.1"};async function se(e){if(A.has(e))return{...ne};let t=N(e),n=a.join(C,t,"package.json");try{let s=await $(n,"utf8");return JSON.parse(s).dependencies??{}}catch{return{}}}async function ie(e){return P(a.join(e,"bun.lockb"))?"bun":P(a.join(e,"pnpm-lock.yaml"))?"pnpm":P(a.join(e,"yarn.lock"))?"yarn":"npm"}async function oe(e,t,n){let s=Object.entries(e);if(s.length===0)return!0;console.log(`
3
- Installing dependencies...`);let i=s.map(([g,p])=>`${g}@${p}`),r;switch(t){case"bun":r=`bun add ${i.join(" ")}`;break;case"pnpm":r=`pnpm add ${i.join(" ")}`;break;case"yarn":r=`yarn add ${i.join(" ")}`;break;default:r=`npm install ${i.join(" ")}`}let l=I(r,{stdio:"inherit",shell:!0,cwd:n});return l.error||l.status!==0?(console.warn(`
2
+ import{spawnSync as I}from"child_process";import{existsSync as $}from"fs";import{mkdir as A,readdir as z,readFile as P,writeFile as S}from"fs/promises";import c from"path";import{pathToFileURL as J,fileURLToPath as B}from"url";var M=c.dirname(B(import.meta.url)),X=c.resolve(M,".."),W=c.join(X,"packages"),H=new Set([".ts",".tsx",".cts",".mts",".js",".jsx",".css",".scss",".sass",".mdx",".md"]),V=new Set(["node_modules","dist",".turbo",".next","build",".cache"]),U=new Set(["accordion","alert","alert-dialog","autocomplete","avatar","badge","breadcrumb","button","card","checkbox","checkbox-group","collapsible","combobox","command","dialog","empty","field","fieldset","form","frame","group","input","label","menu","meter","number-field","pagination","popover","preview-card","progress","radio-group","scroll-area","select","separator","sheet","skeleton","slider","switch","table","tabs","textarea","toast","toggle","toggle-group","toolbar","tooltip"]);function N(e){if(!e)return e;let t=e.split("/");return t[t.length-1]||e}function Y(e){let t=e.trim();return t&&((t.startsWith("@/")||t.startsWith("~/"))&&(t=`src/${t.slice(2)}`),t.startsWith("/")&&(t=t.slice(1)),t=t.replace(/^\.\//,""),t=t.replace(/\/+$/,""),t)}function _(e){let t=N(e);return t==="ui"?"love-ui":t}function q(e){let t=e.loveui??{},n=typeof t.target=="string"?t.target.trim():"",s=t.category;if(n){let i=typeof t.includePackageName=="boolean"?t.includePackageName:!1;return{base:n.replace(/\/+$/,""),includePackageName:i}}return s==="feature"?{base:"components",includePackageName:!0}:s==="block"?{base:"components/blocks",includePackageName:!0}:{base:"components/ui",includePackageName:!0}}function G(e,t,n){let s=e.startsWith("src/")?e.slice(4):e;if(!t.includePackageName){let f=t.base.split("/").filter(Boolean),p=f[f.length-1];p&&s.startsWith(`${p}/`)&&(s=s.slice(p.length+1))}let l=`${(t.includePackageName?`${t.base}/${n}`:t.base).replace(/\/+/g,"/")}/${s}`.replace(/\/+/g,"/");return{cleanedPath:s,target:l}}async function K(e){let t=c.join(e,"components.json");try{let n=await P(t,"utf8"),i=JSON.parse(n).aliases?.components;return i?Y(i):null}catch{return null}}async function Q(e){let t=["tsconfig.json","jsconfig.json"].map(n=>c.join(e,n)).find(n=>$(n));if(t)try{let n=await P(t,"utf8"),i=JSON.parse(n).compilerOptions?.paths;if(i&&typeof i=="object")for(let a of Object.keys(i)){let l=i[a];if(a==="@/*"&&Array.isArray(l)&&l.some(f=>f.startsWith("src/")||f.startsWith("./src/")))return"src/components";if(a==="@/*"&&Array.isArray(l)&&l.some(f=>f.startsWith("app/")||f.startsWith("./app/")))return"app/components"}}catch{}return $(c.join(e,"src"))?"src/components":$(c.join(e,"app"))?"app/components":"components"}function T(e,t,n){let s=a=>{let l=a.startsWith("/"),f=a.endsWith("/"),p=a.split("/").filter(Boolean),m=[];for(let k of p)m[m.length-1]!==k&&m.push(k);let u=m.join("/");return`${l?"/":""}${u}${f?"/":""}`};if(n)return s(e);let i=t.replace(/\/+$/,"");if(e.startsWith("components/")){let a=e.slice(10);return s(`${i}${a}`.replace(/^\//,""))}if(e.startsWith("lib/")){if(i.startsWith("src/"))return s(`src/${e}`);if(i.startsWith("app/"))return s(`app/${e}`)}if(e.startsWith("hooks/")){if(i.startsWith("src/"))return s(`src/${e}`);if(i.startsWith("app/"))return s(`app/${e}`)}return e.startsWith("ui/")?s(`${i}/${e}`):s(e)}async function E(e,t){let n=c.dirname(c.join(t,e));await A(n,{recursive:!0})}async function Z(e,t){let n=c.join(e,"package.json"),s={};try{let p=await P(n,"utf8");s=JSON.parse(p)}catch{}let i=q(s),a=N(t),l=[];async function f(p,m){let u=await z(p,{withFileTypes:!0});for(let k of u){if(V.has(k.name))continue;let j=c.join(p,k.name);if(k.isDirectory()){await f(j,m);continue}let x=c.extname(k.name);if(!H.has(x)||k.name==="package.json")continue;let R=c.relative(m,j).split(c.sep).join("/"),{target:v}=G(R,i,a),F=await P(j,"utf8");l.push({path:R,target:v,content:F})}}return await f(e,e),l}async function ee(e){let t=c.join(W,"love-ui"),n=c.join(t,"src","ui",`${e}.tsx`);if(!$(n))return null;try{let s=[],i=await P(n,"utf8");i=i.replace(/from\s+["']@loveui\/ui\/lib\/utils["']/g,'from "@/lib/utils"'),s.push({path:`src/ui/${e}.tsx`,target:`components/ui/${e}.tsx`,content:i});let a=c.join(t,"src","lib","utils.ts");if($(a)){let l=await P(a,"utf8");s.push({path:"src/lib/utils.ts",target:"lib/utils.ts",content:l})}return s}catch(s){return console.warn(`Warning: unable to read ${e} component`,s),null}}async function te(e){if(U.has(e))return await ee(e);let t=_(e),n=c.join(W,t);if(!$(n))return null;try{return await Z(n,e)}catch(s){return console.warn(`Warning: unable to read bundled sources for ${e}`,s),null}}var ne={"@base-ui-components/react":"1.0.0-beta.4","class-variance-authority":"^0.7.1",clsx:"^2.1.1","tailwind-merge":"^3.3.1"};async function se(e){if(U.has(e))return{...ne};let t=_(e),n=c.join(W,t,"package.json");try{let s=await P(n,"utf8");return JSON.parse(s).dependencies??{}}catch{return{}}}async function ie(e){return $(c.join(e,"bun.lockb"))?"bun":$(c.join(e,"pnpm-lock.yaml"))?"pnpm":$(c.join(e,"yarn.lock"))?"yarn":"npm"}async function re(e,t,n){let s=Object.entries(e);if(s.length===0)return!0;console.log(`
3
+ Installing dependencies...`);let i=s.map(([f,p])=>`${f}@${p}`),a;switch(t){case"bun":a=`bun add ${i.join(" ")}`;break;case"pnpm":a=`pnpm add ${i.join(" ")}`;break;case"yarn":a=`yarn add ${i.join(" ")}`;break;default:a=`npm install ${i.join(" ")}`}let l=I(a,{stdio:"inherit",shell:!0,cwd:n});return l.error||l.status!==0?(console.warn(`
4
4
  Failed to install dependencies. You may need to install them manually:`),console.warn(` ${i.join(`
5
5
  `)}`),!1):(console.log(`Dependencies installed successfully!
6
- `),!0)}async function re(e=process.argv.slice(2)){(e.length===0||e.length===1&&(e[0]==="--version"||e[0]==="-v"))&&(console.log("love-ui version 1.1.9"),process.exit(0)),(e.length<2||e[0]!=="add")&&(console.log("Usage: npx love-ui add [...packages]"),console.log(" npx love-ui --version"),process.exit(1));let t=e.slice(1),n=process.cwd(),s=await K(n),i=await Q(n),r=s??i,l=s!==null,g=await ie(n),p={};for(let u of t){if(!u.trim())continue;console.log(`
7
- Adding ${u}...`);let d=null,w=null;if(u.startsWith("http://")||u.startsWith("https://"))try{let o=await fetch(u);o.ok?d=await o.json():console.warn(`Failed to fetch ${u}: HTTP ${o.status}`)}catch(o){console.warn(`Failed to fetch from ${u}:`,o)}else{let o=new URL(`r/${u}.json`,"https://www.loveui.dev/");try{let c=await fetch(o);c.ok&&(d=await c.json())}catch{}w=await te(u)}let j=w??d?.files??[];j=j.map(o=>{let c=o.target||o.path;return c.startsWith("registry/default/")&&(c=c.replace("registry/default/","")),{...o,target:c}});let F=j.find(o=>o.target.match(/^components\/comp-\d+\.tsx$/));if(F){let o=j.filter(c=>c.target.match(/^components\/[^/]+\//)&&c.target!==F.target);if(o.length>0&&o[0]){let c=o[0].target.match(/^components\/([^/]+)\//);if(c&&c[1]){let h=c[1];F.target=`components/${h}-demo.tsx`}}}if(!j.length){console.warn(`Component "${u}" not found. Available components can be found at https://loveui.dev`);continue}l||await U(a.join(n,r),{recursive:!0});let R=0,x=0;for(let o of j){if(!o.content)continue;let c=E(o.target,r,l),h=a.join(n,c),k=P(h),f=o.content;if(f=f.replace(/@\/registry\/building-blocks\/default\/components\//g,"@/components/"),f=f.replace(/@\/registry\/building-blocks\/default\/ui\//g,"@/components/ui/"),f=f.replace(/@\/registry\/building-blocks\/default\/lib\//g,"@/lib/"),f=f.replace(/@\/registry\/default\/components\//g,"@/components/"),f=f.replace(/@\/registry\/default\/ui\//g,"@/components/ui/"),f=f.replace(/@\/registry\/default\/lib\//g,"@/lib/"),k)try{if(await $(h,"utf8")===f)continue}catch{}await T(c,n),await S(h,f,"utf8"),k?x++:R++}if(R>0&&console.log(`\u2713 Created ${R} file${R>1?"s":""}`),x>0&&console.log(`\u2713 Updated ${x} file${x>1?"s":""}`),d?.registryDependencies&&d.registryDependencies.length>0){console.log(`
8
- Installing ${d.registryDependencies.length} required component${d.registryDependencies.length>1?"s":""}...`);for(let o of d.registryDependencies){let c=o;o.startsWith("https://loveui.dev/building-blocks/r/")&&(c=`https://ui.loveui.dev/ui/r/${o.split("/").pop()}`);try{let h=await fetch(c);if(h.ok){let k=await h.json(),W=(k?.files??[]).map(m=>{let b=m.target||m.path;return b.startsWith("registry/default/")&&(b=b.replace("registry/default/","")),{...m,target:b}});for(let m of W){if(!m.content)continue;let b=E(m.target,r,l),D=a.join(n,b),L=P(D),y=m.content;if(y=y.replace(/@\/registry\/building-blocks\/default\/components\//g,"@/components/"),y=y.replace(/@\/registry\/building-blocks\/default\/ui\//g,"@/components/ui/"),y=y.replace(/@\/registry\/building-blocks\/default\/lib\//g,"@/lib/"),y=y.replace(/@\/registry\/default\/components\//g,"@/components/"),y=y.replace(/@\/registry\/default\/ui\//g,"@/components/ui/"),y=y.replace(/@\/registry\/default\/lib\//g,"@/lib/"),L)try{if(await $(D,"utf8")===y)continue}catch{}await T(b,n),await S(D,y,"utf8")}let O=["@loveui/shadcn-ui","jotai","lucide-react","react","react-dom"];if(k?.dependencies)if(Array.isArray(k.dependencies))k.dependencies.forEach(m=>{O.includes(m)||(p[m]="latest")});else{let m=k.dependencies;Object.keys(m).forEach(b=>{!O.includes(b)&&m[b]&&(p[b]=m[b])})}}else console.warn(` \u2717 Failed to fetch ${c}: HTTP ${h.status}`)}catch(h){console.warn(` \u2717 Failed to install ${c}:`,h.message)}}console.log("\u2713 Installed registry dependencies")}let v={};d?.dependencies?Array.isArray(d.dependencies)?d.dependencies.forEach(o=>{v[o]="latest"}):v=d.dependencies:v=await se(u),Object.assign(p,v)}Object.keys(p).length>0&&await oe(p,g,n),console.log(`
9
- \u2713 Done! You can now import and use the components in your app.`)}var ae=process.argv[1]&&(import.meta.url===J(process.argv[1]).href||process.argv[1].includes("love-ui")||process.argv[1].includes("loveui"));ae&&re().catch(e=>{console.error(e),process.exit(1)});export{re as run};
6
+ `),!0)}async function oe(e=process.argv.slice(2)){(e.length===0||e.length===1&&(e[0]==="--version"||e[0]==="-v"))&&(console.log("love-ui version 1.1.9"),process.exit(0)),(e.length<2||e[0]!=="add")&&(console.log("Usage: npx love-ui add [...packages]"),console.log(" npx love-ui --version"),process.exit(1));let t=e.slice(1),n=process.cwd(),s=await K(n),i=await Q(n),a=s??i,l=s!==null,f=await ie(n),p={};for(let m of t){if(!m.trim())continue;console.log(`
7
+ Adding ${m}...`);let u=null,k=null;if(m.startsWith("http://")||m.startsWith("https://")){let r=m;r.includes("/building-blocks/r/")&&(r=r.replace("/building-blocks/r/","/building-blocks/"),console.log(`Auto-corrected URL to: ${r}`));try{let o=await fetch(r);o.ok?u=await o.json():console.warn(`Failed to fetch ${r}: HTTP ${o.status}`)}catch(o){console.warn(`Failed to fetch from ${r}:`,o)}}else{let r=new URL(`r/${m}.json`,"https://www.loveui.dev/");try{let o=await fetch(r);o.ok&&(u=await o.json())}catch{}k=await te(m)}let j=k??u?.files??[];j=j.map(r=>{let o=r.target||r.path;return o.startsWith("registry/default/")&&(o=o.replace("registry/default/","")),{...r,target:o}});let x=j.find(r=>r.target.match(/^components\/comp-\d+\.tsx$/));if(x){let r=j.filter(o=>o.target.match(/^components\/[^/]+\//)&&o.target!==x.target);if(r.length>0&&r[0]){let o=r[0].target.match(/^components\/([^/]+)\//);if(o&&o[1]){let h=o[1];x.target=`components/${h}-demo.tsx`}}else if(u?.meta?.tags&&Array.isArray(u.meta.tags)&&u.meta.tags.length>0){let h=u.meta.tags.slice(0,2).filter(b=>b.length>0);if(h.length>0){let b=h.join("-").toLowerCase().replace(/\s+/g,"-");x.target=`components/${b}.tsx`}}}if(!j.length){console.warn(`Component "${m}" not found. Available components can be found at https://loveui.dev`);continue}l||await A(c.join(n,a),{recursive:!0});let R=0,v=0;for(let r of j){if(!r.content)continue;let o=T(r.target,a,l),h=c.join(n,o),b=$(h),g=r.content;if(g=g.replace(/@\/registry\/building-blocks\/default\/components\//g,"@/components/"),g=g.replace(/@\/registry\/building-blocks\/default\/ui\//g,"@/components/ui/"),g=g.replace(/@\/registry\/building-blocks\/default\/lib\//g,"@/lib/"),g=g.replace(/@\/registry\/building-blocks\/default\/hooks\//g,"@/hooks/"),g=g.replace(/@\/registry\/default\/components\//g,"@/components/"),g=g.replace(/@\/registry\/default\/ui\//g,"@/components/ui/"),g=g.replace(/@\/registry\/default\/lib\//g,"@/lib/"),g=g.replace(/@\/registry\/default\/hooks\//g,"@/hooks/"),b)try{if(await P(h,"utf8")===g)continue}catch{}await E(o,n),await S(h,g,"utf8"),b?v++:R++}if(R>0&&console.log(`\u2713 Created ${R} file${R>1?"s":""}`),v>0&&console.log(`\u2713 Updated ${v} file${v>1?"s":""}`),u?.registryDependencies&&u.registryDependencies.length>0){console.log(`
8
+ Installing ${u.registryDependencies.length} required component${u.registryDependencies.length>1?"s":""}...`);for(let r of u.registryDependencies){let o=r;r.startsWith("https://loveui.dev/building-blocks/r/")&&(o=`https://ui.loveui.dev/ui/r/${r.split("/").pop()}`);try{let h=await fetch(o);if(h.ok){let b=await h.json(),C=(b?.files??[]).map(y=>{let w=y.target||y.path;return w.startsWith("registry/default/")&&(w=w.replace("registry/default/","")),{...y,target:w}});for(let y of C){if(!y.content)continue;let w=T(y.target,a,l),D=c.join(n,w),L=$(D),d=y.content;if(d=d.replace(/@\/registry\/building-blocks\/default\/components\//g,"@/components/"),d=d.replace(/@\/registry\/building-blocks\/default\/ui\//g,"@/components/ui/"),d=d.replace(/@\/registry\/building-blocks\/default\/lib\//g,"@/lib/"),d=d.replace(/@\/registry\/building-blocks\/default\/hooks\//g,"@/hooks/"),d=d.replace(/@\/registry\/default\/components\//g,"@/components/"),d=d.replace(/@\/registry\/default\/ui\//g,"@/components/ui/"),d=d.replace(/@\/registry\/default\/lib\//g,"@/lib/"),d=d.replace(/@\/registry\/default\/hooks\//g,"@/hooks/"),L)try{if(await P(D,"utf8")===d)continue}catch{}await E(w,n),await S(D,d,"utf8")}let O=["@loveui/shadcn-ui","jotai","lucide-react","react","react-dom"];if(b?.dependencies)if(Array.isArray(b.dependencies))b.dependencies.forEach(y=>{O.includes(y)||(p[y]="latest")});else{let y=b.dependencies;Object.keys(y).forEach(w=>{!O.includes(w)&&y[w]&&(p[w]=y[w])})}}else console.warn(` \u2717 Failed to fetch ${o}: HTTP ${h.status}`)}catch(h){console.warn(` \u2717 Failed to install ${o}:`,h.message)}}console.log("\u2713 Installed registry dependencies")}let F={};u?.dependencies?Array.isArray(u.dependencies)?u.dependencies.forEach(r=>{F[r]="latest"}):F=u.dependencies:F=await se(m),Object.assign(p,F)}Object.keys(p).length>0&&await re(p,f,n),console.log(`
9
+ \u2713 Done! You can now import and use the components in your app.`)}var ae=process.argv[1]&&(import.meta.url===J(process.argv[1]).href||process.argv[1].includes("love-ui")||process.argv[1].includes("loveui"));ae&&oe().catch(e=>{console.error(e),process.exit(1)});export{oe as run};
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{Server as ge}from"@modelcontextprotocol/sdk/server";var L={name:"love-ui",version:"1.2.5",private:!1,license:"AGPL-3.0-or-later",type:"module",bin:{loveui:"dist/index.js","love-ui":"dist/index.js","loveui-mcp":"dist/mcp-server.js"},files:["dist","packages","*.ts","*.tsx","*.css","*.mdx"],main:"packages/love-ui/index.ts",types:"packages/love-ui/index.ts",exports:{".":{import:"./packages/love-ui/index.ts",require:"./packages/love-ui/index.ts"},"./lib/*":"./packages/love-ui/*","./components/*":"./packages/love-ui/components/*","./shadcn-ui/*":"./packages/shadcn-ui/*","./package.json":"./package.json"},dependencies:{"@modelcontextprotocol/sdk":"^1.18.1",postcss:"^8.5.6","postcss-nested":"^7.0.2"},scripts:{build:"tsup",postbuild:"node ./scripts/copy-packages.mjs",clean:"rimraf dist packages"},devDependencies:{"@types/node":"^20.14.10",rimraf:"^6.0.1",tsup:"^8.5.0"}};import{constants as X}from"fs";import{access as H,readFile as N,readdir as C}from"fs/promises";import D,{extname as W,join as P,relative as V}from"path";import{fileURLToPath as Y}from"url";import A from"postcss";import Q from"postcss-nested";var Z=D.dirname(Y(import.meta.url)),ee=D.resolve(Z,".."),U=D.join(ee,"packages"),te=new Set([".turbo",".next",".git","dist","build","storybook-static","node_modules","__tests__","__mocks__","coverage"]),se=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".css",".scss",".sass",".mdx"]),ne=new Set(["package.json","tsconfig.json","tsconfig.build.json","tsconfig.test.json","README.md",".DS_Store"]),ie=new Set(["shadcn-ui","typescript-config","patterns","loveui","love-ui"]),re=e=>e.replace(/\\/g,"/"),J=async(e,s,t)=>{let n=await C(e,{withFileTypes:!0});for(let i of n){let o=P(e,i.name);if(i.isDirectory()){if(te.has(i.name))continue;await J(o,s,t);continue}let d=W(i.name);!se.has(d)||ne.has(i.name)||i.name.endsWith(".d.ts")||i.name.endsWith(".test.ts")||i.name.endsWith(".test.tsx")||i.name.endsWith(".stories.tsx")||t.push({absolute:o,relative:re(V(s,o))})}},oe=(e,s)=>{let t=e.loveui??{},n=typeof t.target=="string"?t.target.trim():"",i=t.category;if(n.length>0){let o=typeof t.includePackageName=="boolean"?t.includePackageName:!1;return{base:n.replace(/\/+$/,""),includePackageName:o}}return i==="feature"?{base:"components",includePackageName:!0}:i==="block"?{base:"components/blocks",includePackageName:!0}:{base:"components/ui",includePackageName:!0}},ae=e=>{let t=(e.loveui??{}).type;return typeof t=="string"&&t.trim().length>0?t:"registry:ui"},ce=async e=>{try{return await H(e,X.F_OK),!0}catch{return!1}},le=e=>e.startsWith("@loveui/")||e.startsWith("@repo/"),pe=e=>e.replace(/^@repo\//,"").replace(/^@loveui\//,""),G=async()=>(await C(U,{withFileTypes:!0})).filter(s=>s.isDirectory()).map(s=>s.name).filter(s=>!ie.has(s)).sort((s,t)=>s.localeCompare(t)),E=async e=>{let s=P(U,e),t=P(s,"package.json");if(!await ce(t))throw new Error(`Missing package.json for ${e}`);let n=JSON.parse(await N(t,"utf8")),i=ae(n),o=Object.keys(n.dependencies??{}),d=Object.keys(n.peerDependencies??{}),O=Object.keys(n.devDependencies??{}),k=new Set([...o,...d,...O].filter(le).filter(r=>r!=="@loveui/shadcn-ui")),T=[...new Set([...o,...d].filter(r=>!k.has(r)))],_=[...new Set(O.filter(r=>!k.has(r)&&!["@loveui/typescript-config","@types/react","@types/react-dom","typescript"].includes(r)))],w=[];for(let r of k){let m=pe(r);w.push(`https://www.loveui.dev/r/${m}.json`)}let I=[];await J(s,s,I);let u=[],c={},p=oe(n,e);for(let r of I){let m=await N(r.absolute,"utf8"),R=W(r.absolute);if(R===".css"||R===".scss"||R===".sass"){let y=await A([Q]).process(m,{from:void 0});A.parse(y.css).walkAtRules("layer",b=>{let j=`@layer ${b.params}`;c[j]??={},b.walkRules(a=>{if(a.parent&&a.parent.type==="atrule"&&a.parent.name==="media")return;let h=a.selector,l={};a.walkDecls(v=>{l[v.prop]=v.value}),Object.keys(l).length>0&&(c[j][h]=l)}),b.walkAtRules("media",a=>{let h=`@media ${a.params}`,l=c[j];l[h]??={};let v=l[h];a.walkRules($=>{let B=$.selector,x={};$.walkDecls(F=>{x[F.prop]=F.value}),Object.keys(x).length>0&&(v[B]=x)})})});continue}let g=r.relative.startsWith("src/")?r.relative.slice(4):r.relative;if(!p.includePackageName){let y=p.base.split("/").filter(Boolean),f=y[y.length-1];f&&g.startsWith(`${f}/`)&&(g=g.slice(f.length+1))}let q=e.includes("/")?e.split("/").pop()??e:e,z=(p.includePackageName?`${p.base}/${q}`:p.base).replace(/\/+$/,"");u.push({type:i,path:g,target:`${z}/${g}`.replace(/\/+/g,"/"),content:m})}let K=!u.length&&Object.keys(c).length>0?"registry:style":i;return{$schema:"https://ui.shadcn.com/schema/registry-item.json",name:e,type:K,title:n.title??e,description:n.description,author:n.author??"Connor Love <hello@loveconnor.com>",dependencies:T.length?T:void 0,devDependencies:_.length?_:void 0,registryDependencies:w.length?Array.from(new Set(w)):void 0,files:u.length?u:void 0,css:Object.keys(c).length?c:void 0}};var S="loveui://registry/",de=e=>`${S}${e}`;async function ue(){let e=new ge({name:"loveui-mcp",version:L.version??"0.0.0"});e.addResourceProvider({name:"loveui-registry",listResources:async()=>(await G()).map(t=>({uri:de(t),name:t,description:`loveui registry definition for ${t}`,mimeType:"application/json"})),readResource:async s=>{if(!s.startsWith(S))throw new Error(`Unsupported resource URI: ${s}`);let t=s.slice(S.length),n=await E(t);return{contents:[{uri:s,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}}),e.addTool({name:"get-loveui-package",description:"Fetch a loveui registry definition by package name.",inputSchema:{type:"object",additionalProperties:!1,properties:{name:{type:"string",description:"Package name, e.g. badge"}},required:["name"]},handler:async s=>{let t=s?.name;if(typeof t!="string"||t.trim()==="")throw new Error("Package name is required.");let n=await E(t);return{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}}),await e.start()}ue().catch(e=>{console.error(e),process.exit(1)});
2
+ import{Server as ge}from"@modelcontextprotocol/sdk/server";var L={name:"love-ui",version:"1.2.8",private:!1,license:"AGPL-3.0-or-later",type:"module",bin:{loveui:"dist/index.js","love-ui":"dist/index.js","loveui-mcp":"dist/mcp-server.js"},files:["dist","packages","*.ts","*.tsx","*.css","*.mdx"],main:"packages/love-ui/index.ts",types:"packages/love-ui/index.ts",exports:{".":{import:"./packages/love-ui/index.ts",require:"./packages/love-ui/index.ts"},"./lib/*":"./packages/love-ui/*","./components/*":"./packages/love-ui/components/*","./shadcn-ui/*":"./packages/shadcn-ui/*","./package.json":"./package.json"},dependencies:{"@modelcontextprotocol/sdk":"^1.18.1",postcss:"^8.5.6","postcss-nested":"^7.0.2"},scripts:{build:"tsup",postbuild:"node ./scripts/copy-packages.mjs",clean:"rimraf dist packages"},devDependencies:{"@types/node":"^20.14.10",rimraf:"^6.0.1",tsup:"^8.5.0"}};import{constants as X}from"fs";import{access as H,readFile as N,readdir as C}from"fs/promises";import D,{extname as W,join as P,relative as V}from"path";import{fileURLToPath as Y}from"url";import A from"postcss";import Q from"postcss-nested";var Z=D.dirname(Y(import.meta.url)),ee=D.resolve(Z,".."),U=D.join(ee,"packages"),te=new Set([".turbo",".next",".git","dist","build","storybook-static","node_modules","__tests__","__mocks__","coverage"]),se=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".css",".scss",".sass",".mdx"]),ne=new Set(["package.json","tsconfig.json","tsconfig.build.json","tsconfig.test.json","README.md",".DS_Store"]),ie=new Set(["shadcn-ui","typescript-config","patterns","loveui","love-ui"]),re=e=>e.replace(/\\/g,"/"),J=async(e,s,t)=>{let n=await C(e,{withFileTypes:!0});for(let i of n){let o=P(e,i.name);if(i.isDirectory()){if(te.has(i.name))continue;await J(o,s,t);continue}let d=W(i.name);!se.has(d)||ne.has(i.name)||i.name.endsWith(".d.ts")||i.name.endsWith(".test.ts")||i.name.endsWith(".test.tsx")||i.name.endsWith(".stories.tsx")||t.push({absolute:o,relative:re(V(s,o))})}},oe=(e,s)=>{let t=e.loveui??{},n=typeof t.target=="string"?t.target.trim():"",i=t.category;if(n.length>0){let o=typeof t.includePackageName=="boolean"?t.includePackageName:!1;return{base:n.replace(/\/+$/,""),includePackageName:o}}return i==="feature"?{base:"components",includePackageName:!0}:i==="block"?{base:"components/blocks",includePackageName:!0}:{base:"components/ui",includePackageName:!0}},ae=e=>{let t=(e.loveui??{}).type;return typeof t=="string"&&t.trim().length>0?t:"registry:ui"},ce=async e=>{try{return await H(e,X.F_OK),!0}catch{return!1}},le=e=>e.startsWith("@loveui/")||e.startsWith("@repo/"),pe=e=>e.replace(/^@repo\//,"").replace(/^@loveui\//,""),G=async()=>(await C(U,{withFileTypes:!0})).filter(s=>s.isDirectory()).map(s=>s.name).filter(s=>!ie.has(s)).sort((s,t)=>s.localeCompare(t)),E=async e=>{let s=P(U,e),t=P(s,"package.json");if(!await ce(t))throw new Error(`Missing package.json for ${e}`);let n=JSON.parse(await N(t,"utf8")),i=ae(n),o=Object.keys(n.dependencies??{}),d=Object.keys(n.peerDependencies??{}),O=Object.keys(n.devDependencies??{}),k=new Set([...o,...d,...O].filter(le).filter(r=>r!=="@loveui/shadcn-ui")),T=[...new Set([...o,...d].filter(r=>!k.has(r)))],_=[...new Set(O.filter(r=>!k.has(r)&&!["@loveui/typescript-config","@types/react","@types/react-dom","typescript"].includes(r)))],w=[];for(let r of k){let m=pe(r);w.push(`https://www.loveui.dev/r/${m}.json`)}let I=[];await J(s,s,I);let u=[],c={},p=oe(n,e);for(let r of I){let m=await N(r.absolute,"utf8"),R=W(r.absolute);if(R===".css"||R===".scss"||R===".sass"){let y=await A([Q]).process(m,{from:void 0});A.parse(y.css).walkAtRules("layer",b=>{let j=`@layer ${b.params}`;c[j]??={},b.walkRules(a=>{if(a.parent&&a.parent.type==="atrule"&&a.parent.name==="media")return;let h=a.selector,l={};a.walkDecls(v=>{l[v.prop]=v.value}),Object.keys(l).length>0&&(c[j][h]=l)}),b.walkAtRules("media",a=>{let h=`@media ${a.params}`,l=c[j];l[h]??={};let v=l[h];a.walkRules($=>{let B=$.selector,x={};$.walkDecls(F=>{x[F.prop]=F.value}),Object.keys(x).length>0&&(v[B]=x)})})});continue}let g=r.relative.startsWith("src/")?r.relative.slice(4):r.relative;if(!p.includePackageName){let y=p.base.split("/").filter(Boolean),f=y[y.length-1];f&&g.startsWith(`${f}/`)&&(g=g.slice(f.length+1))}let q=e.includes("/")?e.split("/").pop()??e:e,z=(p.includePackageName?`${p.base}/${q}`:p.base).replace(/\/+$/,"");u.push({type:i,path:g,target:`${z}/${g}`.replace(/\/+/g,"/"),content:m})}let K=!u.length&&Object.keys(c).length>0?"registry:style":i;return{$schema:"https://ui.shadcn.com/schema/registry-item.json",name:e,type:K,title:n.title??e,description:n.description,author:n.author??"Connor Love <hello@loveconnor.com>",dependencies:T.length?T:void 0,devDependencies:_.length?_:void 0,registryDependencies:w.length?Array.from(new Set(w)):void 0,files:u.length?u:void 0,css:Object.keys(c).length?c:void 0}};var S="loveui://registry/",de=e=>`${S}${e}`;async function ue(){let e=new ge({name:"loveui-mcp",version:L.version??"0.0.0"});e.addResourceProvider({name:"loveui-registry",listResources:async()=>(await G()).map(t=>({uri:de(t),name:t,description:`loveui registry definition for ${t}`,mimeType:"application/json"})),readResource:async s=>{if(!s.startsWith(S))throw new Error(`Unsupported resource URI: ${s}`);let t=s.slice(S.length),n=await E(t);return{contents:[{uri:s,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}}),e.addTool({name:"get-loveui-package",description:"Fetch a loveui registry definition by package name.",inputSchema:{type:"object",additionalProperties:!1,properties:{name:{type:"string",description:"Package name, e.g. badge"}},required:["name"]},handler:async s=>{let t=s?.name;if(typeof t!="string"||t.trim()==="")throw new Error("Package name is required.");let n=await E(t);return{content:[{type:"text",text:JSON.stringify(n,null,2)}]}}}),await e.start()}ue().catch(e=>{console.error(e),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "love-ui",
3
- "version": "1.2.7",
3
+ "version": "1.2.9",
4
4
  "private": false,
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "type": "module",
@@ -0,0 +1,62 @@
1
+ # @loveui/code-blocks
2
+
3
+ React code-block components for LoveUI.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @loveui/code-blocks
9
+ ```
10
+
11
+ ## Required Styles
12
+
13
+ Import your project styles and at least one highlighter stylesheet.
14
+
15
+ ```css
16
+ @import "@loveui/code-blocks/styles/globals.css";
17
+ @import "@loveui/code-blocks/styles/shiki.css";
18
+ /* or */
19
+ @import "@loveui/code-blocks/styles/sugar-high.css";
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```tsx
25
+ import {
26
+ CodeBlock,
27
+ CodeBlockHeader,
28
+ CodeBlockContent,
29
+ CodeBlockGroup,
30
+ CodeBlockIcon,
31
+ CopyButton,
32
+ CodeblockShiki,
33
+ } from "@loveui/code-blocks";
34
+
35
+ const code = "console.log('LoveUI');";
36
+
37
+ export function Example() {
38
+ return (
39
+ <CodeBlock>
40
+ <CodeBlockHeader>
41
+ <CodeBlockGroup>
42
+ <CodeBlockIcon language="ts" />
43
+ <span>example.ts</span>
44
+ </CodeBlockGroup>
45
+ <CopyButton content={code} />
46
+ </CodeBlockHeader>
47
+ <CodeBlockContent>
48
+ <CodeblockShiki code={code} language="ts" />
49
+ </CodeBlockContent>
50
+ </CodeBlock>
51
+ );
52
+ }
53
+ ```
54
+
55
+ ## Exports
56
+
57
+ - Code block primitives: `CodeBlock`, `CodeBlockHeader`, `CodeBlockContent`, `CodeBlockGroup`, `CodeBlockIcon`
58
+ - Highlighters: `CodeblockShiki`, `CodeBlockSugarHigh`
59
+ - MDX helpers: `PreShikiComponent`, `PreSugarHighComponent`
60
+ - Blocks: `InlineCode`, `MultiTabs`, `CodeBlockSelectPkg`, `CodeBlockTabsPkg`
61
+ - Utilities: `cn`, `copyToClipboard`, `reactToText`, `highlight`, `sugarHighHighlight`
62
+ - Store: `usePackageManager`
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "src/styles/globals.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": false,
11
+ "prefix": ""
12
+ },
13
+ "iconLibrary": "lucide",
14
+ "aliases": {
15
+ "components": "@/components",
16
+ "utils": "@/utils",
17
+ "ui": "@/components/ui",
18
+ "lib": "@/lib",
19
+ "hooks": "@/hooks"
20
+ }
21
+ }
@@ -1,28 +1,52 @@
1
1
  {
2
- "name": "@loveui/code-block",
3
- "description": "Provides syntax highlighting, line numbers, and copy to clipboard functionality for code blocks.",
2
+ "name": "@loveui/code-blocks",
4
3
  "version": "0.1.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "files": [
7
+ "src",
8
+ "components.json",
9
+ "README.md"
10
+ ],
11
+ "sideEffects": [
12
+ "**/*.css"
13
+ ],
14
+ "exports": {
15
+ ".": "./src/index.ts",
16
+ "./components/*": "./src/components/*",
17
+ "./utils/*": "./src/utils/*",
18
+ "./stores/*": "./src/stores/*",
19
+ "./styles/globals.css": "./src/styles/globals.css",
20
+ "./styles/shiki.css": "./src/styles/shiki.css",
21
+ "./styles/sugar-high.css": "./src/styles/sugar-high.css",
22
+ "./components.json": "./components.json"
23
+ },
24
+ "scripts": {
25
+ "check-types": "tsc --noEmit"
26
+ },
5
27
  "dependencies": {
6
- "@radix-ui/react-use-controllable-state": "^1.2.2",
7
- "@loveui/shadcn-ui": "^0.1.0",
8
- "@shikijs/transformers": "^3.13.0",
9
- "lucide-react": "^0.545.0",
10
- "react": "^19.2.0",
11
- "react-dom": "^19.2.0",
12
- "react-icons": "^5.5.0",
13
- "shiki": "3.13.0"
28
+ "@base-ui/react": "1.1.0",
29
+ "@react-symbols/icons": "1.3.0",
30
+ "@shikijs/langs": "3.22.0",
31
+ "@shikijs/themes": "3.22.0",
32
+ "class-variance-authority": "0.7.1",
33
+ "clsx": "2.1.1",
34
+ "lucide-react": "0.563.0",
35
+ "shiki": "3.22.0",
36
+ "sugar-high": "0.9.5",
37
+ "tailwind-merge": "3.4.0",
38
+ "tw-animate-css": "1.4.0",
39
+ "zustand": "5.0.11"
14
40
  },
15
- "devDependencies": {
16
- "@loveui/typescript-config": "^0.1.0",
17
- "@types/react": "^19.2.2",
18
- "@types/react-dom": "^19.2.1",
19
- "typescript": "^5.9.3"
41
+ "peerDependencies": {
42
+ "react": ">=18",
43
+ "react-dom": ">=18",
44
+ "tailwindcss": ">=4"
20
45
  },
21
- "files": [
22
- "dist",
23
- "*.ts",
24
- "*.tsx",
25
- "*.css",
26
- "*.mdx"
27
- ]
46
+ "devDependencies": {
47
+ "@types/mdx": "2.0.13",
48
+ "@types/react": "19.2.10",
49
+ "@types/react-dom": "19.2.3",
50
+ "typescript": "5.9.3"
51
+ }
28
52
  }
@@ -0,0 +1,146 @@
1
+ "use client";
2
+
3
+ import { useState, type FC, type SVGProps } from "react";
4
+ import {
5
+ usePackageManager,
6
+ type PackageManager,
7
+ } from "../../../stores/packageManager";
8
+
9
+ import {
10
+ CodeBlock,
11
+ CodeBlockContent,
12
+ CodeBlockHeader,
13
+ CodeBlockIcon,
14
+ } from "../code-block";
15
+ import { CopyButton } from "../copy-button";
16
+ import { CodeblockShiki } from "../client/shiki";
17
+
18
+ import {
19
+ DropdownMenu,
20
+ DropdownMenuContent,
21
+ DropdownMenuItem,
22
+ DropdownMenuTrigger,
23
+ } from "../../ui/dropdown-menu";
24
+
25
+ import { cn } from "../../../utils/cn";
26
+ import { Bun, NPM, PNPM, Yarn } from "@react-symbols/icons";
27
+ import { CheckIcon, ChevronDownIcon } from "lucide-react";
28
+
29
+ interface CodeBlockSelectPkgProps {
30
+ command: string;
31
+ title: string;
32
+ type: "install" | "dlx";
33
+ }
34
+
35
+ interface Command {
36
+ name: PackageManager;
37
+ install: string;
38
+ icon: FC<SVGProps<SVGSVGElement>>;
39
+ dlx: string;
40
+ }
41
+
42
+ const Commands: Command[] = [
43
+ {
44
+ name: "npm",
45
+ install: "npm i",
46
+ icon: NPM,
47
+ dlx: "npx",
48
+ },
49
+ {
50
+ name: "pnpm",
51
+ install: "pnpm i",
52
+ icon: PNPM,
53
+ dlx: "pnpm dlx",
54
+ },
55
+ {
56
+ name: "yarn",
57
+ install: "yarn add",
58
+ icon: Yarn,
59
+ dlx: "yarn dlx",
60
+ },
61
+ {
62
+ name: "bun",
63
+ install: "bun add",
64
+ icon: Bun,
65
+ dlx: "bunx --bun",
66
+ },
67
+ ];
68
+
69
+ const SelectPackageManager = () => {
70
+ const [isOpen, setIsOpen] = useState(false);
71
+ const { packageManager, setPackageManager } = usePackageManager();
72
+
73
+ const selectedPkg =
74
+ Commands.find((pkg) => pkg.name === packageManager) ?? Commands[0];
75
+ const Icon = selectedPkg.icon;
76
+
77
+ return (
78
+ <DropdownMenu open={isOpen} onOpenChange={setIsOpen}>
79
+ <DropdownMenuTrigger
80
+ title="Select Package Manager"
81
+ className="group flex cursor-pointer items-center space-x-1 px-2"
82
+ >
83
+ <Icon className="size-4" />
84
+ <ChevronDownIcon
85
+ size={13}
86
+ className={cn(
87
+ "transform transition-transform duration-200 ease-in-out",
88
+ "group-hover:text-black dark:group-hover:text-white",
89
+ isOpen && "rotate-180 text-black dark:text-white",
90
+ )}
91
+ />
92
+ </DropdownMenuTrigger>
93
+ <DropdownMenuContent align="end" alignOffset={2}>
94
+ {Commands.map((pkg) => {
95
+ const PkgIcon = pkg.icon;
96
+ return (
97
+ <DropdownMenuItem
98
+ key={pkg.name}
99
+ title={`Using ${pkg.name}`}
100
+ onClick={() => setPackageManager(pkg.name)}
101
+ className="flex w-full items-center justify-between"
102
+ >
103
+ <div className="flex items-center space-x-2">
104
+ <PkgIcon className="size-4" />
105
+ <span>{pkg.name}</span>
106
+ </div>
107
+ {selectedPkg.name === pkg.name && <CheckIcon width={14} />}
108
+ </DropdownMenuItem>
109
+ );
110
+ })}
111
+ </DropdownMenuContent>
112
+ </DropdownMenu>
113
+ );
114
+ };
115
+
116
+ const CodeBlockSelectPkg = ({
117
+ title,
118
+ type,
119
+ command,
120
+ }: CodeBlockSelectPkgProps) => {
121
+ const { packageManager } = usePackageManager();
122
+
123
+ const selectedPkg =
124
+ Commands.find((pkg) => pkg.name === packageManager) ?? Commands[0];
125
+ const fullCommand = `${selectedPkg[type]} ${command}`;
126
+
127
+ return (
128
+ <CodeBlock>
129
+ <CodeBlockHeader>
130
+ <div className="flex items-center space-x-2">
131
+ <CodeBlockIcon language="bash" />
132
+ <span className="font-medium">{title}</span>
133
+ </div>
134
+ <div className="flex items-center space-x-2 divide-x divide-neutral-300 dark:divide-neutral-700">
135
+ <SelectPackageManager />
136
+ <CopyButton className="pl-1" content={fullCommand} />
137
+ </div>
138
+ </CodeBlockHeader>
139
+ <CodeBlockContent>
140
+ <CodeblockShiki language="bash" code={fullCommand} />
141
+ </CodeBlockContent>
142
+ </CodeBlock>
143
+ );
144
+ };
145
+
146
+ export { CodeBlockSelectPkg, SelectPackageManager };
@@ -0,0 +1,110 @@
1
+ "use client";
2
+
3
+ import type { FC, SVGProps } from "react";
4
+ import {
5
+ usePackageManager,
6
+ type PackageManager,
7
+ } from "../../../stores/packageManager";
8
+
9
+ import {
10
+ CodeBlock,
11
+ CodeBlockContent,
12
+ CodeBlockHeader,
13
+ CodeBlockIcon,
14
+ } from "../code-block";
15
+ import { CopyButton } from "../copy-button";
16
+ import { CodeblockShiki } from "../client/shiki";
17
+
18
+ import { Bun, NPM, PNPM, Yarn } from "@react-symbols/icons";
19
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../ui/tabs";
20
+
21
+ interface Command {
22
+ name: PackageManager;
23
+ install: string;
24
+ icon: FC<SVGProps<SVGSVGElement>>;
25
+ dlx: string;
26
+ }
27
+
28
+ interface CodeBlockTabsPkgProps {
29
+ command: string;
30
+ type: "install" | "dlx";
31
+ }
32
+
33
+ const Commands: Command[] = [
34
+ {
35
+ name: "npm",
36
+ install: "npm i",
37
+ icon: NPM,
38
+ dlx: "npx",
39
+ },
40
+ {
41
+ name: "pnpm",
42
+ install: "pnpm i",
43
+ icon: PNPM,
44
+ dlx: "pnpm dlx",
45
+ },
46
+ {
47
+ name: "yarn",
48
+ install: "yarn add",
49
+ icon: Yarn,
50
+ dlx: "yarn dlx",
51
+ },
52
+ {
53
+ name: "bun",
54
+ install: "bun add",
55
+ icon: Bun,
56
+ dlx: "bunx --bun",
57
+ },
58
+ ];
59
+
60
+ const CodeBlockTabsPkg = ({ command, type }: CodeBlockTabsPkgProps) => {
61
+ const { packageManager, setPackageManager } = usePackageManager();
62
+
63
+ const selectedPkg =
64
+ Commands.find((pkg) => pkg.name === packageManager) ?? Commands[0];
65
+ const fullCommand = `${selectedPkg[type]} ${command}`;
66
+
67
+ return (
68
+ <Tabs
69
+ className="w-full gap-1"
70
+ value={packageManager}
71
+ onValueChange={(value) => setPackageManager(value as PackageManager)}
72
+ >
73
+ <CodeBlock>
74
+ <CodeBlockHeader>
75
+ <div className="flex items-center space-x-1">
76
+ <CodeBlockIcon language="bash" />
77
+ <TabsList className="gap-1 border-0 bg-transparent dark:bg-transparent">
78
+ {Commands.map((cmd) => {
79
+ const Icon = cmd.icon;
80
+ return (
81
+ <TabsTrigger
82
+ key={cmd.name}
83
+ value={cmd.name}
84
+ className="data-[state=active]:shadow-none"
85
+ >
86
+ <Icon className="size-4" />
87
+ <span>{cmd.name}</span>
88
+ </TabsTrigger>
89
+ );
90
+ })}
91
+ </TabsList>
92
+ </div>
93
+ <CopyButton className="pl-1" content={fullCommand} />
94
+ </CodeBlockHeader>
95
+ <CodeBlockContent>
96
+ {Commands.map((cmd) => (
97
+ <TabsContent key={cmd.name} value={cmd.name} className="mt-0">
98
+ <CodeblockShiki
99
+ language="bash"
100
+ code={`${cmd[type]} ${command}`}
101
+ />
102
+ </TabsContent>
103
+ ))}
104
+ </CodeBlockContent>
105
+ </CodeBlock>
106
+ </Tabs>
107
+ );
108
+ };
109
+
110
+ export { CodeBlockTabsPkg };
@@ -0,0 +1,28 @@
1
+ "use client";
2
+
3
+ import type { Languages } from "../../../utils/shiki/highlight";
4
+
5
+ import {
6
+ CodeBlock,
7
+ CodeBlockContent,
8
+ } from "../code-block";
9
+ import { CopyButton } from "../copy-button";
10
+ import { CodeblockShiki } from "../client/shiki";
11
+
12
+ interface InlineCodeProps {
13
+ code: string;
14
+ language?: Languages;
15
+ }
16
+
17
+ const InlineCode = ({ code, language = "bash" }: InlineCodeProps) => {
18
+ return (
19
+ <CodeBlock>
20
+ <CodeBlockContent className="flex w-full items-center justify-between">
21
+ <CodeblockShiki language={language} code={code} />
22
+ <CopyButton className="px-3" content={code} />
23
+ </CodeBlockContent>
24
+ </CodeBlock>
25
+ );
26
+ };
27
+
28
+ export default InlineCode;