Procházet zdrojové kódy

Merge branch 'main' into tony/navigation-update

Tony Boyle před 11 měsíci
rodič
revize
df7180b5e5
78 změnil soubory, kde provedl 4900 přidání a 2342 odebrání
  1. 8 2
      markdoc/tags.js
  2. 13 13
      package.json
  3. 511 2308
      pnpm-lock.yaml
  4. binární
      public/images/hybrid-ui-template-image.jpg
  5. 12 5
      src/components/Fence.jsx
  6. 0 1
      src/components/Layout.jsx
  7. 208 0
      src/components/apiComponents/apiComponentWrapper.jsx
  8. 223 0
      src/components/apiComponents/apiParams.jsx
  9. 111 0
      src/components/apiComponents/endPointSelector.jsx
  10. 57 0
      src/components/apiComponents/exampleSelector.jsx
  11. 61 0
      src/components/apiComponents/languageComponents/cSharpRenderer.jsx
  12. 42 0
      src/components/apiComponents/languageComponents/curlRequestRenderer.jsx
  13. 101 0
      src/components/apiComponents/languageComponents/goRequestRenderer.jsx
  14. 95 0
      src/components/apiComponents/languageComponents/javaRenderer.jsx
  15. 45 0
      src/components/apiComponents/languageComponents/javascriptRequestRenderer.jsx
  16. 59 0
      src/components/apiComponents/languageComponents/kotlinRenderer.jsx
  17. 81 0
      src/components/apiComponents/languageComponents/phpRenderer.jsx
  18. 60 0
      src/components/apiComponents/languageComponents/pythonRequestRenderer.jsx
  19. 50 0
      src/components/apiComponents/languageComponents/rubyRenderer.jsx
  20. 52 0
      src/components/apiComponents/languageComponents/rustRenderer.jsx
  21. 58 0
      src/components/apiComponents/languageComponents/swiftRenderer.jsx
  22. 0 0
      src/components/apiComponents/languageComponents/umiRequestRenderer.jsx
  23. 220 0
      src/components/apiComponents/languageRenderer.jsx
  24. 43 0
      src/components/apiComponents/languageSelector.jsx
  25. 14 0
      src/components/apiComponents/responce.jsx
  26. 27 5
      src/components/icons/index.jsx
  27. 12 0
      src/components/icons/languages/CSharpIcon.jsx
  28. 10 0
      src/components/icons/languages/CurlIcon.jsx
  29. 19 0
      src/components/icons/languages/GoIcon.jsx
  30. 14 0
      src/components/icons/languages/JavaIcon.jsx
  31. 0 0
      src/components/icons/languages/JavaScriptIcon.jsx
  32. 14 0
      src/components/icons/languages/KotlinIcon.jsx
  33. 14 0
      src/components/icons/languages/PhpIcon.jsx
  34. 14 0
      src/components/icons/languages/PythonIcon.jsx
  35. 10 0
      src/components/icons/languages/RubyIcon.jsx
  36. 10 0
      src/components/icons/languages/RustIcon.jsx
  37. 10 0
      src/components/icons/languages/ShellIcon.jsx
  38. 10 0
      src/components/icons/languages/SwiftIcon.jsx
  39. 14 0
      src/components/icons/languages/TypescriptIcon.jsx
  40. 5 0
      src/components/icons/spinner.jsx
  41. 51 0
      src/components/products/aura/index.js
  42. 1 0
      src/components/products/candyMachine/index.js
  43. 6 0
      src/components/products/guides/index.js
  44. 11 0
      src/components/products/mpl-hybrid/index.js
  45. 51 0
      src/lib/api/aura/das/getAssestByAuthority.js
  46. 184 0
      src/lib/api/aura/das/getAsset.js
  47. 357 0
      src/lib/api/aura/das/getAssetBatch.js
  48. 54 0
      src/lib/api/aura/das/getAssetProof.js
  49. 17 0
      src/lib/api/aura/das/getAssetProofBatch.js
  50. 57 0
      src/lib/api/aura/das/getAssetsByCreator.js
  51. 59 0
      src/lib/api/aura/das/getAssetsByGroup.js
  52. 51 0
      src/lib/api/aura/das/getAssetsByOwner.js
  53. 169 0
      src/lib/api/aura/das/getSignaturesForAsset.js
  54. 55 0
      src/lib/api/aura/das/getTokenAccounts.js
  55. 161 0
      src/lib/api/aura/das/searchAssest.js
  56. 30 0
      src/lib/api/aura/methods.js
  57. 55 0
      src/lib/api/aura/template.js
  58. 23 0
      src/lib/api/renderRequestBody.js
  59. 35 0
      src/lib/api/template.js
  60. 10 0
      src/pages/aura/api/v1/das/get-asset-batch.md
  61. 9 0
      src/pages/aura/api/v1/das/get-asset-proof-batch.md
  62. 10 0
      src/pages/aura/api/v1/das/get-asset-proof.md
  63. 9 0
      src/pages/aura/api/v1/das/get-asset.md
  64. 10 0
      src/pages/aura/api/v1/das/get-assets-by-authority.md
  65. 10 0
      src/pages/aura/api/v1/das/get-assets-by-creator.md
  66. 9 0
      src/pages/aura/api/v1/das/get-assets-by-group.md
  67. 9 0
      src/pages/aura/api/v1/das/get-assets-by-owner.md
  68. 9 0
      src/pages/aura/api/v1/das/get-signatures-for-asset.md
  69. 9 0
      src/pages/aura/api/v1/das/get-token-accounts.md
  70. 9 0
      src/pages/aura/api/v1/das/search-assets.md
  71. 8 0
      src/pages/aura/api/v1/testApiMethod.md
  72. 5 5
      src/pages/candy-machine/guards.md
  73. 468 0
      src/pages/candy-machine/guides/airdrop-mint-to-another-wallet.md
  74. 4 2
      src/pages/candy-machine/guides/index.md
  75. 463 0
      src/pages/candy-machine/guides/mint-to-another-wallet.md
  76. 3 1
      src/pages/candy-machine/mint.md
  77. 88 0
      src/pages/mpl-hybrid/guides/mpl-404-hyrbid-ui-template.md
  78. 24 0
      src/styles/extra.css

+ 8 - 2
markdoc/tags.js

@@ -8,6 +8,7 @@ import Image from '@/components/Image'
 import { QuickLink, QuickLinks } from '@/components/QuickLinks'
 import { Seperator } from '@/components/Seperator'
 import { Totem, TotemAccordion, TotemProse } from '@/components/Totem'
+import ApiComponentWrapper from '@/components/apiComponents/apiComponentWrapper'
 import {
   Diagram,
   transformDiagramTag,
@@ -17,7 +18,6 @@ import { PackagesUsed } from '@/components/helperComponents/packagesUsed'
 import { MarkdocGrid as ProductGrid } from '@/components/products/Grid'
 import { MarkdocGrid as AllProductsGrid } from '@/components/products/GridAllProducts'
 
-
 const tags = {
   callout: {
     attributes: {
@@ -58,7 +58,7 @@ const tags = {
       description: { type: String },
       icon: { type: String },
       href: { type: String },
-      target: { type: String }
+      target: { type: String },
     },
   },
   'product-grid': {
@@ -162,6 +162,12 @@ const tags = {
     },
     selfClosing: true,
   },
+  apiRenderer: {
+    attributes: {
+      method: { type: String },
+    },
+    render: ApiComponentWrapper,
+  },
 }
 
 export default tags

+ 13 - 13
package.json

@@ -11,35 +11,35 @@
   },
   "browserslist": "defaults, not ie <= 11",
   "dependencies": {
-    "@docsearch/react": "^3.2.1",
-    "@headlessui/react": "^1.7.13",
-    "@heroicons/react": "^2.0.18",
+    "@docsearch/react": "^3.8.0",
+    "@headlessui/react": "2.2.0",
+    "@heroicons/react": "^2.2.0",
     "@hotjar/browser": "^1.0.9",
     "@markdoc/markdoc": "0.3.0",
     "@markdoc/next.js": "0.2.3",
-    "@sindresorhus/slugify": "^2.1.0",
-    "@tailwindcss/typography": "^0.5.7",
-    "autoprefixer": "^10.4.12",
+    "@sindresorhus/slugify": "^2.2.1",
+    "@tailwindcss/typography": "^0.5.15",
+    "autoprefixer": "^10.4.20",
     "clsx": "^1.2.1",
-    "focus-visible": "^5.2.0",
+    "focus-visible": "^5.2.1",
     "html-to-image": "^1.11.11",
     "lightense-images": "^1.0.17",
-    "next": "13.3.0",
+    "next": "13.4.7",
     "postcss-focus-visible": "^6.0.4",
     "postcss-import": "^14.1.0",
     "prism-react-renderer": "^1.3.5",
     "prismjs": "^1.29.0",
     "react": "18.2.0",
     "react-dom": "18.2.0",
-    "reactflow": "^11.7.2",
-    "tailwindcss": "^3.3.0"
+    "reactflow": "^11.11.4",
+    "tailwindcss": "^3.4.16"
   },
   "devDependencies": {
     "eslint": "8.26.0",
     "eslint-config-next": "13.0.2",
-    "prettier": "^2.8.7",
-    "prettier-plugin-tailwindcss": "^0.2.6",
-    "sharp": "^0.32.0"
+    "prettier": "^2.8.8",
+    "prettier-plugin-tailwindcss": "^0.2.8",
+    "sharp": "^0.32.6"
   },
   "packageManager": "pnpm@9.1.4+sha512.9df9cf27c91715646c7d675d1c9c8e41f6fce88246f1318c1aa6a1ed1aeb3c4f032fcdf4ba63cc69c4fe6d634279176b5358727d8f2cc1e65b65f43ce2f8bfb0"
 }

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 511 - 2308
pnpm-lock.yaml


binární
public/images/hybrid-ui-template-image.jpg


+ 12 - 5
src/components/Fence.jsx

@@ -1,6 +1,13 @@
-import Highlight, { defaultProps } from 'prism-react-renderer'
-import { Fragment } from 'react'
-import CopyToClipboardButton from './products/CopyToClipboard'
+import Highlight, { defaultProps } from 'prism-react-renderer';
+import { Fragment } from 'react';
+import CopyToClipboardButton from './products/CopyToClipboard';
+(typeof global !== 'undefined' ? global : window).Prism = Prism
+
+require('prismjs/components/prism-kotlin')
+require('prismjs/components/prism-csharp')
+require('prismjs/components/prism-java')
+require('prismjs/components/prism-php')
+require('prismjs/components/prism-ruby')
 
 export function Fence({ children, language }) {
   return (
@@ -11,9 +18,9 @@ export function Fence({ children, language }) {
       theme={undefined}
     >
       {({ className, style, tokens, getTokenProps }) => (
-        <pre className={className + ' relative scrollbar '} style={style}>
+        <pre className={className + ' scrollbar relative '} style={style}>
           <CopyToClipboardButton text={children} />
-          <code className='w-[calc(100%-25px)] block overflow-auto '>
+          <code className="block w-[calc(100%-25px)] overflow-auto ">
             {tokens.map((line, lineIndex) => (
               <Fragment key={lineIndex}>
                 {line

+ 0 - 1
src/components/Layout.jsx

@@ -33,7 +33,6 @@ export function Layout({ children, page }) {
       <div
         className={clsx(
           'relative mx-auto flex justify-center sm:px-2 lg:px-8 xl:px-12'
-          // hasNavigation ? 'max-w-8xl' : 'max-w-6xl'
         )}
       >
         {/* Navigation. */}

+ 208 - 0
src/components/apiComponents/apiComponentWrapper.jsx

@@ -0,0 +1,208 @@
+'use client'
+
+import apiMethods from '@/lib/api/aura/methods'
+import { useEffect, useState } from 'react'
+import { Fence } from '../Fence'
+import Spinner from '../icons/spinner'
+import { Totem, TotemAccordion } from '../Totem'
+import ApiParameterDisplay from './apiParams'
+import { endpoints } from './endPointSelector'
+import ApiExampleSelector from './exampleSelector'
+import LanguageRenderer from './languageRenderer'
+import Responce from './responce'
+
+const ApiComponentWrapper = (args) => {
+  const api = apiMethods[args.method]
+
+  const [screenWidth, setScreenWidth] = useState(null)
+  const [responce, setResponce] = useState(null)
+  const [isLoading, setIsLoading] = useState(false)
+  const [selectedExample, setSelectedExample] = useState(-1)
+  const [activeEndpoint, setActiveEndpoint] = useState(endpoints.solanaMainnet)
+
+  const handleSetExample = (index) => {
+    if (index == -1) {
+      setBody((prev) => {
+        let newBody = { ...prev }
+        newBody.params = {}
+        return newBody
+      })
+      setSelectedExample(index)
+      return
+    }
+
+    setBody((prev) => {
+      let newBody = { ...prev }
+      newBody.params = api.examples[index].body.params
+      return newBody
+    })
+
+    setSelectedExample(index)
+    if (activeEndpoint.name !== 'Custom') {
+      console.log(activeEndpoint)
+      console.log(api.examples[index])
+      setActiveEndpoint(endpoints[api.examples[index].chain])
+    }
+  }
+
+  const [body, setBody] = useState({
+    jsonrpc: '2.0',
+    id: '1',
+    method: api.method,
+    params: {},
+  })
+
+  // Track screen width on resize (client-side only)
+  useEffect(() => {
+    const handleResize = () => {
+      setScreenWidth(window.innerWidth)
+    }
+
+    // Set the initial screen width when the component mounts
+    if (screenWidth === null) {
+      setScreenWidth(window.innerWidth)
+    }
+
+    window.addEventListener('resize', handleResize)
+
+    return () => window.removeEventListener('resize', handleResize)
+  }, [screenWidth])
+
+  if (screenWidth === null) {
+    return null
+  }
+
+  const isLargeScreen = screenWidth >= 1536 // 2xl breakpoint
+
+  const handleSetParam = (path, value) => {
+    setBody((prev) => {
+      const newBody = { ...prev }
+
+      // Recursive function to traverse and update or clean up fields
+      const updateField = (obj, path) => {
+        const key = path[0]
+
+        if (path.length === 1) {
+          // If we are at the target field
+          if (
+            !value ||
+            (Array.isArray(value) && value.every((v) => v === ''))
+          ) {
+            // Delete the field if value is null, undefined, or an empty key-value pair
+            delete obj[key]
+          } else {
+            // Otherwise, set the value
+            obj[key] = value
+          }
+        } else {
+          // Ensure the parent key exists and is an object
+          if (!obj[key] || typeof obj[key] !== 'object') {
+            obj[key] = {}
+          }
+
+          // Recurse into the nested object
+          updateField(obj[key], path.slice(1))
+
+          // Remove the parent key if it becomes empty after the update
+          if (Object.keys(obj[key]).length === 0) {
+            delete obj[key]
+          }
+        }
+      }
+
+      updateField(newBody.params, path)
+
+      return newBody
+    })
+  }
+
+  const handleTryItOut = async () => {
+    setResponce(null)
+    setIsLoading(true)
+
+    const res = await fetch(activeEndpoint.uri, {
+      method: 'POST',
+      headers: {
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify(body),
+    })
+
+    const resJson = await res.json()
+
+    console.log(resJson)
+
+    setResponce(resJson)
+
+    setIsLoading(false)
+  }
+
+  return (
+    <div>
+      <div className="flex w-full flex-col-reverse gap-8 2xl:flex-row ">
+        <div className="flex w-full flex-col gap-8 2xl:w-1/2">
+          {api.examples && isLargeScreen && (
+            <ApiExampleSelector
+              examples={api.examples}
+              selectedExample={selectedExample}
+              handleSetExample={(index) => handleSetExample(index)}
+            />
+          )}
+
+          <ApiParameterDisplay
+            params={api.params}
+            body={body.params}
+            setParam={(path, value) => {
+              handleSetParam(path, value)
+            }}
+          />
+          <button
+            className="block min-w-[150px] rounded-lg border border-gray-200 px-4 py-3 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-300 dark:placeholder-neutral-500 2xl:hidden"
+            onClick={handleTryItOut}
+          >
+            {isLoading ? <Spinner className="h-6 w-6" /> : 'Try it out'}
+          </button>
+          {responce && !isLargeScreen && <Responce responce={responce} />}
+        </div>
+
+        <div className="flex w-full flex-col items-end gap-4 2xl:w-1/2">
+          {api.examples && !isLargeScreen && (
+            <ApiExampleSelector
+              examples={api.examples}
+              selectedExample={selectedExample}
+              handleSetExample={(index) => handleSetExample(index)}
+            />
+          )}
+          <LanguageRenderer
+            api={api}
+            body={body}
+            activeEndPoint={activeEndpoint}
+            setActiveEndPoint={(endpoint) => setActiveEndpoint(endpoint)}
+          />
+          <button
+            className="hidden min-w-[150px] items-center justify-center rounded-lg border border-gray-200 px-4 py-3 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-300 dark:placeholder-neutral-500 2xl:flex"
+            onClick={handleTryItOut}
+          >
+            {isLoading ? <Spinner className="h-6 w-6" /> : 'Try it out'}
+          </button>
+          {responce && isLargeScreen && <Responce responce={responce} />}
+        </div>
+      </div>
+
+      {api.exampleResponse && (
+        <>
+          <hr className="my-8 border-gray-200 dark:border-neutral-700" />
+          <Totem className="w-full">
+            <TotemAccordion title="Example Response">
+              <Fence className="w-full" language="python">
+                {JSON.stringify(api.exampleResponse, null, 2)}
+              </Fence>
+            </TotemAccordion>
+          </Totem>
+        </>
+      )}
+    </div>
+  )
+}
+
+export default ApiComponentWrapper

+ 223 - 0
src/components/apiComponents/apiParams.jsx

@@ -0,0 +1,223 @@
+import { Select } from '@headlessui/react'
+import { ChevronDownIcon } from '@heroicons/react/20/solid'
+import { TrashIcon } from '@heroicons/react/24/outline'
+import { PlusIcon } from '@heroicons/react/24/solid'
+import clsx from 'clsx'
+import { PluginsIcon } from '../icons/dual-tone/PluginsIcon'
+
+// Recursive component for rendering nested parameters
+const ParamRenderer = ({ param, subValue, setParam, path = [], value }) => {
+  let content
+
+  switch (param.type) {
+    case 'string':
+      content = (
+        <input
+          name={param.name}
+          type="text"
+          className="block w-full rounded-md border border-gray-200 px-2 py-1 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900/50 dark:text-neutral-300 dark:placeholder-neutral-500"
+          placeholder={param.placeholder}
+          onChange={(e) => setParam(path, e.target.value)}
+          value={value || ''}
+        />
+      )
+      break
+
+    case 'number':
+      content = (
+        <input
+          name={param.name}
+          type="number"
+          className="block w-full rounded-md border border-gray-200 px-2 py-1 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900/50 dark:text-neutral-300 dark:placeholder-neutral-500"
+          placeholder={param.value}
+          onChange={(e) => setParam(path, Number.parseInt(e.target.value))}
+          value={value || ''}
+        />
+      )
+      break
+
+    case 'object':
+      content = (
+        <div className="-mx-3 ml-2 mt-1 flex flex-col">
+          {Object.entries(param.value).map(([key, value]) => (
+            <ParamRenderer
+              path={[...path, key]}
+              key={key}
+              param={{ name: key, ...value, subValue: true }}
+              subValue={true}
+              setParam={(path, value) => setParam(path, value)}
+            />
+          ))}
+        </div>
+      )
+      break
+
+    case 'array':
+      content = (
+        <div className="m-0 flex flex-col gap-2">
+          {param.value.map((item, index) => (
+            <div key={index} className="flex gap-2">
+              <input
+                className="block w-full rounded-md border border-gray-200 px-2 py-2 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900/50 dark:text-neutral-300 dark:placeholder-neutral-500"
+                placeholder={param.placeHolder}
+                onChange={(e) => {
+                  const newValue = param.value
+                  newValue[index] = e.target.value
+                  setParam(path, newValue)
+                }}
+                value={item}
+              />
+              <TrashIcon
+                className=" h-6 w-6 cursor-pointer self-center text-gray-500 dark:text-neutral-400"
+                onClick={() => {
+                  const newValue = param.value
+                  newValue.splice(index, 1)
+                  setParam(path, newValue)
+                }}
+              />
+            </div>
+          ))}
+          <PlusIcon
+            className=" h-6 w-6 cursor-pointer self-end text-gray-500 dark:text-neutral-400"
+            onClick={() => {
+              // add item to array
+              const newValue = param.value
+              newValue.push('')
+              setParam(path, newValue)
+            }}
+          />
+        </div>
+      )
+      break
+
+    case 'boolean':
+      content = (
+        <div className="relative flex h-10 w-full">
+          <Select
+            onChange={(e) =>
+              setParam(path, e.target.value === 'true' ? true : false)
+            }
+            className={clsx(
+              'dark:white block w-full appearance-none rounded-lg border border-black/10 bg-white/5 px-3 py-1.5 text-sm/6 text-black dark:border-white/15 dark:bg-transparent',
+              'focus:outline-none data-[focus]:outline-2 data-[focus]:-outline-offset-2 data-[focus]:outline-white/25',
+              '*:text-black dark:text-white'
+            )}
+          >
+            {!param.required && <option value={''} />}
+            <option value="true">true</option>
+            <option value="false">false</option>
+          </Select>
+          <ChevronDownIcon
+            className="group pointer-events-none absolute right-2.5 top-3 my-auto size-4 fill-black/60 dark:fill-white"
+            aria-hidden="true"
+          />
+        </div>
+      )
+      break
+    case 'option':
+      content = (
+        <div className="relative flex h-10 w-full">
+          <Select
+            onChange={(e) => setParam(path, e.target.value)}
+            className={clsx(
+              'dark:white block w-full appearance-none rounded-lg border border-black/10 bg-white/5 px-3 py-1.5 text-sm/6 text-black dark:border-white/15 dark:bg-transparent',
+              'focus:outline-none data-[focus]:outline-2 data-[focus]:-outline-offset-2 data-[focus]:outline-white/25',
+              '*:text-black dark:text-white'
+            )}
+          >
+            {!param.required && <option value={''} />}
+            {param.value.map((choice, index) => {
+              return (
+                <option key={index} value={choice}>
+                  {choice}
+                </option>
+              )
+            })}
+          </Select>
+          <ChevronDownIcon
+            className="group pointer-events-none absolute right-2.5 top-3 my-auto size-4 fill-black/60 dark:fill-white"
+            aria-hidden="true"
+          />
+        </div>
+      )
+      break
+    case 'arrayKeyValuePair':
+      content = (
+        <div div className="flex flex-col gap-2">
+          <input
+            name={`${param.name}-key`}
+            type="text"
+            className="block w-full rounded-md border border-gray-200 px-2 py-1 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900/50 dark:text-neutral-300 dark:placeholder-neutral-500"
+            placeholder={'key'}
+            onChange={(e) => {
+              const newValue = [e.target.value, value ? value[1] : '']
+              setParam(path, newValue)
+            }}
+            value={value ? value[0] : ''}
+          />
+          <input
+            name={`${param.name}-value`}
+            type="text"
+            className="block w-full rounded-md border border-gray-200 px-2 py-1 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900/50 dark:text-neutral-300 dark:placeholder-neutral-500"
+            placeholder={'value'}
+            onChange={(e) => {
+              const newValue = [value ? value[0] : '', e.target.value]
+              setParam(path, newValue)
+            }}
+            value={value ? value[1] : ''}
+          />
+        </div>
+      )
+      break
+
+    default:
+      content = <span className="text-sm">{String(param.value)}</span>
+  }
+
+  return (
+    <div
+      className={`${
+        !subValue && 'border-t border-gray-200 py-2 dark:border-neutral-700/50'
+      } ${param.type === 'object' ? '' : 'flex flex-col gap-2'}`}
+    >
+      <div className="px-3">
+        <label className="text-sm font-medium text-black dark:text-white">
+          {param.name}
+        </label>
+        <span className="ml-2 inline-block text-xs text-gray-500 dark:text-neutral-400">
+          {param.type}
+        </span>
+        {param.required && (
+          <span className="ml-2 inline-block text-xs text-red-500 dark:text-red-400">
+            required
+          </span>
+        )}
+      </div>
+      <div className="px-3 text-xs italic">{param.description}</div>
+      <div className="px-3 pb-2">{content}</div>
+    </div>
+  )
+}
+
+const ApiParameterDisplay = ({ params, setParam, body }) => {
+  return (
+    <div className="flex w-full flex-col gap-4 rounded-xl border border-gray-200 bg-white py-4 pb-0 dark:border-neutral-700/50 dark:bg-neutral-800/50">
+      <div className="px-3 text-xs font-semibold uppercase text-gray-500 dark:text-neutral-300">
+        Body Params
+      </div>
+      <div className="flex flex-col">
+        {params.map((param) => (
+          <ParamRenderer
+            value={body[param.name]}
+            path={[param.name]}
+            key={param.name}
+            param={param}
+            setParam={(path, value) => setParam(path, value)}
+          />
+        ))}
+      </div>
+    </div>
+  )
+}
+
+export default ApiParameterDisplay

+ 111 - 0
src/components/apiComponents/endPointSelector.jsx

@@ -0,0 +1,111 @@
+import { Select } from '@headlessui/react'
+import { ChevronDownIcon } from '@heroicons/react/20/solid'
+import clsx from 'clsx'
+import { useState } from 'react'
+
+export const endpoints = {
+  solanaMainnet: {
+    name: 'Solana Mainnet',
+    uri: 'https://aura-mainnet.metaplex.com',
+    value: 'solanaMainnet',
+  },
+  solanaDevnet: {
+    name: 'Solana Devnet',
+    uri: 'https://aura-devnet.metaplex.com',
+    value: 'solanaDevnet',
+  },
+  eclipseAuraMainnet: {
+    name: 'Eclipse Mainnet',
+    uri: 'https://aura-eclipse-mainnet.metaplex.com',
+    value: 'eclipseAuraMainnet',
+    value: 'eclipseAuraMainnet',
+  },
+  custom: {
+    name: 'Custom',
+    uri: '',
+    value: 'custom',
+  },
+}
+
+const EndPointSelector = ({ setActiveEndpoint, activeEndpoint }) => {
+  const [isCustom, setIsCustom] = useState(false)
+  const [customEndPoint, setCustomEndPoint] = useState('')
+
+  // read endpoint from local storage
+
+  const handleSelectEndpoint = (e) => {
+
+    if (e.target.name === 'selectEndPoint') {
+      if (e.target.value === 'custom') {
+        setIsCustom(true)
+        const endpoint = localStorage.getItem('customEndPoint') || ''
+
+        setActiveEndpoint({
+          name: 'Custom',
+          uri: endpoint,
+        })
+        setCustomEndPoint(endpoint)
+      } else {
+        setIsCustom(false)
+        setActiveEndpoint(endpoints[e.target.value])
+      }
+    }
+    if (e.target.name === 'customEndPoint') {
+      setActiveEndpoint({
+        name: 'Custom',
+        uri: e.target.value,
+      })
+      setCustomEndPoint(e.target.value)
+    }
+  }
+
+  return (
+    <div className="flex flex-col gap-2 px-1">
+      <label
+        className="text-sm font-medium text-gray-800 dark:text-neutral-400"
+        htmlFor="endPoint"
+      >
+        Endpoint
+      </label>
+      <div className="relative flex h-12 w-full">
+        <Select
+          id="endPoint"
+          name="selectEndPoint"
+          className={clsx(
+            'dark:white block w-full appearance-none rounded-lg border border-black/10 bg-white/5 px-3 py-1.5 text-sm/6 text-black dark:border-white/15 dark:bg-transparent',
+            'focus:outline-none data-[focus]:outline-2 data-[focus]:-outline-offset-2 data-[focus]:outline-white/25',
+            // Make the text of each option black on Windows
+            '*:text-black dark:text-white'
+          )}
+          onChange={(e) => handleSelectEndpoint(e)}
+          value={isCustom ? 'custom' : activeEndpoint.value}
+        >
+          {Object.entries(endpoints).map(([key, value]) => (
+            <option key={key} value={key}>
+              {value.name}
+            </option>
+          ))}
+        </Select>
+        <ChevronDownIcon
+          className="group pointer-events-none absolute right-2.5 top-4 my-auto size-4 fill-black/60 dark:fill-white"
+          aria-hidden="true"
+        />
+      </div>
+
+      <input
+        type="text"
+        name="customEndPoint"
+        placeholder="https://"
+        className="block w-full rounded-lg border border-gray-200 px-2 py-2 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-300 dark:placeholder-neutral-500"
+        onChange={(e) => {
+          handleSelectEndpoint(e)
+          localStorage.setItem('customEndPoint', e.target.value)
+        }}
+        disabled={!isCustom}
+        value={isCustom ? customEndPoint : activeEndpoint.uri}
+      />
+    </div>
+  )
+}
+
+export default EndPointSelector

+ 57 - 0
src/components/apiComponents/exampleSelector.jsx

@@ -0,0 +1,57 @@
+import { Select } from '@headlessui/react'
+import { ChevronDownIcon } from '@heroicons/react/20/solid'
+import clsx from 'clsx'
+
+const ApiExampleSelector = ({
+  examples,
+  selectedExample,
+  handleSetExample,
+}) => {
+  return (
+    <div className="w-full">
+      <label
+        className="mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400"
+        htmlFor="endPoint"
+      >
+        Example Queries
+      </label>
+      <div className="relative flex w-full gap-2">
+        <div className="relative flex h-12 w-full">
+          <Select
+            onChange={(e) => handleSetExample(e.target.value)}
+            value={selectedExample}
+            className={clsx(
+              'dark:white block w-full appearance-none rounded-lg border border-black/10 bg-white/5 px-3 py-1.5 text-sm/6 text-black dark:border-white/15 dark:bg-transparent',
+              'focus:outline-none data-[focus]:outline-2 data-[focus]:-outline-offset-2 data-[focus]:outline-white/25',
+              '*:text-black dark:text-white'
+            )}
+          >
+            <option value={-1}>-</option>
+            <optgroup label="Solana Mainnet">
+              {examples.map((example, index) => {
+                return (
+                  <option key={index} value={index}>
+                    {example.name}
+                  </option>
+                )
+              })}
+            </optgroup>
+          </Select>
+          <ChevronDownIcon
+            className="group pointer-events-none absolute right-2.5 top-4 my-auto size-4 fill-black/60 dark:fill-white"
+            aria-hidden="true"
+          />
+        </div>
+
+        <button
+          onClick={() => handleSetExample(-1)}
+          className="block rounded-lg border border-gray-200 px-4 text-sm focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/50 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-300 dark:placeholder-neutral-500"
+        >
+          Clear
+        </button>
+      </div>
+    </div>
+  )
+}
+
+export default ApiExampleSelector

+ 61 - 0
src/components/apiComponents/languageComponents/cSharpRenderer.jsx

@@ -0,0 +1,61 @@
+const { Fence } = require('@/components/Fence');
+
+const CSharpRequestRenderer = ({
+  url,
+  bodyMethod,
+  rpcVersion,
+  bodyParams,
+  id,
+}) => {
+  const httpBody = bodyParams;
+
+  const object = {
+    method: 'POST',
+    body: {
+      jsonrpc: rpcVersion ? rpcVersion : '2.0',
+      id: id ? id : 1,
+      method: bodyMethod,
+      params: httpBody,
+    },
+  };
+
+  const jsonBody = JSON.stringify(object.body, null, 2).replace(/"/g, '""');
+
+  const code = `
+using System;
+using System.Net.Http;
+using System.Text;
+
+class Program
+{
+  static void Main() {
+    var url = "${url}";
+    var data = new StringContent(@"
+    ${jsonBody.replace(/\n/g, '\n    ')}
+    ", Encoding.UTF8, "application/json");
+
+    var client = new HttpClient();
+    var request = new HttpRequestMessage {
+      Method = HttpMethod.Post,
+      RequestUri = new Uri(url),
+      Content = data
+    };
+
+    try {
+      var response = client.SendAsync(request).Result;
+      Console.WriteLine($"Status Code: {response.StatusCode}");
+      Console.WriteLine(response.Content.ReadAsStringAsync().Result);
+    } catch (Exception ex) {
+      Console.WriteLine($"An error occurred: {ex.Message}");
+    }
+  }
+}`;
+
+  return (
+    <Fence maxHeight={400} language="csharp">
+      {code}
+    </Fence>
+  );
+};
+
+export default CSharpRequestRenderer;

+ 42 - 0
src/components/apiComponents/languageComponents/curlRequestRenderer.jsx

@@ -0,0 +1,42 @@
+import { Fence } from '@/components/Fence'
+
+const CurlRequestRenderer = ({
+  url,
+  headers,
+  bodyMethod,
+  rpcVersion,
+  bodyParams,
+  id,
+}) => {
+  const httpBody = bodyParams
+
+  const object = {
+    method: 'POST',
+    headers: headers,
+    body: {
+      jsonrpc: rpcVersion ? rpcVersion : '2.0',
+      id: id ? id : 1,
+      method: bodyMethod,
+      params: httpBody,
+    },
+  }
+
+  // Dynamically generate the headers dictionary for curl
+  const headersCode = Object.entries(headers)
+    .map(([key, value]) => `-H "${key}: ${value}"`)
+    .join(' ')
+
+  // JSON body formatted for curl with escaped double quotes
+  const jsonBody = JSON.stringify(object.body).replace(/"/g, '\\"') // Make it a single-line string
+
+  // Generate the curl command (single-line body)
+  const code = `curl -X POST ${headersCode} -d "${jsonBody}" ${url}`
+
+  return (
+    <Fence className="w-full" language="bash">
+      {code}
+    </Fence>
+  )
+}
+
+export default CurlRequestRenderer

+ 101 - 0
src/components/apiComponents/languageComponents/goRequestRenderer.jsx

@@ -0,0 +1,101 @@
+import { Fence } from '@/components/Fence'
+
+const GoRequestRenderer = ({
+  url,
+  headers,
+  bodyMethod,
+  rpcVersion,
+  bodyParams,
+  id,
+}) => {
+  const httpBody = bodyParams
+
+  const object = {
+    method: 'POST',
+    headers: headers,
+    body: {
+      jsonrpc: rpcVersion ? rpcVersion : '2.0',
+      id: id ? id : 1,
+      method: bodyMethod,
+      params: httpBody,
+    },
+  }
+
+  // Dynamically generate the headers dictionary for Go
+  const headersCode = Object.entries(headers)
+    .map(([key, value]) => `    "${key}": "${value}",`)
+    .join('\n')
+
+  // Generate the raw string literal JSON body (no escaping quotes)
+  const jsonBody = JSON.stringify(object.body, null, 2)
+
+  const code = `package main
+
+import (
+  "bytes"
+  "fmt"
+  "io/ioutil"
+  "net/http"
+  "time"
+)
+
+func main() {
+  url := "${url}"
+  headers := map[string]string{
+${headersCode}
+  }
+  data := bytes.NewBuffer([]byte(\`${jsonBody.replace(/\n/g, '\n    ')}
+\`))
+
+  req, err := http.NewRequest("POST", url, data)
+  if err != nil {
+    fmt.Printf("Error creating request: %v\\n", err)
+    return
+  }
+
+  for key, value := range headers {
+    req.Header.Set(key, value)
+  }
+
+  // Create an HTTP client with a timeout
+  client := &http.Client{
+    Timeout: 10 * time.Second,
+  }
+
+  // Send the request
+  resp, err := client.Do(req)
+  if err != nil {
+    fmt.Printf("Error making request to %s: %v\\n", url, err)
+    return
+  }
+
+  // Ensure response body is closed
+  defer func() {
+    if resp != nil && resp.Body != nil {
+      resp.Body.Close()
+    }
+  }()
+
+  // Print the status code
+  fmt.Println("Status:", resp.Status)
+
+  // Read the response body
+  body, err := ioutil.ReadAll(resp.Body)
+  if err != nil {
+    fmt.Printf("Error reading response body: %v\\n", err)
+    return
+  }
+
+  // Print the response body
+  fmt.Println("Response Body:", string(body))
+}
+`
+
+  return (
+    <Fence className="w-full" language="go">
+      {code}
+    </Fence>
+  )
+}
+
+export default GoRequestRenderer

+ 95 - 0
src/components/apiComponents/languageComponents/javaRenderer.jsx

@@ -0,0 +1,95 @@
+import { Fence } from '@/components/Fence'
+
+const JavaRequestRenderer = ({
+  url,
+  headers,
+  bodyMethod,
+  rpcVersion,
+  bodyParams,
+  id,
+}) => {
+  const httpBody = bodyParams
+
+  const object = {
+    method: 'POST',
+    headers: headers,
+    body: {
+      jsonrpc: rpcVersion ? rpcVersion : '2.0',
+      id: id ? id : 1,
+      method: bodyMethod,
+      params: httpBody,
+    },
+  }
+
+  // Dynamically generate the headers dictionary for Java
+  const headersCode = Object.entries(headers)
+    .map(([key, value]) => `con.setRequestProperty("${key}", "${value}");`)
+    .join('\n')
+
+  // Format the JSON body correctly for the Java code with proper indentation
+  const jsonBody = JSON.stringify(object.body, null, 2)
+
+  const code = `import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class Main {
+    public static void main(String[] args) {
+        try {
+            String url = "${url}";
+            String jsonInputString = """
+            ${jsonBody.replace(/\n/g, '\n            ')}
+            """ ;
+
+            // Create a URL object from the string URL
+            URL obj = new URL(url);
+            HttpURLConnection con = (HttpURLConnection) obj.openConnection();
+
+            // Set the HTTP method to POST
+            con.setRequestMethod("POST");
+
+            // Set the headers
+            ${headersCode}
+
+            // Enable input and output streams
+            con.setDoOutput(true);
+
+            // Write the request body (JSON)
+            try (OutputStream os = con.getOutputStream()) {
+                byte[] input = jsonInputString.getBytes("utf-8");
+                os.write(input, 0, input.length);
+            }
+
+            // Get the response code
+            int responseCode = con.getResponseCode();
+            System.out.println("Response Code: " + responseCode);
+
+            // Read the response body
+            try (BufferedReader br = new BufferedReader(
+                    new InputStreamReader(con.getInputStream(), "utf-8"))) {
+                StringBuilder response = new StringBuilder();
+                String responseLine;
+                while ((responseLine = br.readLine()) != null) {
+                    response.append(responseLine.trim());
+                }
+                System.out.println("Response Body: " + response.toString());
+            }
+
+        } catch (Exception e) {
+            System.err.println("Error occurred while making the request:");
+            e.printStackTrace();
+        }
+    }
+}
+`
+
+  return (
+    <Fence className="w-full" language="java">
+      {code}
+    </Fence>
+  )
+}
+
+export default JavaRequestRenderer

+ 45 - 0
src/components/apiComponents/languageComponents/javascriptRequestRenderer.jsx

@@ -0,0 +1,45 @@
+import { Fence } from "@/components/Fence";
+
+
+const JavaScriptRequestRenderer = ({ url, headers, bodyMethod, rpcVersion, bodyParams, id }) => {
+  const httpBody = bodyParams;
+
+  const object = {
+    method: 'POST',
+    headers: headers,
+    body: {
+      jsonrpc: rpcVersion ? rpcVersion : '2.0',
+      id: id ? id : 1,
+      method: bodyMethod,
+      params: httpBody,
+    },
+  };
+
+  // Dynamically generate headers for JavaScript
+  const headersCode = Object.entries(headers)
+    .map(([key, value]) => `"${key}": "${value}"`)
+    .join(',\n');
+
+  // Format the body with indentation
+  const jsonBody = JSON.stringify(object.body, null, 2);  // 4-space indentation for JSON
+
+  const code = `const url = "${url}";
+
+fetch(url, {
+    method: "POST",
+    headers: ${headersCode},
+    body: ${jsonBody.replace(/\n/g, '\n    ')}
+})
+.then(response => response.json())
+.then(data => console.log(data))
+.catch(error => console.error("Error:", error));
+`;
+
+  return (
+    <Fence className="w-full" language="javascript">
+      {code}
+    </Fence>
+  );
+};
+
+export default JavaScriptRequestRenderer;

+ 59 - 0
src/components/apiComponents/languageComponents/kotlinRenderer.jsx

@@ -0,0 +1,59 @@
+import { Fence } from '@/components/Fence';
+
+const KotlinRequestRenderer = ({ url, bodyMethod, bodyParams }) => {
+  const httpBody = bodyParams;
+
+  const code = `
+import java.io.OutputStream
+import java.net.HttpURLConnection
+import java.net.URL
+
+fun main() {
+    try {
+        val url = "${url}"
+        val jsonInputString = """
+            {
+                "jsonrpc": "2.0",
+                "id": 1,
+                "method": "${bodyMethod}",
+                "params": ${JSON.stringify(httpBody, null, 2).replace(/\n/g, '\n                ')}
+            }
+        """
+
+        // Create a URL object from the string URL
+        val obj = URL(url)
+        val con = obj.openConnection() as HttpURLConnection
+
+        // Set the HTTP method to POST
+        con.requestMethod = "POST"
+
+        // Set the headers
+        con.setRequestProperty("Content-Type", "application/json")
+
+        // Enable input and output streams
+        con.doOutput = true
+
+        // Write the request body (JSON)
+        con.outputStream.use { os: OutputStream ->
+            val input = jsonInputString.toByteArray(Charsets.UTF_8)
+            os.write(input, 0, input.size)
+        }
+
+        // Get the response code
+        val responseCode = con.responseCode
+        println("Response Code: \$responseCode")
+
+    } catch (e: Exception) {
+        e.printStackTrace()
+    }
+}
+`;
+
+  return (
+    <Fence className="w-full" language="kotlin">
+      {code}
+    </Fence>
+  );
+};
+
+export default KotlinRequestRenderer;

+ 81 - 0
src/components/apiComponents/languageComponents/phpRenderer.jsx

@@ -0,0 +1,81 @@
+import { Fence } from '@/components/Fence'
+
+const PhpRequestRenderer = ({
+  url,
+  headers,
+  bodyMethod,
+  rpcVersion,
+  bodyParams,
+  id,
+}) => {
+  const httpBody = bodyParams
+
+  // Handle default values for `rpcVersion` and `id`
+  const rpcVersionValue = rpcVersion || '2.0'
+  const idValue = id || 1
+
+  // Convert httpBody to a PHP-compatible format
+  const formatParamsForPhp = (params) => {
+    if (Array.isArray(params)) {
+      return `[${params.map((item) => `'${item}'`).join(', ')}]` // Correct array formatting for PHP
+    }
+    if (typeof params === 'object') {
+      return `[${Object.entries(params)
+        .map(([key, value]) => `'${key}' => '${value}'`)
+        .join(', ')}]` // Use PHP array syntax for key-value pairs
+    }
+    return `'${params}'`
+  }
+
+  const formattedParams = formatParamsForPhp(httpBody)
+
+  const headersCode = Object.entries(headers)
+    .map(([key, value]) => `"${key}: ${value}"`)
+    .join(',\n    ')
+
+  const code = `
+<?php
+
+$url = "${url}";
+$data = [
+    "jsonrpc" => "${rpcVersionValue}",
+    "id" => ${idValue},
+    "method" => "${bodyMethod}",
+    "params" => ${formattedParams}
+];
+
+// Initialize cURL session
+$ch = curl_init($url);
+
+// Set cURL options
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+curl_setopt($ch, CURLOPT_POST, true);
+curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
+curl_setopt($ch, CURLOPT_HTTPHEADER, [
+    "Content-Type: application/json",
+]);
+
+// Execute cURL request
+$response = curl_exec($ch);
+
+// Check for errors
+if ($response === false) {
+    echo "cURL Error: " . curl_error($ch);
+} else {
+    echo "Response: " . $response;
+}
+
+// Close cURL session
+curl_close($ch);
+
+?>
+`
+
+  return (
+    <Fence className="w-full" language="php">
+      {code}
+    </Fence>
+  )
+}
+
+export default PhpRequestRenderer

+ 60 - 0
src/components/apiComponents/languageComponents/pythonRequestRenderer.jsx

@@ -0,0 +1,60 @@
+import { Fence } from '@/components/Fence';
+
+const PythonRequestRenderer = ({ url, headers, bodyMethod, rpcVersion, bodyParams, id }) => {
+  const httpBody = bodyParams;
+
+  // Handle default values for `rpcVersion` and `id`
+  const rpcVersionValue = rpcVersion || '2.0';
+  const idValue = id || 1;
+
+  // Function to format params as Python-style dictionaries
+  const formatParamsForPython = (params) => {
+    if (Array.isArray(params)) {
+      return `[${params.map(item => `'${item}'`).join(', ')}]`; // Correct array formatting for Python
+    }
+    if (typeof params === 'object') {
+      return `{${Object.entries(params)
+        .map(([key, value]) => `'${key}': '${value}'`)
+        .join(', ')}}`; // Use Python dict syntax for key-value pairs
+    }
+    return `'${params}'`;
+  };
+
+  const formattedParams = formatParamsForPython(httpBody);
+
+  // Convert headers to Python dict format
+  const headersCode = Object.entries(headers)
+    .map(([key, value]) => `'${key}': '${value}'`)
+    .join(",\n    ");
+
+  const code = `
+import requests
+import json
+
+url = "${url}"
+
+headers = {
+    "Content-Type": "application/json",
+}
+
+data = {
+    "jsonrpc": "${rpcVersionValue}",
+    "id": ${idValue},
+    "method": "${bodyMethod}",
+    "params": ${formattedParams}
+}
+
+response = requests.post(url, headers=headers, data=json.dumps(data))
+
+print(f"Response Code: {response.status_code}")
+print(f"Response Body: {response.text}")
+`;
+
+  return (
+    <Fence className="w-full" language="python">
+      {code}
+    </Fence>
+  );
+};
+
+export default PythonRequestRenderer;

+ 50 - 0
src/components/apiComponents/languageComponents/rubyRenderer.jsx

@@ -0,0 +1,50 @@
+import { Fence } from '@/components/Fence';
+
+const RubyRequestRenderer = ({ url, headers, bodyMethod, rpcVersion, bodyParams, id }) => {
+  const httpBody = bodyParams;
+
+  const headersCode = Object.entries(headers)
+    .map(([key, value]) => `    request["${key}"] = "${value}"`)
+    .join("\n");
+
+  const code = `
+require 'net/http'
+require 'json'
+require 'uri'
+
+# Parse the URL
+uri = URI.parse("${url}")
+uri.path = uri.path.empty? ? "/" : uri.path  # Ensure the path is not empty
+
+http = Net::HTTP.new(uri.host, uri.port)
+
+# Prepare the request body
+request_body = {
+  "jsonrpc": "${rpcVersion ? rpcVersion : '2.0'}",
+  "id": ${id ? id : 1},
+  "method": "${bodyMethod}",
+  "params": ${JSON.stringify(httpBody)}
+}.to_json
+
+# Create the POST request
+request = Net::HTTP::Post.new(uri.path, { "Content-Type" => "application/json" })
+${headersCode}
+
+# Set the request body
+request.body = request_body
+
+# Send the request and get the response
+response = http.request(request)
+
+# Output the response
+puts "Response: #{response.body}"
+`;
+
+  return (
+    <Fence className="w-full" language="ruby">
+      {code}
+    </Fence>
+  );
+};
+
+export default RubyRequestRenderer;

+ 52 - 0
src/components/apiComponents/languageComponents/rustRenderer.jsx

@@ -0,0 +1,52 @@
+import { Fence } from '@/components/Fence';
+
+const RustRequestRenderer = ({ url, headers, bodyMethod, rpcVersion, bodyParams, id }) => {
+  const httpBody = bodyParams;
+
+  const headersCode = Object.entries(headers)
+    .map(([key, value]) => `    request = request.header("${key}", "${value}")`)
+    .join("\n");
+
+  const code = `
+use reqwest::blocking::Client;
+use reqwest::header::CONTENT_TYPE;
+use serde::{Serialize, Deserialize};
+
+#[derive(Serialize, Deserialize)]
+struct RequestBody {
+    jsonrpc: String,
+    id: u64,
+    method: String,
+    params: serde_json::Value,
+}
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    let url = "${url}";
+    let client = Client::new();
+
+    let request_body = RequestBody {
+        jsonrpc: "${rpcVersion ? rpcVersion : '2.0'}".to_string(),
+        id: ${id ? id : 1},
+        method: "${bodyMethod}".to_string(),
+        params: serde_json::json!(${JSON.stringify(httpBody)}),
+    };
+
+    let request = client.post(url)
+        .header(CONTENT_TYPE, "application/json");
+
+    let response = request.json(&request_body).send()?;
+
+    println!("Response: {:?}", response.text()?);
+
+    Ok(())
+}
+`;
+
+  return (
+    <Fence className="w-full" language="rust">
+      {code}
+    </Fence>
+  );
+};
+
+export default RustRequestRenderer;

+ 58 - 0
src/components/apiComponents/languageComponents/swiftRenderer.jsx

@@ -0,0 +1,58 @@
+import { Fence } from '@/components/Fence';
+
+const SwiftRequestRenderer = ({ url, headers, bodyMethod, rpcVersion, bodyParams, id }) => {
+  const httpBody = bodyParams;
+
+  const headersCode = Object.entries(headers)
+    .map(([key, value]) => `        request.setValue("${value}", forHTTPHeaderField: "${key}")`)
+    .join("\n");
+
+  const jsonBody = JSON.stringify({
+    jsonrpc: rpcVersion ? rpcVersion : '2.0',
+    id: id ? id : 1,
+    method: bodyMethod,
+    params: httpBody,
+  }, null, 2);
+
+  const code = `
+import Foundation
+
+let url = URL(string: "${url}")!
+var request = URLRequest(url: url)
+request.httpMethod = "POST"
+request.setValue("application/json", forHTTPHeaderField: "Content-Type")
+
+${headersCode}
+
+let jsonData = """
+${jsonBody}
+""".data(using: .utf8)!
+
+request.httpBody = jsonData
+
+let task = URLSession.shared.dataTask(with: request) { data, response, error in
+    if let error = error {
+        print("Error: \(error.localizedDescription)")
+        return
+    }
+
+    if let response = response as? HTTPURLResponse {
+        print("Response Status Code: \(response.statusCode)")
+    }
+
+    if let data = data, let responseString = String(data: data, encoding: .utf8) {
+        print("Response Body: \(responseString)")
+    }
+}
+
+task.resume()
+`;
+
+  return (
+    <Fence className="w-full" language="swift">
+      {code}
+    </Fence>
+  );
+};
+
+export default SwiftRequestRenderer;

+ 0 - 0
src/components/apiComponents/languageComponents/umiRequestRenderer.jsx


+ 220 - 0
src/components/apiComponents/languageRenderer.jsx

@@ -0,0 +1,220 @@
+import { useCallback, useState } from 'react'
+import EndPointSelector, { endpoints } from './endPointSelector'
+import CSharpRequestRenderer from './languageComponents/cSharpRenderer'
+import CurlRequestRenderer from './languageComponents/curlRequestRenderer'
+import GoRequestRenderer from './languageComponents/goRequestRenderer'
+import JavaRenderer from './languageComponents/javaRenderer'
+import JavascriptRequestRenderer from './languageComponents/javascriptRequestRenderer'
+import KotlinRenderer from './languageComponents/kotlinRenderer'
+import PhpRenderer from './languageComponents/phpRenderer'
+import PythonRequestRenderer from './languageComponents/pythonRequestRenderer'
+import RubyRenderer from './languageComponents/rubyRenderer'
+import RustRequestRenderer from './languageComponents/rustRenderer'
+import SwiftRequestRenderer from './languageComponents/swiftRenderer'
+import LanguageSelector from './languageSelector'
+
+const LanguageRenderer = ({ api, body, setActiveEndPoint, activeEndPoint }) => {
+  const [activeLanguage, setActiveLanguage] = useState('javascript')
+
+  function strToTitleCase(str) {
+    return str.charAt(0).toUpperCase() + str.slice(1)
+  }
+
+  console.log({activeEndPoint})
+
+  const renderLanguage = (activeLanguage, activeEndpoint) => {
+    const headers = api.headers
+      ? api.headers
+      : { 'Content-Type': 'application/json' }
+
+    switch (activeLanguage) {
+      case 'javascript':
+        return (
+          <div className="flex flex-col">
+            <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+              {strToTitleCase(activeLanguage)} Request Example
+            </div>
+            <JavascriptRequestRenderer
+              method={api.method}
+              url={activeEndPoint.uri}
+              headers={headers}
+              bodyMethod={body.method}
+              bodyParams={body.params}
+            />
+          </div>
+        )
+
+      case 'python':
+        return (
+          <div className="flex flex-col">
+            <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+              {strToTitleCase(activeLanguage)} Request Example
+            </div>
+            <PythonRequestRenderer
+              method={api.method}
+              url={activeEndpoint.uri}
+              headers={headers}
+              bodyMethod={body.method}
+              bodyParams={body.params}
+            />
+          </div>
+        )
+
+      case 'curl':
+        return (
+          <div className="flex flex-col">
+            <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+              {strToTitleCase(activeLanguage)} Request Example
+            </div>
+            <CurlRequestRenderer
+              method={api.method}
+              url={end}
+              headers={headers}
+              bodyMethod={body.method}
+              bodyParams={body.params}
+            />
+          </div>
+        )
+
+      case 'go':
+        return (
+          <div className="flex flex-col">
+            <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+              {strToTitleCase(activeLanguage)} Request Example
+            </div>
+            <GoRequestRenderer
+              method={api.method}
+              url={activeEndpoint.uri}
+              headers={headers}
+              bodyMethod={body.method}
+              bodyParams={body.params}
+            />
+          </div>
+        )
+
+      case 'csharp':
+        return (
+          <div className="flex flex-col">
+            <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+              {strToTitleCase(activeLanguage)} Request Example
+            </div>
+            <CSharpRequestRenderer
+              method={endpoint}
+              url={activeEndPoint}
+              // headers={headers}
+              bodyMethod={body.method}
+              bodyParams={body.params}
+            />
+          </div>
+        )
+
+      case 'java':
+        return (
+          <div className="flex flex-col">
+            <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+              {strToTitleCase(activeLanguage)} Request Example
+            </div>
+            <JavaRenderer
+              method={endpoint}
+              url={activeEndPoint}
+              headers={headers}
+              bodyMethod={body.method}
+              bodyParams={body.params}
+            />
+          </div>
+        )
+
+      case 'php':
+        return (
+          <div className="flex flex-col">
+            <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+              {strToTitleCase(activeLanguage)} Request Example
+            </div>
+            <PhpRenderer
+              method={api.method}
+              url={activeEndpoint.uri}
+              headers={headers}
+              bodyMethod={body.method}
+              bodyParams={body.params}
+            />
+          </div>
+        )
+      // case 'kotlin':
+      //   return (
+      //     <div className="flex flex-col">
+      //       <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+      //         {strToTitleCase(activeLanguage)} Request Example
+      //       </div>
+      //       <KotlinRenderer
+      //         method={api.method}
+      //         url={activeEndPoint}
+      //         headers={headers}
+      //         bodyMethod={body.method}
+      //         bodyParams={body.params}
+      //       />
+      //     </div>
+      //   )
+      case 'ruby':
+        return (
+          <div className="flex flex-col">
+            <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+              {strToTitleCase(activeLanguage)} Request Example
+            </div>
+            <RubyRenderer
+              method={api.method}
+              url={activeEndpoint.uri}
+              headers={headers}
+              bodyMethod={body.method}
+              bodyParams={body.params}
+            />
+          </div>
+        )
+      case 'rust':
+        return (
+          <div className="flex flex-col">
+            <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+              {strToTitleCase(activeLanguage)} Request Example
+            </div>
+            <RustRequestRenderer
+              method={api.method}
+              url={activeEndpoint.uri}
+              headers={headers}
+              bodyMethod={body.method}
+              bodyParams={body.params}
+            />
+          </div>
+        )
+      case 'swift':
+        return (
+          <div className="flex flex-col">
+            <div className="-mb-3 text-sm font-medium text-gray-800 dark:text-neutral-400">
+              {strToTitleCase(activeLanguage)} Request Example
+            </div>
+            <SwiftRequestRenderer
+              method={api.method}
+              url={activeEndpoint.uri}
+              headers={headers}
+              bodyMethod={body.method}
+              bodyParams={body.params}
+            />
+          </div>
+        )
+    }
+  }
+
+  return (
+    <div className="flex w-full flex-col gap-8 overflow-hidden">
+      <EndPointSelector
+        setActiveEndpoint={(endpoint) => setActiveEndPoint(endpoint)}
+        activeEndpoint={activeEndPoint}
+      />
+      <LanguageSelector
+        activeLanguage={activeLanguage}
+        setActiveLanguage={(language) => setActiveLanguage(language)}
+      />
+      {renderLanguage(activeLanguage)}
+    </div>
+  )
+}
+
+export default LanguageRenderer

+ 43 - 0
src/components/apiComponents/languageSelector.jsx

@@ -0,0 +1,43 @@
+import { Icon } from '@/components/icons'
+
+const languages = [
+  { name: 'curl', icon: 'CurlIcon' },
+  { name: 'javascript', icon: 'JavaScriptIcon' },
+  { name: 'python', icon: 'PythonIcon' },
+  { name: 'php', icon: 'PhpIcon' },
+  { name: 'go', icon: 'GoIcon' },
+  // { name: 'ruby', icon: 'RubyIcon' },
+  // { name: 'kotlin', icon: 'KotlinIcon' },
+  { name: 'java', icon: 'JavaIcon' },
+  // { name: 'swift', icon: 'SwiftIcon' },
+  { name: 'rust', icon: 'RustIcon' },
+  { name: 'csharp', icon: 'CSharpIcon' },
+]
+
+const LanguageSelector = ({ activeLanguage, setActiveLanguage }) => {
+  return (
+    <div className="scrollbar flex flex-col gap-2">
+      <div className="text-sm font-medium text-gray-800 dark:text-neutral-400">
+        Language
+      </div>
+      <div className="flex overflow-auto">
+        {languages.map((language) => (
+          <button
+            key={language.name}
+            className={`-ms-px inline-flex min-w-16 flex-col items-center justify-center gap-1 border border-gray-200 px-10 py-2 text-xs font-medium text-gray-800 shadow-sm transition-colors first:ms-0 first:rounded-s-lg last:rounded-e-lg hover:bg-gray-50 focus:z-10 focus:bg-accent-300 focus:outline-none focus:ring-1 disabled:pointer-events-none disabled:opacity-50 dark:border-neutral-700 dark:bg-neutral-900 dark:text-white dark:hover:bg-neutral-800 ${
+              activeLanguage === language.name
+                ? 'bg-accent-300 text-black hover:bg-accent-300 dark:bg-accent-300 dark:text-black dark:hover:bg-accent-300'
+                : ''
+            }`}
+            onClick={() => setActiveLanguage(language.name)}
+          >
+            <Icon icon={language.icon} className="h-4 w-4" />
+            {language.name}
+          </button>
+        ))}
+      </div>
+    </div>
+  )
+}
+
+export default LanguageSelector

+ 14 - 0
src/components/apiComponents/responce.jsx

@@ -0,0 +1,14 @@
+import { Fence } from '../Fence'
+
+const Responce = ({ responce }) => {
+  return (
+    <div className="flex flex-col w-full overflow-hidden">
+      <div className='-mb-3'>Response</div>
+      <Fence className="w-full" language="json">
+        {JSON.stringify(responce, null, 2)}
+      </Fence>
+    </div>
+  )
+}
+
+export default Responce

+ 27 - 5
src/components/icons/index.jsx

@@ -1,13 +1,35 @@
-import * as outlineIcons24 from '@heroicons/react/24/outline'
 import * as solidIcons20 from '@heroicons/react/20/solid'
+import * as outlineIcons24 from '@heroicons/react/24/outline'
 import clsx from 'clsx'
 
-import { JavaScriptIcon } from './JavaScriptIcon'
-import { RustIcon } from './RustIcon'
+import { CSharpIcon } from './languages/CSharpIcon'
+import { CurlIcon } from './languages/CurlIcon'
+import { GoIcon } from './languages/GoIcon'
+import { JavaIcon } from './languages/JavaIcon'
+import { JavaScriptIcon } from './languages/JavaScriptIcon'
+import { KotlinIcon } from './languages/KotlinIcon'
+import { PhpIcon } from './languages/PhpIcon'
+import { PythonIcon } from './languages/PythonIcon'
+import { RubyIcon } from './languages/RubyIcon'
+import { RustIcon } from './languages/RustIcon'
+import { ShellIcon } from './languages/ShellIcon'
+import { SwiftIcon } from './languages/SwiftIcon'
+// import { TypescriptIcon } from './languages/TypescriptIcon'
 
 const customIcons = {
-  JavaScriptIcon: JavaScriptIcon,
-  RustIcon: RustIcon,
+  CSharpIcon,
+  CurlIcon,
+  GoIcon,
+  JavaIcon,
+  JavaScriptIcon,
+  KotlinIcon,
+  PhpIcon,
+  PythonIcon,
+  RubyIcon,
+  RustIcon,
+  ShellIcon,
+  SwiftIcon,
+  // TypescriptIcon,
 }
 
 export function Icon({ icon, className, ...props }) {

+ 12 - 0
src/components/icons/languages/CSharpIcon.jsx

@@ -0,0 +1,12 @@
+export function CSharpIcon(props) {
+  return (
+    <svg
+      viewBox="0 0 64 64"
+      fill="currentColor"
+      xmlns="http://www.w3.org/2000/svg"
+      {...props}
+    >
+      <path d="M59.5167 16.194L59.6717 16.0905C59.3618 15.5214 58.897 15.004 58.4322 14.7454L33.4884 0.362167C33.0753 0.103476 32.5072 0 31.8875 0C31.2678 0 30.6997 0.155214 30.2865 0.362167L5.49766 14.7971C4.61972 15.3145 4 16.6079 4 17.5909V46.4091C4 46.9782 4.10329 47.599 4.46479 48.1681L4.3615 48.2199C4.61972 48.6338 4.98123 48.996 5.34273 49.2029L30.2349 63.6378C30.648 63.8965 31.2161 64 31.8358 64C32.4556 64 33.0236 63.8448 33.4368 63.6378L58.2256 49.2029C59.1036 48.6855 59.7233 47.3921 59.7233 46.4091V17.5392C59.775 17.1253 59.7233 16.6597 59.5167 16.194ZM31.8875 52.4107C20.6292 52.4107 11.4883 43.253 11.4883 31.9741C11.4883 20.6952 20.6292 11.5376 31.8875 11.5376C39.4791 11.5376 46.0894 15.7284 49.6012 21.8852L42.8875 25.7656C40.7185 21.8852 36.587 19.2983 31.8875 19.2983C24.9156 19.2983 19.2348 24.9895 19.2348 31.9741C19.2348 38.9588 24.9156 44.65 31.8875 44.65C36.587 44.65 40.7185 42.0631 42.8875 38.2344L49.5495 42.1665C46.0378 48.2716 39.4274 52.4107 31.8875 52.4107ZM58.2256 30.9394H56.5731L56.1083 33.0089H58.2256V35.5958H55.6435L55.0238 38.7001H52.4932L53.1129 35.5958H51.1505L50.5308 38.7001H48.0519L48.6716 35.5958H47.3805V33.0089H49.188L49.6528 30.9394H47.3805V28.3525H50.1176L50.7373 25.2482H53.2679L52.6481 28.3525H54.6106L55.2303 25.2482H57.7092L57.0895 28.3525H58.2256V30.9394ZM51.6669 33.0089H53.6294L54.0942 30.9394H52.1317L51.6669 33.0089Z" />
+    </svg>
+  )
+}

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 10 - 0
src/components/icons/languages/CurlIcon.jsx


+ 19 - 0
src/components/icons/languages/GoIcon.jsx

@@ -0,0 +1,19 @@
+export function GoIcon(props) {
+  return (
+    <svg
+      width="64"
+      height="64"
+      viewBox="0 0 64 64"
+      fill="currentColor"
+      xmlns="http://www.w3.org/2000/svg"
+      {...props}
+    >
+      <path
+        fillRule="evenodd"
+        clipRule="evenodd"
+        d="M5.578 27.4144C5.4565 27.4144 5.4265 27.3534 5.487 27.2629L6.1235 26.4444C6.1835 26.3534 6.3355 26.2929 6.4565 26.2929H17.275C17.3965 26.2929 17.4265 26.3839 17.366 26.4749L16.851 27.2629C16.7905 27.3534 16.639 27.4444 16.548 27.4444L5.578 27.4144ZM1.002 30.2019C0.880999 30.2019 0.850499 30.1419 0.910999 30.0504L1.5475 29.2324C1.608 29.1414 1.7595 29.0809 1.881 29.0809H15.699C15.82 29.0809 15.881 29.1719 15.8505 29.2629L15.608 29.9899C15.578 30.1114 15.4565 30.1719 15.3355 30.1719L1.002 30.2019ZM8.335 32.9899C8.214 32.9899 8.184 32.8989 8.2445 32.8079L8.6685 32.0504C8.7295 31.9594 8.8505 31.8689 8.972 31.8689H15.032C15.1535 31.8689 15.214 31.9594 15.214 32.0809L15.154 32.8079C15.154 32.9294 15.0325 33.0204 14.9415 33.0204L8.335 32.9899ZM39.79 26.8689C37.8805 27.3539 36.5775 27.7174 34.699 28.2019C34.244 28.3234 34.214 28.3534 33.82 27.8989C33.3655 27.3839 33.032 27.0504 32.396 26.7474C30.4865 25.8084 28.638 26.0809 26.911 27.2024C24.8505 28.5354 23.79 30.5049 23.82 32.9594C23.85 35.3839 25.517 37.3839 27.911 37.7174C29.9715 37.9899 31.699 37.2624 33.0625 35.7174C33.335 35.3839 33.5775 35.0204 33.8805 34.5959H28.032C27.396 34.5959 27.2445 34.2019 27.4565 33.6869C27.8505 32.7474 28.5775 31.1719 29.0015 30.3839C29.093 30.2019 29.305 29.8989 29.7595 29.8989H40.7895C40.7295 30.7174 40.7295 31.5354 40.608 32.3539C40.2745 34.5354 39.4565 36.5354 38.123 38.2929C35.941 41.1719 33.093 42.9594 29.4865 43.4444C26.517 43.8384 23.7595 43.2624 21.3355 41.4444C19.093 39.7474 17.8205 37.5049 17.487 34.7174C17.093 31.4144 18.0625 28.4444 20.0625 25.8384C22.214 23.0204 25.0625 21.2324 28.5475 20.5959C31.396 20.0809 34.123 20.4144 36.5775 22.0809C38.1835 23.1414 39.335 24.5959 40.0925 26.3534C40.2745 26.6264 40.154 26.7784 39.79 26.8689Z"
+      />
+      <path d="M49.82 43.6265C47.0625 43.5655 44.547 42.778 42.426 40.9595C40.638 39.4145 39.517 37.4445 39.1535 35.111C38.608 31.687 39.547 28.6565 41.608 25.96C43.82 23.0505 46.4865 21.5355 50.093 20.899C53.1835 20.354 56.093 20.657 58.729 22.4445C61.123 24.081 62.6075 26.293 63.0015 29.202C63.5165 33.293 62.335 36.6265 59.5165 39.475C57.5165 41.505 55.062 42.778 52.244 43.3535C51.426 43.505 50.6075 43.5355 49.82 43.6265ZM57.032 31.384C57.002 30.99 57.002 30.687 56.941 30.384C56.396 27.384 53.638 25.687 50.7595 26.354C47.941 26.99 46.123 28.778 45.4565 31.6265C44.911 33.99 46.0625 36.384 48.244 37.3535C49.911 38.081 51.5775 37.99 53.1835 37.172C55.5775 35.9295 56.8805 33.99 57.032 31.384Z" />
+    </svg>
+  )
+}

+ 14 - 0
src/components/icons/languages/JavaIcon.jsx

@@ -0,0 +1,14 @@
+export function JavaIcon(props) {
+  return (
+    <svg
+      width="64"
+      height="64"
+      viewBox="0 0 64 64"
+      fill="currentColor"
+      xmlns="http://www.w3.org/2000/svg"
+      {...props}
+    >
+      <path d="M23.8142 48.9469C14.2246 51.6101 29.6488 57.112 41.8597 51.9116C39.8596 51.1388 38.425 50.2472 38.425 50.2472C32.9801 51.2704 30.4543 51.3509 25.5116 50.7896C21.4323 50.3252 23.8142 48.9469 23.8142 48.9469ZM40.3977 43.7515C33.1805 45.1318 29.0118 45.0876 23.7318 44.5462C19.649 44.1265 22.3217 42.1596 22.3217 42.1596C11.7602 45.6444 28.2013 49.5986 42.9625 45.3067C41.3935 44.7573 40.3977 43.7515 40.3977 43.7515ZM46.0534 13.6646C46.0539 13.6646 24.7021 18.9638 34.8994 30.6449C37.9094 34.0894 34.1099 37.1863 34.1099 37.1863C34.1099 37.1863 41.7493 33.2669 38.2416 28.3566C34.9643 23.7797 32.452 21.5058 46.0534 13.6646ZM51.0491 53.9679C51.0491 53.9679 52.8125 55.4133 49.1064 56.5303C42.0601 58.6522 19.7729 59.2919 13.5825 56.6153C11.359 55.6527 15.5307 54.3181 16.8433 54.0365C18.2119 53.7419 18.9934 53.7956 18.9934 53.7956C16.5191 52.0636 2.99755 57.1979 12.127 58.6706C37.0209 62.6818 57.5053 56.8641 51.0491 53.9679ZM42.4933 38.9019C43.69 38.0903 45.3429 37.3855 45.3429 37.3855C45.3429 37.3855 40.634 38.2224 35.9427 38.6143C30.1995 39.0931 24.0391 39.1875 20.9466 38.7762C13.6255 37.8032 24.9605 35.1265 24.9605 35.1265C24.9605 35.1265 20.5574 34.8305 15.145 37.4331C8.74323 40.5101 30.98 41.9128 42.4933 38.9019ZM45.2959 46.4242C45.242 46.5683 45.0621 46.7302 45.0621 46.7302C60.6882 42.6469 54.943 32.3366 47.4715 34.9462C46.8159 35.1767 46.4722 35.7126 46.4722 35.7126C46.4722 35.7126 46.8864 35.5467 47.8103 35.355C51.5873 34.5727 56.9987 40.381 45.2959 46.4242ZM32.0907 35.0143C29.7853 29.8343 21.9674 25.3025 32.0942 17.3525C44.7213 7.44504 38.2421 1 38.2421 1C40.8554 11.2358 29.0228 14.3277 24.7516 20.7022C21.843 25.0457 26.1791 29.7131 32.0907 35.0143ZM45.7187 60.7169C36.1315 62.511 24.3059 62.3019 17.294 61.151C17.294 61.151 18.7301 62.3332 26.1112 62.8055C37.3417 63.5193 54.5923 62.4082 55 57.1254C55.0005 57.1254 54.2155 59.128 45.7187 60.7169Z" />
+    </svg>
+  )
+}

+ 0 - 0
src/components/icons/JavaScriptIcon.jsx → src/components/icons/languages/JavaScriptIcon.jsx


+ 14 - 0
src/components/icons/languages/KotlinIcon.jsx

@@ -0,0 +1,14 @@
+export function KotlinIcon(props) {
+  return (
+    <svg
+      width="64"
+      height="64"
+      viewBox="0 0 64 64"
+      fill="currentColor"
+      xmlns="http://www.w3.org/2000/svg"
+      {...props}
+    >
+      <path d="M64 64H0V0H64L32 32L64 64Z" />
+    </svg>
+  )
+}

+ 14 - 0
src/components/icons/languages/PhpIcon.jsx

@@ -0,0 +1,14 @@
+export function PhpIcon(props) {
+  return (
+    <svg
+      width="64"
+      height="64"
+      viewBox="0 0 64 64"
+      fill="currentColor"
+      xmlns="http://www.w3.org/2000/svg"
+      {...props}
+    >
+      <path d="M32 15C14.327 15 0 22.6118 0 32C0 41.3882 14.327 49 32 49C49.6725 49 64 41.3882 64 32C64 22.6118 49.673 15 32 15ZM29.009 19.9534H32.6555V19.9549L31.783 24.4831H35.031C37.0745 24.4831 38.485 24.8436 39.26 25.5631C40.0365 26.2837 40.2685 27.4501 39.959 29.0623L38.4325 36.9897H34.7285L36.1795 29.4516C36.3445 28.5942 36.2835 28.01 35.997 27.698C35.7105 27.3864 35.1005 27.2309 34.168 27.2309H31.254L29.376 36.9887H25.7305L29.009 19.9534ZM13.365 24.4836H20.4315C22.5575 24.4836 24.109 25.0471 25.084 26.1741C26.059 27.3011 26.352 28.8735 25.963 30.8932C25.803 31.7258 25.5315 32.4857 25.1505 33.1755C24.769 33.8642 24.2705 34.4949 23.6555 35.0664C22.9215 35.7597 22.1065 36.2545 21.21 36.5489C20.313 36.8443 19.17 36.9907 17.781 36.9907H14.634L13.7615 41.52H10.0865L13.365 24.4836ZM42.048 24.4836H49.113C51.239 24.4836 52.7895 25.0471 53.7645 26.1741H53.7655C54.7405 27.3011 55.0345 28.8735 54.6455 30.8932C54.4855 31.7258 54.215 32.4857 53.834 33.1755C53.4525 33.8642 52.954 34.4949 52.338 35.0664C51.6045 35.7597 50.789 36.2545 49.8915 36.5489C48.9945 36.8443 47.853 36.9907 46.464 36.9907H43.3165L42.4445 41.52H38.7695L42.048 24.4836ZM16.5225 27.1724L15.1515 34.302H17.3855C18.867 34.302 19.9715 34.0212 20.6965 33.4572C21.4215 32.8937 21.9105 31.952 22.165 30.6337C22.4075 29.3678 22.297 28.4731 21.832 27.953C21.367 27.4319 20.437 27.1719 19.04 27.1719L16.5225 27.1724ZM45.204 27.1724L43.832 34.302H46.067C47.5495 34.302 48.652 34.0212 49.378 33.4572C50.1025 32.8937 50.5915 31.952 50.8455 30.6337C51.089 29.3678 50.9785 28.4731 50.5135 27.953C50.0485 27.4319 49.1175 27.1719 47.7215 27.1719L45.204 27.1724Z" />
+    </svg>
+  )
+}

+ 14 - 0
src/components/icons/languages/PythonIcon.jsx

@@ -0,0 +1,14 @@
+export function PythonIcon(props) {
+  return (
+    <svg
+      width="64"
+      height="64"
+      viewBox="0 0 64 64"
+      fill="currentColor"
+      xmlns="http://www.w3.org/2000/svg"
+      {...props}
+    >
+      <path d="M24.2426 30.9538H39.6612C43.9533 30.9538 47.3343 27.3619 47.3343 23.0989V8.56051C47.3343 4.42253 43.8275 1.31381 39.638 0.623453C36.9867 0.186747 34.2471 -0.0119935 31.6074 0.000558551C28.9688 0.0125876 26.5248 0.234863 24.3077 0.623453C17.7746 1.76412 16.6653 4.15423 16.6653 8.56051V14.2178H31.9998V16.3098H10.7303C6.24412 16.3098 2.31531 18.9813 1.08696 24.056C-0.330688 29.8718 -0.393613 33.4276 1.08696 39.5002C2.18418 44.02 4.80427 47.1669 9.29094 47.1669H14.5502V40.3428C14.5502 35.3026 19.0067 30.9538 24.2426 30.9538ZM23.2707 10.4993C21.6707 10.4993 20.3741 9.20276 20.3741 7.59924C20.3741 5.98892 21.6701 4.68037 23.2707 4.68037C24.865 4.68037 26.1679 5.98892 26.1679 7.59924C26.1674 9.20276 24.8645 10.4993 23.2707 10.4993ZM62.8174 24.056C61.7081 19.6377 59.5903 16.3098 55.0978 16.3098H49.4494V23.0989C49.4494 28.355 44.7994 32.5228 39.6612 32.5228H24.2426C20.0188 32.5228 16.6653 36.3543 16.6653 40.5384V55.0778C16.6653 59.2147 20.2319 61.6488 24.3124 62.836C29.1994 64.257 33.8272 64.5138 39.6739 62.836C43.5599 61.7225 47.3343 59.483 47.3343 55.0778V49.2589H31.9998V47.1669H55.0978C59.584 47.1669 61.2565 44.146 62.8174 39.4997C64.4286 34.7168 64.3594 30.1908 62.8174 24.056ZM40.6326 53.138C42.2332 53.138 43.5298 54.4345 43.5298 56.039C43.5298 57.6478 42.2337 58.9569 40.6326 58.9569C39.0383 58.9569 37.736 57.6483 37.736 56.039C37.736 54.4345 39.0383 53.138 40.6326 53.138Z" />
+    </svg>
+  )
+}

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 10 - 0
src/components/icons/languages/RubyIcon.jsx


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 10 - 0
src/components/icons/languages/RustIcon.jsx


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 10 - 0
src/components/icons/languages/ShellIcon.jsx


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 10 - 0
src/components/icons/languages/SwiftIcon.jsx


+ 14 - 0
src/components/icons/languages/TypescriptIcon.jsx

@@ -0,0 +1,14 @@
+export function TypescriptIcon(props) {
+  return (
+    <svg
+      width="64"
+      height="64"
+      viewBox="0 0 64 64"
+      fill="currentColor"
+      xmlns="http://www.w3.org/2000/svg"
+      {...props}
+    >
+      <path d="M0 32V64H64V0H0V32ZM51.5738 29.44C53.1066 29.7957 54.4998 30.5974 55.5776 31.744C56.1709 32.3617 56.6867 33.0494 57.1136 33.792C57.1136 33.8739 54.3488 35.7427 52.6643 36.7872C52.6029 36.8282 52.3571 36.5619 52.0858 36.1574C51.7783 35.6268 51.3413 35.1828 50.8158 34.8667C50.2902 34.5507 49.6932 34.3729 49.0803 34.3501C47.1398 34.217 45.8906 35.2358 45.9008 36.9101C45.8848 37.3269 45.9802 37.7405 46.1773 38.1082C46.6022 38.9939 47.3958 39.5213 49.8842 40.5965C54.4666 42.5677 56.4275 43.8682 57.6461 45.7165C59.008 47.7645 59.3101 51.072 58.3885 53.5194C57.3645 56.1818 54.8557 57.9891 51.3075 58.5882C49.687 58.7738 48.0496 58.7566 46.4333 58.537C43.9666 58.1368 41.6911 56.9623 39.936 55.1834C39.3472 54.5331 38.2003 52.8384 38.272 52.7155C38.4589 52.5768 38.6557 52.4519 38.8608 52.3418L41.216 50.9901L43.0541 49.9251L43.4381 50.4934C44.0861 51.4205 44.9109 52.2104 45.865 52.8179C47.913 53.8931 50.7085 53.7446 52.0909 52.5005C52.555 52.0446 52.8446 51.4403 52.9091 50.7929C52.9737 50.1455 52.8091 49.496 52.4442 48.9574C51.9322 48.2458 50.9082 47.6467 48.0461 46.3974C44.7437 44.9741 43.3203 44.0934 42.0198 42.6906C41.208 41.7648 40.6086 40.6726 40.2637 39.4906C40.0064 38.1401 39.9684 36.7571 40.151 35.3946C40.832 32.2048 43.223 29.9776 46.7149 29.3171C48.332 29.117 49.97 29.1619 51.5738 29.4502V29.44ZM36.5517 32.1229V34.7443H28.2419V58.4141H22.3488V34.7392H14.0186V32.1792C13.9962 31.2979 14.0201 30.4161 14.0902 29.5373C14.121 29.4963 19.2102 29.4758 25.3542 29.4861H36.521L36.5517 32.1229Z" />
+    </svg>
+  )
+}

+ 5 - 0
src/components/icons/spinner.jsx

@@ -0,0 +1,5 @@
+const Spinner = ({className, style}) => {
+  return <span className={`loader ${className}`} style={style}></span>
+}
+
+export default Spinner

+ 51 - 0
src/components/products/aura/index.js

@@ -63,6 +63,57 @@ export const aura = {
             },
           ],
         },
+
+        {
+          title: 'DAS Methods',
+          collapsed: true,
+          links: [
+            {
+              title: 'Get Asset',
+              href: '/aura/api/v1/das/get-asset',
+            },
+            {
+              title: 'Get Asset Proof',
+              href: '/aura/api/v1/das/get-asset-proof',
+            },
+            {
+              title: 'Get Asset Batch',
+              href: '/aura/api/v1/das/get-asset-batch',
+            },
+            {
+              title: 'Get Asset Proof Batch',
+              href: '/aura/api/v1/das/get-asset-proof-batch',
+            },
+            {
+              title: 'Get Assets by Owner',
+              href: '/aura/api/v1/das/get-assets-by-owner',
+            },
+            {
+              title: 'Get Assets by Authority',
+              href: '/aura/api/v1/das/get-assets-by-authority',
+            },
+            {
+              title: 'Get Assets By Creator',
+              href: '/aura/api/v1/das/get-assets-by-creator',
+            },
+            {
+              title: 'Get Assets By Group',
+              href: '/aura/api/v1/das/get-assets-by-group',
+            },
+            {
+              title: 'Get Signatures For Asset',
+              href: '/aura/api/v1/das/get-signatures-for-asset',
+            },
+            {
+              title: 'Get Token Accounts',
+              href: '/aura/api/v1/das/get-token-accounts',
+            },
+            {
+              title: 'Search Assets',
+              href: '/aura/api/v1/das/search-assets',
+            },
+          ],
+        },
       ],
     },
   ],

+ 1 - 0
src/components/products/candyMachine/index.js

@@ -117,6 +117,7 @@ export const candyMachine = {
         {
           title: 'Candy Machine Guides',
           links: [
+            { title: 'Mint NFTs to Another Wallet - Airdrop example', href: '/candy-machine/guides/airdrop-mint-to-another-wallet' },
             { title: 'Create an NFT Collection on Solana with Candy Machine', href: '/candy-machine/guides/create-an-nft-collection-on-solana-with-candy-machine' }
           ],
         },

+ 6 - 0
src/components/products/guides/index.js

@@ -148,6 +148,12 @@ export const guides = {
               created: '2024-09-04',
               updated: null, // null means it's never been updated
             },
+            {
+              title: 'MPL-404 Hybrid UI Template',
+              href: '/mpl-hybrid/guides/mpl-404-hyrbid-ui-template',
+              created: '2024-12-16',
+              updated: null, // null means it's never been updated
+            },
           ],
         },
         {

+ 11 - 0
src/components/products/mpl-hybrid/index.js

@@ -34,6 +34,12 @@ export const mplHybrid = {
             { title: 'Javascript SDK', href: '/mpl-hybrid/sdk/javascript' },
           ],
         },
+        {
+          title: 'UI Templates',
+          links: [
+            { title: 'MPL-404 Hybrid UI', href: '/mpl-hybrid/guides/mpl-404-hyrbid-ui-template', created: '2024-12-16' },
+          ],
+        },
         {
           title: 'Features',
           links: [
@@ -81,6 +87,11 @@ export const mplHybrid = {
               title: 'Create your first Hybrid Collection',
               href: '/mpl-hybrid/guides/create-your-first-hybrid-collection',
             },
+            {
+              title: 'MPL-404 Hyrbid UI Template',
+              href: '/mpl-hybrid/guides/mpl-404-hyrbid-ui-template',
+              created: '2024-12-16',
+            },
           ],
         },
       ],

+ 51 - 0
src/lib/api/aura/das/getAssestByAuthority.js

@@ -0,0 +1,51 @@
+const getAssetsByAuthority = {
+  description: 'Returns the list of assets given an authority address.',
+  method: 'getAssetsByAuthority',
+  params: [
+    {
+      name: 'authorityAddress',
+      type: 'string',
+      description: 'Public key of the authority',
+      placeholder: 'Public key of the authority',
+      required: true,
+    },
+    {
+      name: 'sortBy',
+      type: 'object',
+      description: 'Sorting criteria',
+      value: {
+        sortBy: {
+          type: 'option',
+          value: ['created', 'updated', 'recentAction', 'none'],
+        },
+        sortDirection: {
+          type: 'option',
+          value: ['asc', 'desc'],
+        },
+      },
+    },
+    {
+      name: 'limit',
+      type: 'number',
+      description: 'Number of assets to return',
+    },
+    {
+      name: 'page',
+      type: 'number',
+      description: 'The index of the "page" to retrieve.',
+    },
+    {
+      name: 'before',
+      type: 'string',
+      description: 'Retrieve assets before the specified ID',
+    },
+    {
+      name: 'after',
+      type: 'string',
+      description: 'Retrieve assets after the specified ID',
+    },
+  ],
+  examples: null,
+}
+
+export default getAssetsByAuthority

+ 184 - 0
src/lib/api/aura/das/getAsset.js

@@ -0,0 +1,184 @@
+const getAsset = {
+  description: 'Get an asset by its ID',
+  method: 'getAsset',
+  params: [
+    {
+      type: 'string',
+      description: 'Public key of the asset',
+      name: 'id',
+      placeholder: 'Public key of the asset',
+      required: true,
+    },
+  ],
+  examples: [
+    {
+      name: 'Galactic Geckos EP 1 #985 (Core Asset)',
+      description: 'Get an asset by its ID',
+      chain: 'solanaMainnet',
+      body: {
+        params: {
+          id: '5avjMVza8SuMhgTfzEGNWJskDELMCQk9juAAc8zeQoNa',
+        },
+      },
+    },
+    {
+      name: 'Saga Monkes #6233 (cNFT)',
+      description: 'Get an asset by its ID',
+      chain: 'solanaMainnet',
+      body: {
+        params: {
+          id: 'H6GDZujkpEcxbpDgEbSbNFxNtSi3RBJPJC5GZCvzagaP',
+        },
+      },
+    },
+    {
+      name: 'Madlad #4221 (pNFT)',
+      description: 'Get an asset by its ID',
+      chain: 'solanaMainnet',
+      body: {
+        params: {
+          id: 'G3nEdTzAvPvSuj2Z5oSSiMN42NayQDZvkC3usMrnGaTi',
+        },
+      },
+    },
+    
+    {
+      name: 'THUG #2926 (NFT)',
+      description: 'Get an asset by its ID',
+      chain: 'solanaMainnet',
+      body: {
+        params: {
+          id: 'EvGJtxZAjxYGwYDtHprvApfLTx44PxsSCtWq3uVmfboy',
+        },
+      },
+    },
+  ],
+  exampleResponse : {
+    "jsonrpc": "2.0",
+    "result": {
+      "interface": "ProgrammableNFT",
+      "id": "8aguf5d15kvHVsXyr8WfY73JgdQnWq1z6FhsUWqawivd",
+      "content": {
+        "$schema": "https://schema.metaplex.com/nft1.0.json",
+        "json_uri": "https://arweave.net/7V_i2RU5fZO9UTtR5e04oCH-ySTmFAS_TISGfjeBkp4",
+        "files": [
+          {
+            "uri": "https://arweave.net/Ji5Lf4paxnY2kPCjnnQOfiBdtwGjIed7mDKyHjM14Fc",
+            "mime": "image/png"
+          },
+          {
+            "uri": "https://cdn.solanamonkey.business/gen2/121.png",
+            "mime": "image/png"
+          }
+        ],
+        "metadata": {
+          "attributes": [
+            {
+              "trait_type": "Attributes Count",
+              "value": 2
+            },
+            {
+              "trait_type": "Type",
+              "value": "Purple"
+            },
+            {
+              "trait_type": "Clothes",
+              "value": "Red Shirt"
+            },
+            {
+              "trait_type": "Ears",
+              "value": "None"
+            },
+            {
+              "trait_type": "Mouth",
+              "value": "None"
+            },
+            {
+              "trait_type": "Eyes",
+              "value": "None"
+            },
+            {
+              "trait_type": "Hat",
+              "value": "White Fedora 1"
+            }
+          ],
+          "description": "SMB is a collection of 5000 randomly generated 24x24 pixels NFTs on the Solana Blockchain. Each SolanaMonkey is unique and comes with different type and attributes varying in rarity.",
+          "name": "SMB #121",
+          "symbol": "SMB",
+          "token_standard": "ProgrammableNonFungible"
+        },
+        "links": {
+          "image": "https://arweave.net/Ji5Lf4paxnY2kPCjnnQOfiBdtwGjIed7mDKyHjM14Fc",
+          "external_url": "https://solanamonkey.business/"
+        }
+      },
+      "authorities": [
+        {
+          "address": "mdaoxg4DVGptU4WSpzGyVpK3zqsgn7Qzx5XNgWTcEA2",
+          "scopes": [
+            "full"
+          ]
+        }
+      ],
+      "compression": {
+        "eligible": false,
+        "compressed": false,
+        "data_hash": "",
+        "creator_hash": "",
+        "asset_hash": "",
+        "tree": "",
+        "seq": 0,
+        "leaf_id": 0
+      },
+      "grouping": [
+        {
+          "group_key": "collection",
+          "group_value": "SMBtHCCC6RYRutFEPb4gZqeBLUZbMNhRKaMKZZLHi7W",
+          "verified": true
+        }
+      ],
+      "royalty": {
+        "royalty_model": "creators",
+        "target": null,
+        "percent": 0,
+        "basis_points": 0,
+        "primary_sale_happened": true,
+        "locked": false
+      },
+      "creators": [
+        {
+          "address": "mdaoxg4DVGptU4WSpzGyVpK3zqsgn7Qzx5XNgWTcEA2",
+          "share": 0,
+          "verified": true
+        },
+        {
+          "address": "HAryckvjyViFQEmhmMoCtqqBMJnpXEYViamyDhZUJfnG",
+          "share": 100,
+          "verified": false
+        },
+        {
+          "address": "9uBX3ASjxWvNBAD1xjbVaKA74mWGZys3RGSF7DdeDD3F",
+          "share": 0,
+          "verified": false
+        }
+      ],
+      "ownership": {
+        "frozen": true,
+        "delegated": false,
+        "delegate": null,
+        "ownership_model": "single",
+        "owner": "1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix"
+      },
+      "supply": null,
+      "mutable": true,
+      "burnt": false,
+      "lamports": 5616720,
+      "executable": false,
+      "metadata_owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
+      "rent_epoch": 18446744073709552000
+    },
+    "id": "1"
+  }
+}
+
+export default getAsset

+ 357 - 0
src/lib/api/aura/das/getAssetBatch.js

@@ -0,0 +1,357 @@
+const getAssetBatch = {
+  description: 'Get an asset by its ID',
+  method: 'getAssetBatch',
+  params: [
+    {
+      type: 'array',
+      description: 'Public keys of the Assets to fetch',
+      name: 'ids',
+      value: [""],
+      required: true,
+      placeHolder: "Asset Public Key"
+    },
+  ],
+  exampleResponse: {
+    "jsonrpc": "2.0",
+    "result": [
+      {
+        "interface": "MplCoreAsset",
+        "id": "5avjMVza8SuMhgTfzEGNWJskDELMCQk9juAAc8zeQoNa",
+        "content": {
+          "$schema": "https://schema.metaplex.com/nft1.0.json",
+          "json_uri": "https://arweave.net/2xl-wNjCDAnCEtPbtUZRlXypSP6boMVTt5On8F7NPoc",
+          "files": [
+            {
+              "uri": "https://arweave.net/2LmjJyHmQY0OFoWg3cx2cTlV-fSIMGVMiPUFgLSv4Lk",
+              "mime": "image/png"
+            }
+          ],
+          "metadata": {
+            "attributes": [
+              {
+                "trait_type": "rarity",
+                "value": "Legendary"
+              },
+              {
+                "trait_type": "used",
+                "value": "false"
+              },
+              {
+                "trait_type": "signed",
+                "value": "false"
+              }
+            ],
+            "description": "A young girl narrowly escaped an evil space pirate and is rescued by a team of mercenaries. Together, their discovery will unlock the secrets of the galaxy - and lead to an adventure that threatens life as they know it!",
+            "name": "Galactic Geckos EP 1 #985",
+            "symbol": ""
+          },
+          "links": {
+            "image": "https://arweave.net/2LmjJyHmQY0OFoWg3cx2cTlV-fSIMGVMiPUFgLSv4Lk",
+            "external_url": "https://dreader.app"
+          }
+        },
+        "authorities": [
+          {
+            "address": "FXj8W4m33SgLB5ZAg35g8wsqFTvywc6fmJTXzoQQhrVf",
+            "scopes": [
+              "full"
+            ]
+          }
+        ],
+        "compression": {
+          "eligible": false,
+          "compressed": false,
+          "data_hash": "",
+          "creator_hash": "",
+          "asset_hash": "",
+          "tree": "",
+          "seq": 0,
+          "leaf_id": 0
+        },
+        "grouping": [
+          {
+            "group_key": "collection",
+            "group_value": "8J1w2Khc79x5itJkpfc1HDcSLseY84R9dbKmJHQH5brD",
+            "verified": true
+          }
+        ],
+        "royalty": {
+          "royalty_model": "creators",
+          "target": null,
+          "percent": 0,
+          "basis_points": 0,
+          "primary_sale_happened": false,
+          "locked": false
+        },
+        "creators": [],
+        "ownership": {
+          "frozen": false,
+          "delegated": false,
+          "delegate": null,
+          "ownership_model": "single",
+          "owner": "7aLBCrbn4jDNSxLLJYRRnKbkqA5cuaeaAzn74xS7eKPD"
+        },
+        "supply": null,
+        "mutable": true,
+        "burnt": false,
+        "lamports": 3525360,
+        "executable": false,
+        "rent_epoch": 18446744073709552000,
+        "plugins": {},
+        "mpl_core_info": {
+          "plugins_json_version": 1
+        },
+        "external_plugins": []
+      },
+      {
+        "interface": "V1_NFT",
+        "id": "H6GDZujkpEcxbpDgEbSbNFxNtSi3RBJPJC5GZCvzagaP",
+        "content": {
+          "$schema": "https://schema.metaplex.com/nft1.0.json",
+          "json_uri": "https://shdw-drive.genesysgo.net/5HXhJs7ScMnUEZPxmr1f4EMzwTVEhfV1TEXLW7qacMis/6233.json",
+          "files": [
+            {
+              "uri": "https://shdw-drive.genesysgo.net/5HXhJs7ScMnUEZPxmr1f4EMzwTVEhfV1TEXLW7qacMis/6233.png",
+              "mime": "image/png"
+            }
+          ],
+          "metadata": {
+            "attributes": [
+              {
+                "trait_type": "Background",
+                "value": "Saga"
+              },
+              {
+                "trait_type": "Fur",
+                "value": "Mocha"
+              },
+              {
+                "trait_type": "Clothing",
+                "value": "Band Hoodie"
+              },
+              {
+                "trait_type": "Mouth",
+                "value": "Beaming"
+              },
+              {
+                "trait_type": "Head",
+                "value": "Mullet Gang"
+              },
+              {
+                "trait_type": "Eyes",
+                "value": "Wayfarers"
+              }
+            ],
+            "description": "Saga Monkes is an exclusive generative art collection airdropped to Saga Genesis Token holders. Learn more at https://SagaMonkes.com",
+            "name": "MONKE #6233",
+            "symbol": "MONKE",
+            "token_standard": "NonFungible"
+          },
+          "links": {
+            "image": "https://shdw-drive.genesysgo.net/5HXhJs7ScMnUEZPxmr1f4EMzwTVEhfV1TEXLW7qacMis/6233.png"
+          }
+        },
+        "authorities": [
+          {
+            "address": "4JdzLtiv96HEnpmpyN7ZdkupvZpZfSFRV6im7HUnsEXT",
+            "scopes": [
+              "full"
+            ]
+          }
+        ],
+        "compression": {
+          "eligible": false,
+          "compressed": true,
+          "data_hash": "2iY1CPYktGQHQbuNkkvonEryMvnoaJiUjLnufHJotron",
+          "creator_hash": "Ep5RkW26Mcyk4njkeL3mnH3EUHoaPktuSYWJajMnSCoR",
+          "asset_hash": "8uKWwYxK7imdvHSPthAVJhidAh5EwuvahdW3BpMYXaz8",
+          "tree": "2uH9TkmYkAKGrK7EPnd4Y7JVYswpQ2aED9deMn8QoYVy",
+          "seq": 102852,
+          "leaf_id": 6201
+        },
+        "grouping": [
+          {
+            "group_key": "collection",
+            "group_value": "GokAiStXz2Kqbxwz2oqzfEXuUhE7aXySmBGEP7uejKXF",
+            "verified": true
+          }
+        ],
+        "royalty": {
+          "royalty_model": "creators",
+          "target": null,
+          "percent": 0.069,
+          "basis_points": 690,
+          "primary_sale_happened": false,
+          "locked": false
+        },
+        "creators": [
+          {
+            "address": "8McVhmNjsYSkwQ34QXJb2ADgLWERcHcpqxSzRZUCRZfQ",
+            "share": 40,
+            "verified": false
+          },
+          {
+            "address": "niFtyPVUnA4dd3gaoajiwmX1keTsTi4k626szinHE5Z",
+            "share": 40,
+            "verified": false
+          },
+          {
+            "address": "KRTv1iR6dH7FuPoW51BQ9hU9UTtibYwZTEA3Fjg4RYy",
+            "share": 15,
+            "verified": false
+          },
+          {
+            "address": "6jYqTEtDgkr1v4DtU4QDUmg1cAf4o1GSsQDGt9X8EfPG",
+            "share": 5,
+            "verified": false
+          }
+        ],
+        "ownership": {
+          "frozen": false,
+          "delegated": false,
+          "delegate": null,
+          "ownership_model": "single",
+          "owner": "DJT1uEFuseGT8GBu8trBU9ocLHXXrRvCRSk3QKn7Xac4"
+        },
+        "supply": {
+          "print_max_supply": 0,
+          "print_current_supply": 0,
+          "edition_nonce": 0
+        },
+        "mutable": true,
+        "burnt": false
+      },
+      {
+        "interface": "ProgrammableNFT",
+        "id": "G3nEdTzAvPvSuj2Z5oSSiMN42NayQDZvkC3usMrnGaTi",
+        "content": {
+          "$schema": "https://schema.metaplex.com/nft1.0.json",
+          "json_uri": "https://madlads.s3.us-west-2.amazonaws.com/json/4221.json",
+          "files": [
+            {
+              "uri": "https://madlads.s3.us-west-2.amazonaws.com/images/4221.png",
+              "mime": "image/png"
+            },
+            {
+              "uri": "https://arweave.net/qJ5B6fx5hEt4P7XbicbJQRyTcbyLaV-OQNA1KjzdqOQ/4221.png",
+              "mime": "image/png"
+            }
+          ],
+          "metadata": {
+            "attributes": [
+              {
+                "trait_type": "Gender",
+                "value": "Female"
+              },
+              {
+                "trait_type": "Type",
+                "value": "Light"
+              },
+              {
+                "trait_type": "Expression",
+                "value": "Mad"
+              },
+              {
+                "trait_type": "Hair",
+                "value": "Lovelace"
+              },
+              {
+                "trait_type": "Eyes",
+                "value": "Blue"
+              },
+              {
+                "trait_type": "Mouth",
+                "value": "Red"
+              },
+              {
+                "trait_type": "Clothing",
+                "value": "Luxe"
+              },
+              {
+                "trait_type": "Background",
+                "value": "White"
+              }
+            ],
+            "description": "Fock it.",
+            "name": "Mad Lads #4221",
+            "symbol": "MAD",
+            "token_standard": "ProgrammableNonFungible"
+          },
+          "links": {
+            "image": "https://madlads.s3.us-west-2.amazonaws.com/images/4221.png",
+            "external_url": "https://madlads.com"
+          }
+        },
+        "authorities": [
+          {
+            "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW",
+            "scopes": [
+              "full"
+            ]
+          }
+        ],
+        "compression": {
+          "eligible": false,
+          "compressed": false,
+          "data_hash": "",
+          "creator_hash": "",
+          "asset_hash": "",
+          "tree": "",
+          "seq": 0,
+          "leaf_id": 0
+        },
+        "grouping": [
+          {
+            "group_key": "collection",
+            "group_value": "J1S9H3QjnRtBbbuD4HjPV6RpRhwuk4zKbxsnCHuTgh9w",
+            "verified": true
+          }
+        ],
+        "royalty": {
+          "royalty_model": "creators",
+          "target": null,
+          "percent": 0.042,
+          "basis_points": 420,
+          "primary_sale_happened": true,
+          "locked": false
+        },
+        "creators": [
+          {
+            "address": "5XvhfmRjwXkGp3jHGmaKpqeerNYjkuZZBYLVQYdeVcRv",
+            "share": 0,
+            "verified": true
+          },
+          {
+            "address": "2RtGg6fsFiiF1EQzHqbd66AhW7R5bWeQGpTbv2UMkCdW",
+            "share": 100,
+            "verified": true
+          }
+        ],
+        "ownership": {
+          "frozen": true,
+          "delegated": false,
+          "delegate": null,
+          "ownership_model": "single",
+          "owner": "1BWutmTvYPwDtmw9abTkS4Ssr8no61spGAvW1X6NDix"
+        },
+        "supply": null,
+        "mutable": true,
+        "burnt": false,
+        "lamports": 5616720,
+        "executable": false,
+        "metadata_owner": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s",
+        "rent_epoch": 18446744073709552000,
+        "token_info": {
+          "supply": 1,
+          "decimals": 0,
+          "token_program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+          "mint_authority": "2ntsS4TKHPXHRGf7e95ocJFRmuhCdSHD8do232a8xx96",
+          "freeze_authority": "2ntsS4TKHPXHRGf7e95ocJFRmuhCdSHD8do232a8xx96"
+        }
+      }
+    ],
+    "id": "1"
+  }
+}
+
+export default getAssetBatch

+ 54 - 0
src/lib/api/aura/das/getAssetProof.js

@@ -0,0 +1,54 @@
+const getAssetProof = {
+    description: 'Get the proof of a compressed Digital Asset NFT (cNFT) by its ID',
+    method: 'getAssetProof',
+    params: [
+      {
+        type: 'string',
+        description: 'Public key of the asset',
+        name: 'id',
+        placeholder: 'Public key of the asset',
+        required: true
+      },
+    ],
+    examples: [
+      {
+        name: 'Saga Monkes #6233 (cNFT)',
+        chain: 'solanaMainnet',
+        description: 'Get an asset by its ID',
+        body: {
+          params: {
+            id: 'H6GDZujkpEcxbpDgEbSbNFxNtSi3RBJPJC5GZCvzagaP',
+          },
+        },
+      },
+    ],
+    exampleResponse: {
+      "jsonrpc": "2.0",
+      "result": {
+        "root": "55bo42a5Vz9pKsuXybLBDDijfL15aZ8yo4YvCKivsswm",
+        "proof": [
+          "Wo8BxWavZxJkNYQvDf98kesxX4Yket1PRdLna4hNXxc",
+          "9i9ZcT1KLf9sqx7TzT9AkkAkxAE4yfrWjcuGGrAtpJde",
+          "Bco6o8YsbVvL5RJeRX9gBwvVr3B1xCtSkFAbbsNwFWvW",
+          "7vSEygK2aWtjPC11gNLGzdXdATG3B8DwdZqtcpzJNKjB",
+          "5QxNqt6Ekv5bQaPxgn4cnmqYPpRjg4FHjofXrGvN35L5",
+          "BYebt3P7jCHgTdPvdyJ4DzbeoKj3VEGs6Wv7g9tzWBHK",
+          "AWk4KY6f7wmcdWuhgSk1jQxEm8GeYA7aRFw6CoLKGtc5",
+          "BMkbYSoj6t2VFGHP5oDi1YKTRqKm6DAeyKSNJq3BpeKD",
+          "DeD9EasMhdyZB6Lsgp5xfwxFkhf66tScSH4X3eEuNmKR",
+          "9XeVtw7o4TJZoqjSvJuv8fGjX33n6BWprSogmEjckb9A",
+          "DBmErTVKEMHEsHcc3M7tDNQKGWerVd3a3ihXwq3JSt7R",
+          "6VTjVoMRMgxE7SCmTeyNEguzetfBsCtoSD6Zt27Q68m5",
+          "6LMPcGLfMVJz3mGdh9NPUxRsnNLdqMMptEzpFNP8mRFm",
+          "DaDD5eZcLV2Cev4yLTc3zeqNyMXDAoR7jLjfGC4smQE8"
+        ],
+        "node_index": 22585,
+        "leaf": "8uKWwYxK7imdvHSPthAVJhidAh5EwuvahdW3BpMYXaz8",
+        "tree_id": "2uH9TkmYkAKGrK7EPnd4Y7JVYswpQ2aED9deMn8QoYVy"
+      },
+      "id": "1"
+    }
+  }
+  
+  export default getAssetProof
+  

+ 17 - 0
src/lib/api/aura/das/getAssetProofBatch.js

@@ -0,0 +1,17 @@
+const getAssetProofBatch = {
+  description:
+    'Get the proof of a compressed Digital Asset NFT (cNFT) by its ID',
+  method: 'getAssetProofBatch',
+  params: [
+    {
+      type: 'array',
+      description: 'Public keys of the assets you want to fetch proofs for',
+      name: 'ids',
+      value: [],
+      required: true,
+      placeHolder: 'Asset Public Key',
+    },
+  ],
+}
+
+export default getAssetProofBatch

+ 57 - 0
src/lib/api/aura/das/getAssetsByCreator.js

@@ -0,0 +1,57 @@
+const getAssetsByCreator = {
+    description: 'Returns the list of assets given an authority address.',
+    method: 'getAssetsByCreator',
+    params: [
+      {
+        name: 'creatorAddress',
+        type: 'string',
+        description: 'Public key of the creator',
+        placeholder: 'Public key of the creator',
+        required: true,
+      },
+      {
+        name: 'onlyVerified',
+        type: 'boolean',
+        description: 'Indicates whether to retrieve only verified assets or not.',
+      },
+      {
+        name: 'sortBy',
+        type: 'object',
+        description: 'Sorting criteria',
+        value: {
+          sortBy: {
+            type: 'option',
+            value: ['created', 'updated', 'recentAction', 'none'],
+          },
+          sortDirection: {
+            type: 'option',
+            value: ['asc', 'desc'],
+          },
+        },
+      },
+      {
+        name: 'limit',
+        type: 'number',
+        description: 'Number of assets to return',
+      },
+      {
+        name: 'page',
+        type: 'number',
+        description: 'The index of the "page" to retrieve.',
+      },
+      {
+        name: 'before',
+        type: 'string',
+        description: 'Retrieve assets before the specified ID',
+      },
+      {
+        name: 'after',
+        type: 'string',
+        description: 'Retrieve assets after the specified ID',
+      },
+    ],
+    examples: null,
+  }
+  
+  export default getAssetsByCreator
+  

+ 59 - 0
src/lib/api/aura/das/getAssetsByGroup.js

@@ -0,0 +1,59 @@
+
+const getAssetsByGroup = {
+    description: 'Returns the list of assets given an Group address.',
+    method: 'getAssetsByGroup',
+    params: [
+      {
+        name: 'groupKey',
+        type: 'string',
+        description: 'Public key of the group',
+        placeholder: 'Public key of the group',
+        required: true,
+      },
+      {
+        name: 'groupValue',
+        type: 'string',
+        description: 'The value of the group.',
+        required: true,
+      },
+      {
+        name: 'sortBy',
+        type: 'object',
+        description: 'Sorting criteria',
+        value: {
+          sortBy: {
+            type: 'option',
+            value: ['created', 'updated', 'recentAction', 'none'],
+          },
+          sortDirection: {
+            type: 'option',
+            value: ['asc', 'desc'],
+          },
+        },
+      },
+      {
+        name: 'limit',
+        type: 'number',
+        description: 'Number of assets to return',
+      },
+      {
+        name: 'page',
+        type: 'number',
+        description: 'The index of the "page" to retrieve.',
+      },
+      {
+        name: 'before',
+        type: 'string',
+        description: 'Retrieve assets before the specified ID',
+      },
+      {
+        name: 'after',
+        type: 'string',
+        description: 'Retrieve assets after the specified ID',
+      },
+    ],
+    examples: null,
+  }
+  
+  export default getAssetsByGroup
+  

+ 51 - 0
src/lib/api/aura/das/getAssetsByOwner.js

@@ -0,0 +1,51 @@
+const getAssetsByOwner = {
+  description: 'Returns the list of assets given an Group address.',
+  method: 'getAssetsByOwner',
+  params: [
+    {
+      name: 'ownerAddress',
+      type: 'string',
+      description: 'Public key of the owner',
+      placeholder: 'Public key of the owner',
+      required: true,
+    },
+    {
+      name: 'sortBy',
+      type: 'object',
+      description: 'Sorting criteria',
+      value: {
+        sortBy: {
+          type: 'option',
+          value: ['created', 'updated', 'recentAction', 'none'],
+        },
+        sortDirection: {
+          type: 'option',
+          value: ['asc', 'desc'],
+        },
+      },
+    },
+    {
+      name: 'limit',
+      type: 'number',
+      description: 'Number of assets to return',
+    },
+    {
+      name: 'page',
+      type: 'number',
+      description: 'The index of the "page" to retrieve.',
+    },
+    {
+      name: 'before',
+      type: 'string',
+      description: 'Retrieve assets before the specified ID',
+    },
+    {
+      name: 'after',
+      type: 'string',
+      description: 'Retrieve assets after the specified ID',
+    },
+  ],
+  examples: null,
+}
+
+export default getAssetsByOwner

+ 169 - 0
src/lib/api/aura/das/getSignaturesForAsset.js

@@ -0,0 +1,169 @@
+const getSignaturesForAsset = {
+  description:
+    'Get the proof of a compressed Digital Asset NFT (cNFT) by its ID',
+  method: 'getSignaturesForAsset',
+  params: [
+    {
+      name: 'id',
+      type: 'string',
+      description: 'Public key of the asset',
+      placeholder: 'Public key of the asset',
+      required: true,
+    },
+    {
+      name: 'page',
+      type: 'number',
+      description: 'The page to return',
+      placeholder: 'The page to return',
+    },
+    {
+      name: 'limit',
+      type: 'number',
+      description:
+        'Amount of signatures to return. Default is 1000. Max is 1000',
+      placeholder: 'Amount',
+    },
+    {
+      name: 'before',
+      type: 'string',
+      description: 'Return results before signature with this ID',
+      placeholder: 'Signature ID',
+    },
+    {
+      name: 'after',
+      type: 'string',
+      description: 'Return results after signature with this ID',
+      placeholder: 'Signature ID',
+    },
+  ],
+  examples: [
+    {
+      name: 'Fetch signatures of Saga Monkes #6233 (cNFT)',
+      description: 'Fetch the signatures associated with an asset by its ID',
+      chain: "solanaMainnet",
+      body: {
+        params: {
+          id: 'H6GDZujkpEcxbpDgEbSbNFxNtSi3RBJPJC5GZCvzagaP',
+        },
+      },
+    },
+  ],
+  exampleResponse: {
+    "jsonrpc": "2.0",
+    "result": {
+      "total": 26,
+      "limit": 1000,
+      "before": "102852",
+      "after": "6202",
+      "items": [
+        [
+          "ku1YghMvsszXcLSGCHTCqZcDh1tRaJV9NmYysgW8xJFBnbHsaGmXrLZWNpW84btE5LFT2ugEibBnHFqR7Ga1dEW",
+          "Transfer"
+        ],
+        [
+          "2cjTJnmHeGj54d2CKhxbYyzu4iwGSSd4BdvxMEWkBZ59wx4GMNz9qwBETjdnc799h6nexctbtAKEUHwnSWWPynHP",
+          "Transfer"
+        ],
+        [
+          "5VYXhQ1hCmAbYxhXppCDAA2mcstGSp9n5f2aY3RH2ZjSdsVhNVGy99f2Mcnc1qLgGS99gvGCgVXnhwzALszeUEzg",
+          "Transfer"
+        ],
+        [
+          "65uJ7B2Za5iEbnC3EuqD5FSZzr6pSmAFAc9kQGEcKqvXuZmtgzzKksBgDSfcA6RdGyBKNLquYq6vRBVx77v7ACK8",
+          "Transfer"
+        ],
+        [
+          "35QGhF8HZ9jJdGKbF4wCJ7dWYeDJAq6sGdo5jDWfnf9z5QJiobS7fu4ZYEk4FmNMvxk6Q3B2Mzz4dUahhzQXi4jp",
+          "UpdateMetadata"
+        ],
+        [
+          "3acoPpA8r6fFvgouphrX8AZs4YycHzSHbZG455DABWaMQTG72nRTgh1Ngvr9bTShaokyx6uH4WpwhdyEPTd61uLY",
+          "Transfer"
+        ],
+        [
+          "3ybYGksQYM289onorCzpGb2iVykH76UQ6iLWuEDkom2pkW4bNZ9Z3tLWEPiMZaHHQkEshz3Szy1L3sSYAHNUuZTw",
+          "Transfer"
+        ],
+        [
+          "3W1fGLVeHqr5o8KFAyV53uUHQGjbi4EWkmukT6peZFXScReu35M1TRiUdqGYxcUCE8nUMHtWro6KZF7Fp5scUDUL",
+          "Transfer"
+        ],
+        [
+          "65pT3upbbd9fFqLDkVGU4Txe92xvCPntr32cBsqFG8UAcSTY1EoZT7v39ZKXmP6iLGdDn14iHnzzt9woc8Rg55Ps",
+          "Transfer"
+        ],
+        [
+          "5YfJqdyGfDeFEtvrXVgJgp78ZktjCCPG3oHtoDgwvhwP1jHYspdQcVWn8YaNsDo3978McgF7NHpBzG8fiGM9pAUB",
+          "Transfer"
+        ],
+        [
+          "5Hkc9E1RcW7joxj6VCCRAV91mrkKbaUjTLNPTTdXKxNCKGPvTcJNkg6rBk3yQHczc3DKzMHvXyARKXW8iDTkUijU",
+          "Transfer"
+        ],
+        [
+          "iuMcrfwQs6DZmYXhdjHMEAbSxBEqe3TZRjxbTH21QncsdvGJxbahVpfuPQsqRCsjx9WZrPQUVVTEk3abR6RPV9x",
+          "Transfer"
+        ],
+        [
+          "5sWWSAN3XTdaER9zSGf4duBWWXdRjnW6emjBsNmntBFxcw1EqRva64X6ouACc9fupCJAa6VVj6tHFxtPZkaMLnzt",
+          "Transfer"
+        ],
+        [
+          "ML3D7hHyYv29uki13o53sbQwnkV2qADJxocEEqPXT5GS2H612MKbLBXEv31QUAQxXn5EHpUmnqmoumS7ju4sduv",
+          "Transfer"
+        ],
+        [
+          "88JcrzFgGgSB3JvzAE9V1Rw158M7tY3HaG8vAfRE55yR3ZNFjMFbNFayAT3BzC56YK9mP31oTH6yMfn948cEHZt",
+          "Transfer"
+        ],
+        [
+          "2NBrzfVKWDnvm7mdAZ7VC5FxfXM2pgAZtAFthkYtDPL6Wbh8XvKkTQUiWUrhz7DD4NH7RzDxEmRaDFLoFWwQRK6k",
+          "Transfer"
+        ],
+        [
+          "NvbTkDe4GAvMXW9yud9GDmzhrLKVBypJkHpveN99s41ieuWrPHnZcwqbL5zUaXGESWx6YmVdgyyPrbt5fA1dTxg",
+          "Transfer"
+        ],
+        [
+          "21fMgxF7AYsDuJ7qAsDZwkPzE5MKHEtTxihfPp2Df4jMCSVN89ihsL5BpDepkTdWA35RkwS95YyN5sg6xopDTyku",
+          "Transfer"
+        ],
+        [
+          "2BGd8CSCXr8TbCjzZ9wDANErggZnBKRVkwJJsFS8mGjphenF8ubo25pCXug77ejomtjxy3PAJegLMhd9nC9kQyRs",
+          "Transfer"
+        ],
+        [
+          "idmLXJSXBqk4GyxXGG7Jt3kN7iocuzS9S9WFLAyh7hMqQXEDoMe9dQEx4ZduPA5vyXgVC4e8pNBsxoHQEridZ9Z",
+          "Transfer"
+        ],
+        [
+          "2cPinwrSXqkcnc1a2f8jqH9HwtGjVaFoGUFgX5ngs9ReQkf762SjwtWSr38Z6Mw42yPk1iNp4rxmVZ5AHbWRDjzp",
+          "Transfer"
+        ],
+        [
+          "5EG6nGd19D7w8iKTZW3j4LrGcPL25Vb8DgC1ow3eSxRc6pt5zjhjVKmUqMmzJhzbWF6CnyfU3eE9uUdj74hP7pBX",
+          "Transfer"
+        ],
+        [
+          "4CGNUpVBBb5GxkJ5wjfBYMzFBCzJYmDxLKrycqyTcXKigU1zyifTbUze7qwoYngQmGRsoeUSTgzTH3fC5hMwqMXL",
+          "Transfer"
+        ],
+        [
+          "pT7iNQXjdSpnLWFT3FWgpjjUZpDxqXGcdV6zuom3AoRhT1XHxggCQPaVNnwZDHo2xyrqi6CJ6atQDyA9zdZgqeA",
+          "Transfer"
+        ],
+        [
+          "3rG9cE8SZ3g9yVxjbBwtJoP91cxAe5NMjKLTrocqfz4ThLB5DUWmHKSUiaWHKMiYYwsLuFCuaL7yWLYSRT946fAh",
+          "Transfer"
+        ],
+        [
+          "3mCjD5iVXMaV2YwmKxUzHVu3WkGggzEa23BVwdu2Nx5Ef7gwzXQSnspZZrtu8xVbddm1LJsjuaenGbtapFeDQXZL",
+          "MintToCollectionV1"
+        ]
+      ]
+    },
+    "id": "1"
+  }
+}
+
+export default getSignaturesForAsset

+ 55 - 0
src/lib/api/aura/das/getTokenAccounts.js

@@ -0,0 +1,55 @@
+const getTokenAccounts = {
+    description: 'Returns the token accounts for a given set of addresses',
+    method: 'getTokenAccounts',
+    params: [
+      {
+          name: 'mint',
+        type: 'string',
+        description: 'Public key of the mint to retrieve',
+        placeholder: 'Public key of the mint',
+      },
+      {
+        name: 'owner',
+      type: 'string',
+      description: 'Owner public key of the token accounts to revtrieve',
+      placeholder: 'Owner public key',
+    },
+    {
+        name: 'limit',
+        type: 'number',
+        description: 'Number of assets to return',
+      },
+      {
+        name: 'page',
+        type: 'number',
+        description: 'The index of the "page" to retrieve.',
+      },
+      {
+        name: 'cursor',
+        type: 'string',
+        description: 'pagination cursor',
+      },
+      {
+        name: 'before',
+        type: 'string',
+        description: 'Retrieve assets before the specified ID',
+      },
+      {
+        name: 'after',
+        type: 'string',
+        description: 'Retrieve assets after the specified ID',
+      },
+      {
+        name: 'options',
+        type: 'object',
+        value: {
+            showZeroBalance: {
+                type: 'boolean',
+                description: 'Show zero balance accounts',
+            }
+        }
+      }
+    ],
+  }
+  
+  export default getTokenAccounts

+ 161 - 0
src/lib/api/aura/das/searchAssest.js

@@ -0,0 +1,161 @@
+const searchAssets = {
+  description: 'Search of Assets based on parameters',
+  method: 'searchAssets',
+  params: [
+    {
+      name: 'negate',
+      type: 'boolean',
+      description:
+        'Indicates whether the search criteria should be inverted or not.',
+    },
+    {
+      name: 'conditionType',
+      type: 'option',
+      value: ['all', 'any'],
+      description:
+        'Indicates whether to retrieve all ("all") or any ("any") asset that matches the search criteria.',
+    },
+    {
+      name: 'interface',
+      type: 'option',
+      value: [
+        'V1_NFT',
+        'V1_PRINT',
+        'LEGACY_NFT',
+        'V2_NFT',
+        'FungibleAsset',
+        'Custom',
+        'Identity',
+        'Executable',
+      ],
+      description:
+        'The interface value (one of ["V1_NFT", "V1_PRINT", "LEGACY_NFT", "V2_NFT", "FungibleAsset", "Custom", "Identity", "Executable"])',
+    },
+    {
+      name: 'ownerAddress',
+      type: 'string',
+      description: 'The owner address of the asset',
+    },
+    {
+      name: 'ownerType',
+      type: 'option',
+      description: 'Type of ownership',
+      value: ['single', 'token'],
+    },
+    {
+      name: 'creatorAddress',
+      type: 'string',
+      description: 'The creator address of the asset',
+    },
+    {
+      name: 'createVerified',
+      type: 'boolean',
+      description: 'Indicates whether the creator must be verified or not.',
+    },
+    {
+      name: 'authorityAddress',
+      type: 'string',
+      description: 'The authority address of the asset',
+    },
+    {
+      name: 'grouping',
+      type: 'arrayKeyValuePair',
+      locked: true,
+      length: 2,
+      value: [],
+    },
+    {
+      name: 'delegateAddress',
+      type: 'string',
+      description: 'The delegate address of the asset',
+    },
+    {
+      name: 'frozen',
+      type: 'boolean',
+      description: 'Indicates whether the asset is frozen or not.',
+    },
+    {
+      name: 'supply',
+      type: 'number',
+      description: 'The supply of the asset',
+    },
+    {
+      name: 'supplyMint',
+      type: 'string',
+      description: 'The supply mint of the asset',
+    },
+    {
+      name: 'compressed',
+      type: 'boolean',
+      description: 'Indicates whether the asset is compressed or not.',
+    },
+    {
+      name: 'compressible',
+      type: 'boolean',
+      description: 'Indicates whether the asset is compressable or not.',
+    },
+    {
+      name: 'royaltyTargetType',
+      type: 'option',
+      value: ['single', 'creators', 'fanout'],
+      description: 'The royalty type of the asset',
+    },
+    {
+      name: 'royaltyTarget',
+      type: 'string',
+      description: 'The target address for royalties',
+    },
+    {
+      name: 'royaltyAmount',
+      type: 'number',
+      description: 'The royalty amount',
+    },
+    {
+      name: 'burnt',
+      type: 'boolean',
+      description: 'Indicates whether the asset is burnt or not.',
+    },
+    {
+      name: 'sortBy',
+      type: 'object',
+      description: 'Sorting criteria',
+      value: {
+        sortBy: {
+          type: 'option',
+          value: ['created', 'updated', 'recentAction', 'none'],
+        },
+        sortDirection: {
+          type: 'option',
+          value: ['asc', 'desc'],
+        },
+      },
+    },
+    {
+      name: 'limit',
+      type: 'number',
+      description: 'Number of assets to return',
+    },
+    {
+      name: 'page',
+      type: 'number',
+      description: 'The index of the "page" to retrieve.',
+    },
+    {
+      name: 'before',
+      type: 'string',
+      description: 'Retrieve assets before the specified ID',
+    },
+    {
+      name: 'after',
+      type: 'string',
+      description: 'Retrieve assets after the specified ID',
+    },
+    {
+      name: 'jsonUri',
+      type: 'string',
+      description: 'The value of the JSON URI of the asset',
+    },
+  ],
+}
+
+export default searchAssets

+ 30 - 0
src/lib/api/aura/methods.js

@@ -0,0 +1,30 @@
+import getAssetsByAuthority from './das/getAssestByAuthority'
+import getAsset from './das/getAsset'
+import getAssetBatch from './das/getAssetBatch'
+import getAssetProof from './das/getAssetProof'
+import getAssetProofBatch from './das/getAssetProofBatch'
+import getAssetsByCreator from './das/getAssetsByCreator'
+import getAssetsByGroup from './das/getAssetsByGroup'
+import getAssetsByOwner from './das/getAssetsByOwner'
+import getSignaturesForAsset from './das/getSignaturesForAsset'
+import getTokenAccounts from './das/getTokenAccounts'
+import searchAssets from './das/searchAssest'
+
+
+import testApiMethod from './template'
+
+const apiMethods = {
+  testApiMethod: testApiMethod,
+  getAsset: getAsset,
+  getAssetProof: getAssetProof,
+  getAssetsByAuthority: getAssetsByAuthority,
+  getAssetsByCreator: getAssetsByCreator,
+  getAssetsByGroup: getAssetsByGroup,
+  getAssetsByOwner: getAssetsByOwner,
+  getAssetBatch: getAssetBatch,
+  getAssetProofBatch: getAssetProofBatch,
+  searchAssets: searchAssets,
+  getSignaturesForAsset: getSignaturesForAsset,
+  getTokenAccounts: getTokenAccounts,
+}
+export default apiMethods

+ 55 - 0
src/lib/api/aura/template.js

@@ -0,0 +1,55 @@
+// Mock API object
+
+const testApiMethod = {
+  method: 'template',
+  params: [
+    {
+      type: 'string',
+      description: 'Name of the person',
+      name: 'name',
+      value: 'John Doe',
+      placeholder: 'John Doe',
+      availableValues: ['John Doe', 'Jane Doe'],
+      optional: true,
+    },
+    { type: 'number', name: 'age', value: 30, placeholder: 30, optional: true },
+    { type: 'boolean', name: 'isStudent', value: false },
+    {
+      type: 'array',
+      name: 'hobbies',
+      value: [],
+      placeholder: ['reading', 'coding', 'hiking'],
+    },
+    {
+      type: 'object',
+      name: 'address',
+      value: {
+        city: {
+          type: 'string',
+          value: 'Metropolis',
+          placeholder: 'Metropolis',
+        },
+        street: {
+          type: 'string',
+          value: 'Main Street',
+          placeholder: 'Main Street',
+        },
+        zip: { type: 'number', value: 54321, placeholder: 54321 },
+      },
+    },
+    {
+      type: 'string',
+      name: 'dateOfBirth',
+      value: '1992-05-14',
+      placeholder: '1992-05-14',
+    },
+    {
+      type: 'file',
+      name: 'profilePicture',
+      value: 'base64_encoded_string',
+      placeholder: 'base64_encoded_string',
+    },
+  ],
+}
+
+export default testApiMethod

+ 23 - 0
src/lib/api/renderRequestBody.js

@@ -0,0 +1,23 @@
+const renderRequestBody = (params) => {
+  const renderParam = (param) => {
+    switch (param.type) {
+      case 'object':
+        return Object.entries(param.value).reduce((acc, [key, value]) => {
+          acc[key] = renderParam(value)
+          return acc
+        }, {})
+      case 'array':
+        return param.value.map((item) => renderParam(item))
+      default:
+        // Return the value for primitive types
+        return param.value
+    }
+  }
+
+  return params.reduce((acc, param) => {
+    acc[param.name] = renderParam(param)
+    return acc
+  }, {})
+}
+
+export default renderRequestBody

+ 35 - 0
src/lib/api/template.js

@@ -0,0 +1,35 @@
+// Mock API object
+
+const templateApiMethod = {
+  method: 'templateApiMethod',
+  params: [
+    {
+      type: 'string',
+      name: 'name',
+      value: 'John Doe',
+      availableValues: ['John Doe', 'Jane Doe'],
+      optional: true,
+    },
+    { type: 'number', name: 'age', value: 30 },
+    { type: 'boolean', name: 'isStudent', value: false },
+    {
+      type: 'array',
+      name: 'hobbies',
+      value: ['reading', 'coding', 'hiking'],
+    },
+    {
+      type: 'object',
+      name: 'address',
+      value: {
+        city: { type: 'string', value: 'Metropolis' },
+        street: { type: 'string', value: 'Main Street' },
+        zip: { type: 'number', value: 54321 },
+      },
+    },
+    { type: 'null', name: 'middleName', value: null },
+    { type: 'string', name: 'dateOfBirth', value: '1992-05-14' },
+    { type: 'file', name: 'profilePicture', value: 'base64_encoded_string' },
+  ],
+}
+
+export default templateApiMethod

+ 10 - 0
src/pages/aura/api/v1/das/get-asset-batch.md

@@ -0,0 +1,10 @@
+---
+title: Get Asset Batch
+metaTitle: Get Asset Batch Method | Aura API
+description: Learn about the Get Asset Batch Aura API Method.
+---
+
+Fetch a batch of NFT Digital Assets from the Solana blockchain including NFTs, pNFTs, cNFTs.
+
+{% apiRenderer method="getAssetBatch" /%}
+

+ 9 - 0
src/pages/aura/api/v1/das/get-asset-proof-batch.md

@@ -0,0 +1,9 @@
+---
+title: Get Asset Proof Batch
+metaTitle: Get Asset Proof Batch Method | Aura API
+description: Learn about the Get Asset Proof Batch Aura API Method.
+---
+
+Fetch a batch of Compressed NFT Digital Asset (cNFT) Proofs Metaplex Aura DAS API.
+
+{% apiRenderer method="getAssetProofBatch" /%}

+ 10 - 0
src/pages/aura/api/v1/das/get-asset-proof.md

@@ -0,0 +1,10 @@
+---
+title: Get Asset Proof
+metaTitle: Get Asset Proof Method | Aura API
+description: Learn about the GetAsset Aura API Method.
+---
+
+Fetch the proof of a Compressed NFT Digial Asset (cNFT) with Aura DAS API.
+
+{% apiRenderer method="getAssetProof" /%}
+

+ 9 - 0
src/pages/aura/api/v1/das/get-asset.md

@@ -0,0 +1,9 @@
+---
+title: Get Asset
+metaTitle: Get Asset Method | Aura API
+description: Learn about the Get Asset Aura API Method.
+---
+
+Fetch an NFT Digital Asset from the Solana blockchain including NFTs, pNFTs, cNFTs.
+
+{% apiRenderer method="getAsset" /%}

+ 10 - 0
src/pages/aura/api/v1/das/get-assets-by-authority.md

@@ -0,0 +1,10 @@
+---
+title: Get Assets by Authority
+metaTitle: Get Assets by Authority Method | Aura API
+description: Learn about the Get Assets by Authority Aura API Method.
+---
+
+Returns the list of assets given an authority address.
+
+{% apiRenderer method="getAssetsByAuthority" /%}
+

+ 10 - 0
src/pages/aura/api/v1/das/get-assets-by-creator.md

@@ -0,0 +1,10 @@
+---
+title: Get Assets by Creator
+metaTitle: Get Assets by Creator Method | Aura API
+description: Learn about the Get Assets by Creator Aura API Method.
+---
+
+Returns a list of assets based on a given creator address.
+
+{% apiRenderer method="getAssetsByCreator" /%}
+

+ 9 - 0
src/pages/aura/api/v1/das/get-assets-by-group.md

@@ -0,0 +1,9 @@
+---
+title: Get Assets by Group
+metaTitle: Get Assets by Group Method | Aura API
+description: Learn about the Get Assets by Group Aura API Method.
+---
+
+Return the list of assets given a group (key, value) pair. For example this can be used to get all assets in a collection.
+
+{% apiRenderer method="getAssetsByGroup" /%}

+ 9 - 0
src/pages/aura/api/v1/das/get-assets-by-owner.md

@@ -0,0 +1,9 @@
+---
+title: Get Assets by Owner
+metaTitle: Get Assets by Owner Method | Aura API
+description: Learn about the Get Assets by Owner Aura API Method.
+---
+
+Return a list of assets ownened by a particular public key.
+
+{% apiRenderer method="getAssetsByOwner" /%}

+ 9 - 0
src/pages/aura/api/v1/das/get-signatures-for-asset.md

@@ -0,0 +1,9 @@
+---
+title: Get Signatures For Asset
+metaTitle: Get Signatures For Asset | Aura API
+description: Learn about the Get Signatures For Asset Aura API Method.
+---
+
+Search and return a list of signatures associated with a digial asset.
+
+{% apiRenderer method="getSignaturesForAsset" /%}

+ 9 - 0
src/pages/aura/api/v1/das/get-token-accounts.md

@@ -0,0 +1,9 @@
+---
+title: Get Token Accounts
+metaTitle: Get Token Accounts | Aura API
+description: Learn about the Get Token Accounts Aura API Method.
+---
+
+Search and return a list of token accounts based on criteria.
+
+{% apiRenderer method="getTokenAccounts" /%}

+ 9 - 0
src/pages/aura/api/v1/das/search-assets.md

@@ -0,0 +1,9 @@
+---
+title: Search Asset
+metaTitle: Search Asset Method | Aura API
+description: Learn about the Search Asset Aura API Method.
+---
+
+Return the list of assets given a search criteria.
+
+{% apiRenderer method="searchAssets" /%}

+ 8 - 0
src/pages/aura/api/v1/testApiMethod.md

@@ -0,0 +1,8 @@
+---
+title: Test Api Method
+metaTitle: Test Api Method | Aura Api
+description: Learn how Batch Minting works.
+---
+
+
+{% apiRenderer method="testApiMethod" /%}

+ 5 - 5
src/pages/candy-machine/guards.md

@@ -336,7 +336,7 @@ import { some, percentAmount, sol, dateTime } from '@metaplex-foundation/umi'
 
 // Create a Candy Machine without a Candy Guard.
 const candyMachine = generateSigner(umi)
-await createCandyMachineV2({
+await (await createCandyMachineV2(umi, {
   candyMachine,
   tokenStandard: TokenStandard.NonFungible,
   collectionMint: collectionMint.publicKey,
@@ -353,12 +353,12 @@ await createCandyMachineV2({
     uriLength: 20,
     isSequential: false,
   }),
-}).sendAndConfirm(umi)
+})).sendAndConfirm(umi)
 
 // Create a Candy Guard.
 const base = generateSigner(umi)
 const candyGuard = findCandyGuardPda(umi, { base: base.publicKey })
-await createCandyGuard({
+await createCandyGuard(umi, {
   base,
   guards: {
     botTax: { lamports: sol(0.01), lastInstruction: false },
@@ -368,13 +368,13 @@ await createCandyGuard({
 }).sendAndConfirm(umi)
 
 // Associate the Candy Guard with the Candy Machine.
-await wrap({
+await wrap(umi, {
   candyMachine: candyMachine.publicKey,
   candyGuard,
 }).sendAndConfirm(umi)
 
 // Dissociate them.
-await unwrap({
+await unwrap(umi, {
   candyMachine: candyMachine.publicKey,
   candyGuard,
 }).sendAndConfirm(umi)

+ 468 - 0
src/pages/candy-machine/guides/airdrop-mint-to-another-wallet.md

@@ -0,0 +1,468 @@
+---
+title: Airdrops - How to Mint NFTs to another Wallet
+metaTitle: Airdrops - Mint from Candy Machine to a different wallet | Candy Machine
+description: A developer guide on how to mint NFTs from a Candy Machine to a different wallet address. Useful for airdrops and similar use cases.
+---
+
+This guide explains how to mint NFTs from a Candy Machine to different wallet addresses - a common requirement for airdrops, giveaways, or distributing NFTs to multiple recipients.
+
+## Prerequisites
+
+- Basic understanding of Solana and NFTs
+- A funded wallet for transaction fees
+
+**either**
+
+- Sugar CLI (v2.0.0 or higher)
+
+**or**
+
+- Node.js 16.0 or higher
+- @metaplex-foundation/mpl-token-metadata
+- @metaplex-foundation/mpl-toolbox
+- @metaplex-foundation/umi-bundle-defaults
+- @metaplex-foundation/mpl-candy-machine
+
+Minting NFTs to another wallet can be particularly useful for airdrops, giveaways, or distributing NFTs to multiple recipients. This guide will walk you through the process of minting NFTs from a Candy Machine to a different wallet address. It is important to note that the person initiating the minting process will bear the minting cost. Therefore, it is often more cost-effective to have the recipient claim the NFT themselves.
+
+{% callout type="note" title="Important Consideration" %}
+- Minting to another wallet can be expensive. You might want to consider using a claim mechanic instead, e.g. using [allowlist](/candy-machine/guards/allow-list) or the [NFT Gate](/candy-machine/guards/nft-gate) Guard. 
+- There are different tools available for Candy Machines with or without guards. Minting without guards is generally easier.
+{% /callout %}
+
+There are two approaches described in this guide:
+1. Mint using [Sugar CLI](#using-sugar-cli). No Coding required!
+2. Mint using [Javascript](#using-typescript-and-metaplex-foundation-mpl-candy-machine)
+
+## Using Sugar CLI
+The Sugar CLI provides two main commands for minting NFTs to other wallets:
+1. `sugar mint` to mint to *one* specific wallet
+2. `sugar airdrop` to mint to *multiple* wallets 
+
+Prerequisite to allow minting through sugar is to have your Candy Machine created **without guard attached**. To create a Candy Machine with sugar you can follow the first steps of [this](https://developers.metaplex.com/candy-machine/guides/create-an-nft-collection-on-solana-with-candy-machine) Guide. If your Candy Machine has guards attached they can be removed using `sugar guard remove`.
+
+### Single Recipient Minting with `sugar mint`
+To mint NFTs to a single recipient wallet, use the `sugar mint` command with these parameters:
+
+- `--receiver <WALLET>`: Specify the recipient's wallet address
+- `--number <NUMBER>`: (Optional) Specify how many NFTs to mint to that wallet
+
+**Example**:
+
+To mint 3 NFTs to the wallet `Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV` one would call:
+
+```sh
+sugar mint --receiver Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV -n 3 --candy-machine 11111111111111111111111111111111
+```
+
+### Multiple Recipients with `sugar airdrop`
+
+To mint NFTs to multiple wallets in a single command `sugar airdrop` can be used. It requires a file containing the addresses and the amount of NFTs each wallet should receive. A file like this could for example be created by snapshotting the owners of NFTs in a specific collection and adding their wallets and NFTs they hold into a file in the following format:
+
+```json
+{
+  "11111111111111111111111111111111": 3,
+  "22222222222222222222222222222222": 1
+}
+```
+
+By default sugar expects this file to be called `airdrop_list.json` but if if you wish to use a file of which has a different file name you can pass the file name in using
+`--airdrop-list`.
+
+**Example**:
+To execute this airdrop the following command can be used
+```sh
+sugar airdrop --candy-machine 11111111111111111111111111111111
+```
+
+## Using Typescript and `@metaplex-foundation/mpl-candy-machine`
+
+In this section the code Snippets for the mint functions in Javascript are shown. Both examples also include a full code snippet where a Candy Machine is created and afterwards a single NFT is minted to a specific wallet. To implement a full blown airdrop script one needs to implement loops and error handling around the mint function.
+
+When minting to another wallet using Typescript, there are two main approaches depending on whether your Candy Machine uses guards:
+
+### Mint without guards
+For Candy Machines without guards, use `mintFromCandyMachineV2`. This function allows you to directly specify the recipient as the `nftOwner`.
+
+```js
+const candyMachineAccount = await fetchCandyMachine(umi, publicKey("CM Address"));
+
+const recipient = publicKey('Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV')
+const nftMint = generateSigner(umi)
+const mintTx = await transactionBuilder()
+  .add(setComputeUnitLimit(umi, { units: 800_000 }))
+  .add(createMintWithAssociatedToken(umi, { mint: nftMint, owner: recipient }))
+  .add(
+    mintV2(umi, {
+      candyMachine: candyMachineAccount.publicKey,
+      nftMint,
+      token: findAssociatedTokenPda(umi, {
+        mint: nftMint.publicKey,
+        owner: recipient,
+      }),
+      collectionMint: candyMachineAccount.collectionMint,
+      collectionUpdateAuthority: candyMachineAccount.authority,
+      tokenStandard: TokenStandard.NonFungible,
+      mintArgs: {
+        mintLimit: some({ // The guards that require mintArgs have to be specified here 
+          id: 1,
+        }),
+      },
+    })
+  )
+  .sendAndConfirm(umi, {
+    confirm: { commitment: 'finalized' },
+  })
+```
+
+{% totem %}
+{% totem-accordion title="Full Code Example" %}
+```js
+import {
+  addConfigLines,
+  createCandyMachineV2,
+  fetchCandyMachine,
+  mintFromCandyMachineV2,
+  mplCandyMachine,
+} from "@metaplex-foundation/mpl-candy-machine";
+import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
+import {
+  generateSigner,
+  keypairIdentity,
+  percentAmount,
+  publicKey,
+  sol,
+  some,
+  transactionBuilder,
+} from "@metaplex-foundation/umi";
+import {
+  createNft,
+  TokenStandard,
+} from "@metaplex-foundation/mpl-token-metadata";
+import { base58 } from "@metaplex-foundation/umi-serializers";
+import {
+  createMintWithAssociatedToken,
+  setComputeUnitLimit,
+} from "@metaplex-foundation/mpl-toolbox";
+
+/**
+ * This script demonstrates how to create a basic Candy Machine without guards
+ * and mint an NFT to a recipient wallet.
+ */
+
+// Configuration
+const RECIPIENT_ADDRESS = "Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV";
+const RPC_ENDPOINT = "https://devnet.helius-rpc.com/?api-key=0aa5bfbe-0077-4414-9d87-02ffa09cc50b";
+
+(async () => {
+  try {
+    // --- Setup ---
+    
+    // Initialize connection to Solana
+    const umi = createUmi(RPC_ENDPOINT).use(mplCandyMachine());
+    const recipient = publicKey(RECIPIENT_ADDRESS);
+
+    // Create and fund a test wallet
+    const walletSigner = generateSigner(umi);
+    umi.use(keypairIdentity(walletSigner));
+    console.log("Funding test wallet with devnet SOL...");
+    await umi.rpc.airdrop(walletSigner.publicKey, sol(0.1), {
+      commitment: "finalized",
+    });
+
+    // --- Create Collection NFT ---
+    
+    const collectionMint = generateSigner(umi);
+    console.log("Creating collection NFT...");
+    console.log("Collection Address:", collectionMint.publicKey);
+
+    const createNftTx = await createNft(umi, {
+      mint: collectionMint,
+      authority: umi.identity,
+      name: "My Collection NFT",
+      uri: "https://example.com/path/to/some/json/metadata.json",
+      sellerFeeBasisPoints: percentAmount(9.99, 2),
+      isCollection: true,
+    }).sendAndConfirm(umi, {
+      confirm: { commitment: "finalized" },
+    });
+    console.log("Collection Created:", base58.deserialize(createNftTx.signature)[0]);
+
+    // --- Create Candy Machine ---
+
+    console.log("Creating basic Candy Machine...");
+    const candyMachine = generateSigner(umi);
+    
+    const createCandyMachineV2Tx = await (
+      await createCandyMachineV2(umi, {
+        candyMachine,
+        tokenStandard: TokenStandard.NonFungible,
+        collectionMint: collectionMint.publicKey,
+        collectionUpdateAuthority: umi.identity,
+        itemsAvailable: 2,
+        sellerFeeBasisPoints: percentAmount(1.23),
+        creators: [
+          {
+            address: umi.identity.publicKey,
+            verified: false,
+            percentageShare: 100,
+          },
+        ],
+        configLineSettings: some({
+          prefixName: "My NFT #",
+          nameLength: 3,
+          prefixUri: "https://example.com/",
+          uriLength: 29,
+          isSequential: false,
+        }),
+      })
+    )
+      .add(
+        addConfigLines(umi, {
+          candyMachine: candyMachine.publicKey,
+          index: 0,
+          configLines: [
+            { name: "1", uri: "https://example.com/nft1.json" },
+            { name: "2", uri: "https://example.com/nft2.json" },
+          ],
+        })
+      )
+      .sendAndConfirm(umi, { confirm: { commitment: "finalized" } });
+      
+    console.log("Candy Machine Created:", base58.deserialize(createCandyMachineV2Tx.signature)[0]);
+
+    // --- Mint NFT ---
+
+    console.log("Minting NFT to recipient...");
+    
+    // Get latest Candy Machine state
+    const candyMachineAccount = await fetchCandyMachine(umi, candyMachine.publicKey);
+
+    // Create mint transaction
+    const nftMint = generateSigner(umi);
+    const mintTx = await transactionBuilder()
+      .add(setComputeUnitLimit(umi, { units: 800_000 }))
+      .add(
+        createMintWithAssociatedToken(umi, { mint: nftMint, owner: recipient })
+      )
+      .add(
+        mintFromCandyMachineV2(umi, {
+          candyMachine: candyMachine.publicKey,
+          mintAuthority: umi.identity,
+          nftOwner: recipient,
+          nftMint,
+          collectionMint: candyMachineAccount.collectionMint,
+          collectionUpdateAuthority: candyMachineAccount.authority,
+        })
+      )
+      .sendAndConfirm(umi, {
+        confirm: { commitment: "finalized" },
+      });
+
+    console.log("NFT Minted Successfully!");  
+    console.log("Mint Transaction:", base58.deserialize(mintTx.signature)[0]);
+
+  } catch (error) {
+    console.error("Failed to execute:", error);
+  }
+})();
+
+```
+{% /totem-accordion  %}
+{% /totem %}
+
+### Mint with Guards
+For Candy Machines with guards `mintV2` can be used. In this case, you'll need to first create the Token Account and Associated Token Account for the recipient using `createMintWithAssociatedToken`. This allows the recipient to receive the NFT without having to sign the transaction.
+
+```js
+const candyMachineAccount = await fetchCandyMachine(umi, publicKey("CM Address"));
+
+const recipient = publicKey('Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV')
+const nftMint = generateSigner(umi)
+const mintTx = await transactionBuilder()
+  .add(setComputeUnitLimit(umi, { units: 800_000 }))
+  .add(createMintWithAssociatedToken(umi, { mint: nftMint, owner: recipient }))
+  .add(
+    mintFromCandyMachineV2(umi, {
+      candyMachine: candyMachine.publicKey,
+      mintAuthority: umi.identity,
+      nftOwner: recipient,
+      nftMint,
+      collectionMint: candyMachineAccount.collectionMint,
+      collectionUpdateAuthority: candyMachineAccount.authority,
+    })
+  )
+  .sendAndConfirm(umi, {
+    confirm: { commitment: 'finalized' },
+  })
+```
+
+{% totem %}
+{% totem-accordion title="Full Code Example" %}
+```js
+import {
+  addConfigLines,
+  create,
+  fetchCandyMachine,
+  mintV2,
+  mplCandyMachine,
+} from "@metaplex-foundation/mpl-candy-machine";
+import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
+import {
+  generateSigner,
+  keypairIdentity,
+  percentAmount,
+  publicKey,
+  sol,
+  some,
+  transactionBuilder,
+} from "@metaplex-foundation/umi";
+import {
+  createNft,
+  TokenStandard,
+} from "@metaplex-foundation/mpl-token-metadata";
+import { base58 } from "@metaplex-foundation/umi-serializers";
+import {
+  createMintWithAssociatedToken,
+  findAssociatedTokenPda,
+  setComputeUnitLimit,
+} from "@metaplex-foundation/mpl-toolbox";
+
+/**
+ * This script demonstrates how to create a Candy Machine with a mint limit guard
+ * and mint an NFT to a recipient wallet.
+ */
+
+// Configuration
+const RECIPIENT_ADDRESS = "Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV";
+const RPC_ENDPOINT = "ENDPOINT";
+
+(async () => {
+  try {
+    // --- Setup ---
+    
+    // Initialize connection to Solana
+    const umi = createUmi(RPC_ENDPOINT).use(mplCandyMachine());
+    const recipient = publicKey(RECIPIENT_ADDRESS);
+
+    // Create and fund a test wallet
+    const walletSigner = generateSigner(umi);
+    umi.use(keypairIdentity(walletSigner));
+    console.log("Funding test wallet with devnet SOL...");
+    await umi.rpc.airdrop(walletSigner.publicKey, sol(0.1), {
+      commitment: "finalized",
+    });
+
+    // --- Create Collection NFT ---
+    
+    const collectionMint = generateSigner(umi);
+    console.log("Creating collection NFT...");
+    console.log("Collection Address:", collectionMint.publicKey);
+
+    const createNftTx = await createNft(umi, {
+      mint: collectionMint,
+      authority: umi.identity,
+      name: "My Collection NFT",
+      uri: "https://example.com/path/to/some/json/metadata.json",
+      sellerFeeBasisPoints: percentAmount(9.99, 2),
+      isCollection: true,
+    }).sendAndConfirm(umi, {
+      confirm: { commitment: "finalized" },
+    });
+    console.log("Collection Created:", base58.deserialize(createNftTx.signature)[0]);
+
+    // --- Create Candy Machine ---
+
+    console.log("Creating Candy Machine with mint limit guard...");
+    const candyMachine = generateSigner(umi);
+    
+    const createCandyMachineV2Tx = await (
+      await create(umi, {
+        candyMachine,
+        tokenStandard: TokenStandard.NonFungible,
+        collectionMint: collectionMint.publicKey,
+        collectionUpdateAuthority: umi.identity,
+        itemsAvailable: 2,
+        sellerFeeBasisPoints: percentAmount(1.23),
+        creators: [
+          {
+            address: umi.identity.publicKey,
+            verified: false,
+            percentageShare: 100,
+          },
+        ],
+        guards: {
+          mintLimit: some({
+            id: 1,
+            limit: 2,
+          }),
+        },
+        configLineSettings: some({
+          prefixName: "My NFT #",
+          nameLength: 3,
+          prefixUri: "https://example.com/",
+          uriLength: 29,
+          isSequential: false,
+        }),
+      })
+    )
+      .add(
+        addConfigLines(umi, {
+          candyMachine: candyMachine.publicKey,
+          index: 0,
+          configLines: [
+            { name: "1", uri: "https://example.com/nft1.json" },
+            { name: "2", uri: "https://example.com/nft2.json" },
+          ],
+        })
+      )
+      .sendAndConfirm(umi, { confirm: { commitment: "finalized" } });
+      
+    console.log("Candy Machine Created:", base58.deserialize(createCandyMachineV2Tx.signature)[0]);
+
+    // --- Mint NFT ---
+
+    console.log("Minting NFT to recipient...");
+    
+    // Get latest Candy Machine state
+    const candyMachineAccount = await fetchCandyMachine(umi, candyMachine.publicKey);
+
+    // Create mint transaction
+    const nftMint = generateSigner(umi);
+    const mintTx = await transactionBuilder()
+      .add(setComputeUnitLimit(umi, { units: 800_000 }))
+      .add(
+        createMintWithAssociatedToken(umi, { mint: nftMint, owner: recipient })
+      )
+      .add(
+        mintV2(umi, {
+          candyMachine: candyMachineAccount.publicKey,
+          nftMint,
+          token: findAssociatedTokenPda(umi, {
+            mint: nftMint.publicKey,
+            owner: recipient,
+          }),
+          collectionMint: candyMachineAccount.collectionMint,
+          collectionUpdateAuthority: candyMachineAccount.authority,
+          tokenStandard: TokenStandard.NonFungible,
+          mintArgs: {
+            mintLimit: some({
+              id: 1,
+            }),
+          },
+        })
+      )
+      .sendAndConfirm(umi, {
+        confirm: { commitment: "finalized" },
+      });
+
+    console.log("NFT Minted Successfully!");
+    console.log("Mint Transaction:", base58.deserialize(mintTx.signature)[0]);
+
+  } catch (error) {
+    console.error("Failed to execute:", error);
+  }
+})();
+```
+{% /totem-accordion %}
+{% /totem %}

+ 4 - 2
src/pages/candy-machine/guides/index.md

@@ -4,5 +4,7 @@ metaTitle: Guides for Metaplex Candy Machine | Candy Machine
 description: A list of guides for the Metaplex Candy Machine for creating NFT collections on Solana.
 ---
 
-
-{% quick-link title="Create an NFT Collection on Solana using Candy Machine" icon="CodeBracketSquare" href="/candy-machine/guides/create-an-nft-collection-on-solana-with-candy-machine" description="Learn how to launch an NFT collection on Solana using Metaplex Candy Machine and the Sugar CLI" /%}
+{% quick-links %}
+{% quick-link title="Airdrop example - Mint NFTs to Another Wallet" icon="CodeBracketSquare" href="/candy-machine/guides/airdrop-mint-to-another-wallet" description="Learn how to Airdrop NFT using Sugar CLI or Typescript" /%}
+{% quick-link title="Create an NFT Collection on Solana using Candy Machine" icon="CodeBracketSquare" href="/candy-machine/guides/create-an-nft-collection-on-solana-with-candy-machine" description="Learn how to launch an NFT collection on Solana using Metaplex Candy Machine and the Sugar CLI" /%}
+{% /quick-links %}

+ 463 - 0
src/pages/candy-machine/guides/mint-to-another-wallet.md

@@ -0,0 +1,463 @@
+---
+title: How to Mint NFTs to Another Wallet - Airdrop example
+metaTitle: Mint from Candy Machine to a different wallet | Candy Machine
+description: A developer guide on how to mint NFTs from a Candy Machine to a different wallet address. Useful for airdrops and similar use cases.
+---
+
+## Overview
+This guide explains how to mint NFTs from a Candy Machine to different wallet addresses - a common requirement for airdrops, giveaways, or distributing NFTs to multiple recipients.
+
+## Prerequisites
+Either
+- Basic understanding of Solana and NFTs
+- A funded wallet for transaction fees
+
+- Sugar CLI (v2.0.0 or higher)
+Or
+- Node.js 16.0 or higher
+- @metaplex-foundation/mpl-token-metadata
+- @metaplex-foundation/mpl-toolbox
+- @metaplex-foundation/umi-bundle-defaults
+- @metaplex-foundation/mpl-candy-machine
+
+Minting NFTs to another wallet can be particularly useful for airdrops, giveaways, or distributing NFTs to multiple recipients. This guide will walk you through the process of minting NFTs from a Candy Machine to a different wallet address. It is important to note that the person initiating the minting process will bear the minting cost. Therefore, it is often more cost-effective to have the recipient claim the NFT themselves.
+
+{% callout type="note" title="Important Consideration" %}
+- Minting to another wallet can be expensive. You might want to consider using a claim mechanic instead.
+- There are different tools available for Candy Machines with or without guards. Minting without guards is generally easier.
+{% /callout %}
+
+There are two approaches described in this guide:
+1. Mint using [sugar CLI](#using-sugar-cli)
+2. Mint using [Javascript](#using-typescript-and-mpl-candy-machine)
+
+## Using Sugar CLI
+The Sugar CLI provides two main commands for minting NFTs to other wallets:
+1. `sugar mint` to mint to *one* specific wallet
+2. `sugar airdrop` to mint to *multiple* wallets 
+
+### Single Recipient Minting with `sugar mint`
+To mint NFTs to a single recipient wallet, use the `sugar mint` command with these parameters:
+
+- `--receiver <WALLET>`: Specify the recipient's wallet address
+- `--number <NUMBER>`: (Optional) Specify how many NFTs to mint to that wallet
+
+**Example**:
+
+To mint 3 NFT to wallet Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV one would call:
+
+```sh
+sugar mint --receiver Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV -n 3 --candy-machine 11111111111111111111111111111111
+```
+
+### Multiple Recipients with `sugar airdrop`
+
+To mint NFTs to multiple wallets in a single command `sugar airdrop` can be used. It requires a file containing the addresses and the amount of NFTs each wallet should receive. A file like this could for example be created by snapshotting the owners of NFTs in a specific collection and adding their wallets and NFTs they hold into a file in the following format:
+
+```json
+{
+  "22222222222222222222222222222222": 3,
+  "33333333333333333333333333333333": 1
+}
+```
+
+By default sugar expects this file to be called `airdrop_list.json`. This default name can be changed with 
+`--airdrop-list`.
+
+**Example**:
+To execute this airdrop the following command can be used
+```sh
+sugar airdrop --candy-machine 11111111111111111111111111111111
+```
+
+## Using Typescript and `mpl-candy-machine`
+
+In this section the code Snippets for mint functions in Javascript are shown. Both examples also include a full code snippet where a candy machine is created and afterwards a single NFT is minted. To implement a full blown airdrop script one needs to implement loops and error handling around the mint function.
+
+When minting to another wallet using Typescript, there are two main approaches depending on whether your Candy Machine uses guards:
+
+### Mint without guards
+For Candy Machines without guards, use `mintFromCandyMachineV2`. This function allows you to directly specify the recipient as the `nftOwner`.
+
+```js
+const candyMachineAccount = await fetchCandyMachine(umi, publicKey("CM Address"));
+
+const recipient = publicKey('Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV')
+const nftMint = generateSigner(umi)
+const mintTx = await transactionBuilder()
+  .add(setComputeUnitLimit(umi, { units: 800_000 }))
+  .add(createMintWithAssociatedToken(umi, { mint: nftMint, owner: recipient }))
+  .add(
+    mintV2(umi, {
+      candyMachine: candyMachineAccount.publicKey,
+      nftMint,
+      token: findAssociatedTokenPda(umi, {
+        mint: nftMint.publicKey,
+        owner: recipient,
+      }),
+      collectionMint: candyMachineAccount.collectionMint,
+      collectionUpdateAuthority: candyMachineAccount.authority,
+      tokenStandard: TokenStandard.NonFungible,
+      mintArgs: {
+        mintLimit: some({ // The guards that require mintArgs have to be specified here 
+          id: 1,
+        }),
+      },
+    })
+  )
+  .sendAndConfirm(umi, {
+    confirm: { commitment: 'finalized' },
+  })
+```
+
+{% totem %}
+{% totem-accordion title="Full Code Example" %}
+```js
+import {
+  addConfigLines,
+  createCandyMachineV2,
+  fetchCandyMachine,
+  mintFromCandyMachineV2,
+  mplCandyMachine,
+} from "@metaplex-foundation/mpl-candy-machine";
+import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
+import {
+  generateSigner,
+  keypairIdentity,
+  percentAmount,
+  publicKey,
+  sol,
+  some,
+  transactionBuilder,
+} from "@metaplex-foundation/umi";
+import {
+  createNft,
+  TokenStandard,
+} from "@metaplex-foundation/mpl-token-metadata";
+import { base58 } from "@metaplex-foundation/umi-serializers";
+import {
+  createMintWithAssociatedToken,
+  setComputeUnitLimit,
+} from "@metaplex-foundation/mpl-toolbox";
+
+/**
+ * This script demonstrates how to create a basic Candy Machine without guards
+ * and mint an NFT to a recipient wallet.
+ */
+
+// Configuration
+const RECIPIENT_ADDRESS = "Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV";
+const RPC_ENDPOINT = "https://devnet.helius-rpc.com/?api-key=0aa5bfbe-0077-4414-9d87-02ffa09cc50b";
+
+(async () => {
+  try {
+    // --- Setup ---
+    
+    // Initialize connection to Solana
+    const umi = createUmi(RPC_ENDPOINT).use(mplCandyMachine());
+    const recipient = publicKey(RECIPIENT_ADDRESS);
+
+    // Create and fund a test wallet
+    const walletSigner = generateSigner(umi);
+    umi.use(keypairIdentity(walletSigner));
+    console.log("Funding test wallet with devnet SOL...");
+    await umi.rpc.airdrop(walletSigner.publicKey, sol(0.1), {
+      commitment: "finalized",
+    });
+
+    // --- Create Collection NFT ---
+    
+    const collectionMint = generateSigner(umi);
+    console.log("Creating collection NFT...");
+    console.log("Collection Address:", collectionMint.publicKey);
+
+    const createNftTx = await createNft(umi, {
+      mint: collectionMint,
+      authority: umi.identity,
+      name: "My Collection NFT",
+      uri: "https://example.com/path/to/some/json/metadata.json",
+      sellerFeeBasisPoints: percentAmount(9.99, 2),
+      isCollection: true,
+    }).sendAndConfirm(umi, {
+      confirm: { commitment: "finalized" },
+    });
+    console.log("Collection Created:", base58.deserialize(createNftTx.signature)[0]);
+
+    // --- Create Candy Machine ---
+
+    console.log("Creating basic Candy Machine...");
+    const candyMachine = generateSigner(umi);
+    
+    const createCandyMachineV2Tx = await (
+      await createCandyMachineV2(umi, {
+        candyMachine,
+        tokenStandard: TokenStandard.NonFungible,
+        collectionMint: collectionMint.publicKey,
+        collectionUpdateAuthority: umi.identity,
+        itemsAvailable: 2,
+        sellerFeeBasisPoints: percentAmount(1.23),
+        creators: [
+          {
+            address: umi.identity.publicKey,
+            verified: false,
+            percentageShare: 100,
+          },
+        ],
+        configLineSettings: some({
+          prefixName: "My NFT #",
+          nameLength: 3,
+          prefixUri: "https://example.com/",
+          uriLength: 29,
+          isSequential: false,
+        }),
+      })
+    )
+      .add(
+        addConfigLines(umi, {
+          candyMachine: candyMachine.publicKey,
+          index: 0,
+          configLines: [
+            { name: "1", uri: "https://example.com/nft1.json" },
+            { name: "2", uri: "https://example.com/nft2.json" },
+          ],
+        })
+      )
+      .sendAndConfirm(umi, { confirm: { commitment: "finalized" } });
+      
+    console.log("Candy Machine Created:", base58.deserialize(createCandyMachineV2Tx.signature)[0]);
+
+    // --- Mint NFT ---
+
+    console.log("Minting NFT to recipient...");
+    
+    // Get latest Candy Machine state
+    const candyMachineAccount = await fetchCandyMachine(umi, candyMachine.publicKey);
+
+    // Create mint transaction
+    const nftMint = generateSigner(umi);
+    const mintTx = await transactionBuilder()
+      .add(setComputeUnitLimit(umi, { units: 800_000 }))
+      .add(
+        createMintWithAssociatedToken(umi, { mint: nftMint, owner: recipient })
+      )
+      .add(
+        mintFromCandyMachineV2(umi, {
+          candyMachine: candyMachine.publicKey,
+          mintAuthority: umi.identity,
+          nftOwner: recipient,
+          nftMint,
+          collectionMint: candyMachineAccount.collectionMint,
+          collectionUpdateAuthority: candyMachineAccount.authority,
+        })
+      )
+      .sendAndConfirm(umi, {
+        confirm: { commitment: "finalized" },
+      });
+
+    console.log("NFT Minted Successfully!");  
+    console.log("Mint Transaction:", base58.deserialize(mintTx.signature)[0]);
+
+  } catch (error) {
+    console.error("Failed to execute:", error);
+  }
+})();
+
+```
+{% /totem-accordion  %}
+{% /totem %}
+
+### Mint with Guards
+For Candy Machines with guards, use `mintV2`. In this case, you'll need to first create the Token Account and Associated Token Account for the recipient using `createMintWithAssociatedToken`. This allows the recipient to receive the NFT without having to sign the transaction.
+
+```js
+const candyMachineAccount = await fetchCandyMachine(umi, publicKey("CM Address"));
+
+const recipient = publicKey('Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV')
+const nftMint = generateSigner(umi)
+const mintTx = await transactionBuilder()
+  .add(setComputeUnitLimit(umi, { units: 800_000 }))
+  .add(createMintWithAssociatedToken(umi, { mint: nftMint, owner: recipient }))
+  .add(
+    mintFromCandyMachineV2(umi, {
+      candyMachine: candyMachine.publicKey,
+      mintAuthority: umi.identity,
+      nftOwner: recipient,
+      nftMint,
+      collectionMint: candyMachineAccount.collectionMint,
+      collectionUpdateAuthority: candyMachineAccount.authority,
+    })
+  )
+  .sendAndConfirm(umi, {
+    confirm: { commitment: 'finalized' },
+  })
+```
+
+{% totem %}
+{% totem-accordion title="Full Code Example" %}
+```js
+import {
+  addConfigLines,
+  create,
+  fetchCandyMachine,
+  mintV2,
+  mplCandyMachine,
+} from "@metaplex-foundation/mpl-candy-machine";
+import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
+import {
+  generateSigner,
+  keypairIdentity,
+  percentAmount,
+  publicKey,
+  sol,
+  some,
+  transactionBuilder,
+} from "@metaplex-foundation/umi";
+import {
+  createNft,
+  TokenStandard,
+} from "@metaplex-foundation/mpl-token-metadata";
+import { base58 } from "@metaplex-foundation/umi-serializers";
+import {
+  createMintWithAssociatedToken,
+  findAssociatedTokenPda,
+  setComputeUnitLimit,
+} from "@metaplex-foundation/mpl-toolbox";
+
+/**
+ * This script demonstrates how to create a Candy Machine with a mint limit guard
+ * and mint an NFT to a recipient wallet.
+ */
+
+// Configuration
+const RECIPIENT_ADDRESS = "Tes1zkZkXhgTaMFqVgbgvMsVkRJpq4Y6g54SbDBeKVV";
+const RPC_ENDPOINT = "ENDPOINT";
+
+(async () => {
+  try {
+    // --- Setup ---
+    
+    // Initialize connection to Solana
+    const umi = createUmi(RPC_ENDPOINT).use(mplCandyMachine());
+    const recipient = publicKey(RECIPIENT_ADDRESS);
+
+    // Create and fund a test wallet
+    const walletSigner = generateSigner(umi);
+    umi.use(keypairIdentity(walletSigner));
+    console.log("Funding test wallet with devnet SOL...");
+    await umi.rpc.airdrop(walletSigner.publicKey, sol(0.1), {
+      commitment: "finalized",
+    });
+
+    // --- Create Collection NFT ---
+    
+    const collectionMint = generateSigner(umi);
+    console.log("Creating collection NFT...");
+    console.log("Collection Address:", collectionMint.publicKey);
+
+    const createNftTx = await createNft(umi, {
+      mint: collectionMint,
+      authority: umi.identity,
+      name: "My Collection NFT",
+      uri: "https://example.com/path/to/some/json/metadata.json",
+      sellerFeeBasisPoints: percentAmount(9.99, 2),
+      isCollection: true,
+    }).sendAndConfirm(umi, {
+      confirm: { commitment: "finalized" },
+    });
+    console.log("Collection Created:", base58.deserialize(createNftTx.signature)[0]);
+
+    // --- Create Candy Machine ---
+
+    console.log("Creating Candy Machine with mint limit guard...");
+    const candyMachine = generateSigner(umi);
+    
+    const createCandyMachineV2Tx = await (
+      await create(umi, {
+        candyMachine,
+        tokenStandard: TokenStandard.NonFungible,
+        collectionMint: collectionMint.publicKey,
+        collectionUpdateAuthority: umi.identity,
+        itemsAvailable: 2,
+        sellerFeeBasisPoints: percentAmount(1.23),
+        creators: [
+          {
+            address: umi.identity.publicKey,
+            verified: false,
+            percentageShare: 100,
+          },
+        ],
+        guards: {
+          mintLimit: some({
+            id: 1,
+            limit: 2,
+          }),
+        },
+        configLineSettings: some({
+          prefixName: "My NFT #",
+          nameLength: 3,
+          prefixUri: "https://example.com/",
+          uriLength: 29,
+          isSequential: false,
+        }),
+      })
+    )
+      .add(
+        addConfigLines(umi, {
+          candyMachine: candyMachine.publicKey,
+          index: 0,
+          configLines: [
+            { name: "1", uri: "https://example.com/nft1.json" },
+            { name: "2", uri: "https://example.com/nft2.json" },
+          ],
+        })
+      )
+      .sendAndConfirm(umi, { confirm: { commitment: "finalized" } });
+      
+    console.log("Candy Machine Created:", base58.deserialize(createCandyMachineV2Tx.signature)[0]);
+
+    // --- Mint NFT ---
+
+    console.log("Minting NFT to recipient...");
+    
+    // Get latest Candy Machine state
+    const candyMachineAccount = await fetchCandyMachine(umi, candyMachine.publicKey);
+
+    // Create mint transaction
+    const nftMint = generateSigner(umi);
+    const mintTx = await transactionBuilder()
+      .add(setComputeUnitLimit(umi, { units: 800_000 }))
+      .add(
+        createMintWithAssociatedToken(umi, { mint: nftMint, owner: recipient })
+      )
+      .add(
+        mintV2(umi, {
+          candyMachine: candyMachineAccount.publicKey,
+          nftMint,
+          token: findAssociatedTokenPda(umi, {
+            mint: nftMint.publicKey,
+            owner: recipient,
+          }),
+          collectionMint: candyMachineAccount.collectionMint,
+          collectionUpdateAuthority: candyMachineAccount.authority,
+          tokenStandard: TokenStandard.NonFungible,
+          mintArgs: {
+            mintLimit: some({
+              id: 1,
+            }),
+          },
+        })
+      )
+      .sendAndConfirm(umi, {
+        confirm: { commitment: "finalized" },
+      });
+
+    console.log("NFT Minted Successfully!");
+    console.log("Mint Transaction:", base58.deserialize(mintTx.signature)[0]);
+
+  } catch (error) {
+    console.error("Failed to execute:", error);
+  }
+})();
+```
+{% /totem-accordion  %}
+{% /totem %

+ 3 - 1
src/pages/candy-machine/mint.md

@@ -384,6 +384,8 @@ Group 2: "public"
 
 {% /diagram %}
 
+{% seperator h="6" /%}
+
 {% dialect-switcher title="Mint from a Candy Machine with guard groups" %}
 {% dialect title="JavaScript" id="js" %}
 
@@ -575,4 +577,4 @@ Congratulations, you now know how Candy Machines work from A to Z!
 Here are some additional reading resources you might be interested in:
 
 - [All Available Guards](/candy-machine/guards): Have a look through all the guards available to you so you can cherry-pick the ones you need.
-- _Create Your First Candy Machine (coming soon)_: This How-To guide helps you upload your assets and create a new Candy Machine from scratch using a CLI tool called “[Sugar](/candy-machine/sugar)”. It also uses our JS SDK to spin up a minting website for your Candy Machine.
+- [Create Your First Candy Machine](/candy-machine/create-an-nft-collection-on-solana-with-candy-machine.md): This How-To guide helps you upload your assets and create a new Candy Machine from scratch using a CLI tool called “[Sugar](/candy-machine/sugar)”.

+ 88 - 0
src/pages/mpl-hybrid/guides/mpl-404-hyrbid-ui-template.md

@@ -0,0 +1,88 @@
+---
+title: Metaplex MPL-404 Hybrid Solana NextJs Tailwind Template
+metaTitle: Metaplex MPL-404 Hybrid NextJs Tailwind Template | Web UI Templates
+description: A web UI template for Metaplex MPL-404 Hybrid using Nextjs, Tailwind, Metaplex Umi, Solana WalletAdapter and Zustand.
+created: 2024-12-16
+---
+
+The Metaplex MPL-404 Hybrid UI Template has been built to give developers and users a development starting point. The template comes preset up with `.env` example files, functional UI components and transaction calls to springboard your development while creating a front end UI for your Hybrid Collection.
+
+{% image src="/images/hybrid-ui-template-image.jpg" classes="m-auto" /%}
+
+## Features
+
+- Nextjs React framework
+- Tailwind
+- Shadcn
+- Solana WalletAdapter
+- Metaplex Umi
+- Zustand
+- Dark/Light Mode
+- Umi Helpers
+
+This UI Template is created using the base Metaplex UI Template. Aditional documentation can be found at the following
+
+Base Template Github Repo - [https://github.com/metaplex-foundation/metaplex-nextjs-tailwind-template](https://github.com/metaplex-foundation/metaplex-nextjs-tailwind-template)
+
+## Installation
+
+```shell
+git clone https://github.com/metaplex-foundation/mpl-hybrid-404-ui-template-nextjs-tailwind-shadcn.git
+```
+
+Github Repo - [https://github.com/metaplex-foundation/mpl-hybrid-404-ui-template-nextjs-tailwind-shadcn](https://github.com/metaplex-foundation/mpl-hybrid-404-ui-template-nextjs-tailwind-shadcn)
+
+
+## Setup
+
+### .env File
+
+Rename `.env.example` to `.env`
+
+Fill out the following with the correct details.
+
+```
+// Escrow Account
+NEXT_PUBLIC_ESCROW="11111111111111111111111111111111"
+NEXT_PUBLIC_COLLECTION="11111111111111111111111111111111"
+NEXT_PUBLIC_TOKEN="11111111111111111111111111111111"
+
+// RPC URL
+NEXT_PUBLIC_RPC="https://myrpc.com/?api-key="
+```
+
+
+### Image Replacement
+In src/assets/images/ there are two images to replace:
+
+- collectionImage.jpg
+- token.jpg
+
+Both of these images are used to save fetching the collection and token Metadata just to access the image uri.
+
+### Change RPC
+
+You can configure the RPC URL for your project in any way you prefer, using one of the following methods:
+
+- .env
+- constants.ts file
+- hardcoded into umi directly
+
+In this example the RPC url is hardcoded into the `umiStore` umi state under `src/store/useUmiStore.ts` at line `21`.
+
+```ts
+const useUmiStore = create<UmiState>()((set) => ({
+  // add your own RPC here
+  umi: createUmi('http://api.devnet.solana.com').use(
+    signerIdentity(
+      createNoopSigner(publicKey('11111111111111111111111111111111'))
+    )
+  ),
+  ...
+}))
+```
+## Additional Documentation
+
+It is recommended to further read the documentation for the base template to understand the helpers and functionality this template is built with
+
+Github Repo - [https://github.com/metaplex-foundation/mpl-hybrid-404-ui-template-nextjs-tailwind-shadcn](https://github.com/metaplex-foundation/mpl-hybrid-404-ui-template-nextjs-tailwind-shadcn)

+ 24 - 0
src/styles/extra.css

@@ -10,7 +10,31 @@
   background-clip: text;
 }
 
+
 html {
   overflow-y: overlay;
   scrollbar-gutter: stable;
 }
+
+.loader {
+  border: 2px solid #fff;
+  border-bottom-color: #d162c2;
+  border-radius: 50%;
+  display: inline-block;
+  box-sizing: border-box;
+  animation: rotation 1s linear infinite;
+}
+
+@keyframes rotation {
+  0% {
+    transform: rotate(0deg);
+  }
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+
+select::-ms-expand {
+  display: none;
+}

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů