├── src ├── assets │ ├── scss │ │ ├── header │ │ │ └── _dropdown-menu.scss │ │ ├── elements │ │ │ ├── _auction_modal.scss │ │ │ ├── _tx-success.scss │ │ │ ├── _live_offers.scss │ │ │ ├── _animated-text.scss │ │ │ ├── _input-range.scss │ │ │ ├── _date-picker.scss │ │ │ ├── _sign-message.scss │ │ │ ├── _wallet.scss │ │ │ ├── _wallet-connect.scss │ │ │ ├── _section-title.scss │ │ │ ├── _uninscribed_stats.scss │ │ │ ├── _bids.scss │ │ │ ├── _cursor.scss │ │ │ ├── _countdown.scss │ │ │ ├── _backtotop.scss │ │ │ └── _toast.scss │ │ ├── default │ │ │ ├── _mixins.scss │ │ │ ├── _text-animation.scss │ │ │ └── _variables.scss │ │ └── style.scss │ ├── fonts │ │ ├── Feather.ttf │ │ ├── Feather.woff │ │ └── Inter │ │ │ ├── static │ │ │ ├── Inter-Black.ttf │ │ │ ├── Inter-Bold.ttf │ │ │ ├── Inter-Light.ttf │ │ │ ├── Inter-Thin.ttf │ │ │ ├── Inter-Medium.ttf │ │ │ ├── Inter-Regular.ttf │ │ │ ├── Inter-SemiBold.ttf │ │ │ ├── Inter-ExtraBold.ttf │ │ │ └── Inter-ExtraLight.ttf │ │ │ ├── Inter-VariableFont_slnt,wght.ttf │ │ │ └── README.txt │ └── images │ │ ├── green-check.gif │ │ └── nos-ft-logo.png ├── components │ ├── ui │ │ ├── offcanvas │ │ │ ├── index.js │ │ │ ├── body.js │ │ │ ├── header.js │ │ │ └── offcanvas.js │ │ ├── burger-button │ │ │ └── index.js │ │ ├── client-avatar │ │ │ └── index.js │ │ ├── slider │ │ │ └── index.js │ │ ├── anchor │ │ │ └── index.js │ │ ├── scroll-to-top │ │ │ └── index.js │ │ └── button │ │ │ └── index.js │ ├── modals │ │ ├── send-bulk-modal │ │ │ ├── transaction-sent-step.js │ │ │ └── select-rate-step.js │ │ ├── bids-modal │ │ │ └── index.js │ │ └── connect-wallet │ │ │ └── index.js │ ├── loading-animation │ │ ├── index.js │ │ └── loading-bar.json │ ├── menu │ │ ├── mobile-menu │ │ │ ├── submenu.js │ │ │ ├── megamenu.js │ │ │ └── index.js │ │ └── main-menu │ │ │ ├── submenu.js │ │ │ ├── megamenu.js │ │ │ └── index.js │ ├── product-details │ │ ├── title.js │ │ └── collection.js │ ├── seo.js │ ├── section-title │ │ └── index.js │ ├── widgets │ │ ├── logo-widget │ │ │ └── index.js │ │ └── quicklink-widget │ │ │ └── index.js │ ├── countdown-timer │ │ ├── countdown-timer-text.js │ │ └── index.js │ ├── logo │ │ └── index.js │ ├── animated-text │ │ └── index.js │ ├── collection-card │ │ └── index.js │ ├── rune-display │ │ └── index.js │ ├── inscription-preview │ │ └── index.js │ ├── transaction-sent-confirmation │ │ └── index.js │ ├── card-options │ │ └── index.js │ ├── btc-transaction-tree │ │ └── psbt.js │ ├── collection-info │ │ └── index.js │ ├── product-bid │ │ └── index.js │ ├── bids │ │ └── bid-list.js │ └── collection-inscription │ │ └── index.js ├── data │ ├── general │ │ ├── header.json │ │ ├── menu.js │ │ ├── footer.json │ │ └── home.json │ └── ordinals.json ├── hooks │ ├── use-simple-scroll-top.js │ ├── use-flyout-search.js │ ├── use-offcanvas.js │ ├── use-header-height.js │ ├── use-bitcoin-price.js │ ├── use-offer-filters.js │ ├── use-delay-unmount.js │ ├── use-sticky.js │ ├── use-scroll-to-top.js │ ├── index.js │ ├── use-output.js │ ├── use-click-outside.js │ ├── use-is-spent.js │ ├── use-auction.js │ ├── use-runes.js │ ├── use-bid.js │ ├── use-marketplace.js │ ├── use-infinite-scroll.js │ ├── use-auctions.js │ ├── use-home.js │ ├── use-inscription.js │ ├── use-sockets.js │ ├── use-wallet-state.js │ └── use-connect-wallet.js ├── index.js ├── utils │ ├── time.js │ ├── nostr-relay.js │ ├── bip322.js │ └── types.js ├── context │ └── wallet-context.js ├── services │ ├── deezy.js │ ├── local-storage.js │ ├── session-storage.js │ └── nitrous-api.js ├── layouts │ ├── wrapper.js │ ├── footer.js │ └── header.js ├── pages │ ├── _document.js │ ├── _app.js │ ├── tools │ │ └── sign.js │ ├── marketplace.js │ ├── auction.js │ ├── index.js │ ├── wallet.js │ ├── output │ │ └── [output].js │ └── inscription │ │ └── [slug].js ├── containers │ ├── product-details │ │ └── loading-button.js │ ├── HeroArea.js │ ├── MainCollections.js │ ├── helpers.js │ └── Collection.js └── lib │ └── constants.config.js ├── env-variables.json ├── netlify.toml ├── public └── images │ ├── logo │ ├── alby.png │ ├── bitcoin.png │ ├── unisat.png │ ├── xverse.png │ ├── generative.png │ ├── metamask.png │ ├── MetaMask_Fox.png │ ├── nos-ft-logo.png │ ├── ordinals-white.svg │ ├── ordswap.svg │ ├── favicon.svg │ └── logo-white.svg │ └── slider │ ├── astralbabe.png │ └── bitcoinfrog.webp ├── README.md ├── .editorconfig ├── .eslintignore ├── .gitignore ├── jsconfig.json ├── next.config.js └── package.json /src/assets/scss/header/_dropdown-menu.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /env-variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "SENTRY_ENVIRONMENT": "" 3 | } 4 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | # example netlify.toml 2 | [build] 3 | command = "yarn build" 4 | publish = ".next" -------------------------------------------------------------------------------- /public/images/logo/alby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/public/images/logo/alby.png -------------------------------------------------------------------------------- /src/assets/fonts/Feather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Feather.ttf -------------------------------------------------------------------------------- /public/images/logo/bitcoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/public/images/logo/bitcoin.png -------------------------------------------------------------------------------- /public/images/logo/unisat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/public/images/logo/unisat.png -------------------------------------------------------------------------------- /public/images/logo/xverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/public/images/logo/xverse.png -------------------------------------------------------------------------------- /src/assets/fonts/Feather.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Feather.woff -------------------------------------------------------------------------------- /public/images/logo/generative.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/public/images/logo/generative.png -------------------------------------------------------------------------------- /public/images/logo/metamask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/public/images/logo/metamask.png -------------------------------------------------------------------------------- /src/assets/images/green-check.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/images/green-check.gif -------------------------------------------------------------------------------- /src/assets/images/nos-ft-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/images/nos-ft-logo.png -------------------------------------------------------------------------------- /src/assets/scss/elements/_auction_modal.scss: -------------------------------------------------------------------------------- 1 | .react-datepicker-wrapper { 2 | margin-left: -14px !important; 3 | } 4 | -------------------------------------------------------------------------------- /public/images/logo/MetaMask_Fox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/public/images/logo/MetaMask_Fox.png -------------------------------------------------------------------------------- /public/images/logo/nos-ft-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/public/images/logo/nos-ft-logo.png -------------------------------------------------------------------------------- /public/images/slider/astralbabe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/public/images/slider/astralbabe.png -------------------------------------------------------------------------------- /public/images/slider/bitcoinfrog.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/public/images/slider/bitcoinfrog.webp -------------------------------------------------------------------------------- /src/assets/fonts/Inter/static/Inter-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Inter/static/Inter-Black.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Inter/static/Inter-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Inter/static/Inter-Bold.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Inter/static/Inter-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Inter/static/Inter-Light.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Inter/static/Inter-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Inter/static/Inter-Thin.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Inter/static/Inter-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Inter/static/Inter-Medium.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Inter/static/Inter-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Inter/static/Inter-Regular.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Inter/static/Inter-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Inter/static/Inter-SemiBold.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Inter/static/Inter-ExtraBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Inter/static/Inter-ExtraBold.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Inter/static/Inter-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Inter/static/Inter-ExtraLight.ttf -------------------------------------------------------------------------------- /src/assets/fonts/Inter/Inter-VariableFont_slnt,wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deezy-inc/deezy-place/HEAD/src/assets/fonts/Inter/Inter-VariableFont_slnt,wght.ttf -------------------------------------------------------------------------------- /src/components/ui/offcanvas/index.js: -------------------------------------------------------------------------------- 1 | export { default as Offcanvas } from "./offcanvas"; 2 | export { default as OffcanvasHeader } from "./header"; 3 | export { default as OffcanvasBody } from "./body"; 4 | -------------------------------------------------------------------------------- /src/data/general/header.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "header-data-1", 3 | "logo": [ 4 | { 5 | "src": "/images/logo/logo-white.svg" 6 | } 7 | ], 8 | "activity_link": "/activity" 9 | } 10 | -------------------------------------------------------------------------------- /src/hooks/use-simple-scroll-top.js: -------------------------------------------------------------------------------- 1 | const { useEffectOnce } = require("react-use"); 2 | 3 | export const useSimpleScrollTop = () => { 4 | useEffectOnce(() => { 5 | window.scrollTo({ top: 0, left: 0, behavior: "smooth" }); 6 | }); 7 | }; 8 | -------------------------------------------------------------------------------- /src/assets/scss/elements/_tx-success.scss: -------------------------------------------------------------------------------- 1 | .tx-success-container { 2 | .action { 3 | display: flex; 4 | align-items: center; 5 | justify-items: center; 6 | flex-direction: column; 7 | } 8 | 9 | .txid { 10 | display: flex; 11 | gap: 8px; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/data/general/menu.js: -------------------------------------------------------------------------------- 1 | export default function (inscriborLink) { 2 | return [ 3 | { 4 | id: 1, 5 | text: "Wallet", 6 | path: "/wallet", 7 | private: true, 8 | }, 9 | { 10 | id: 6, 11 | text: "Sign", 12 | path: "/tools/sign", 13 | }, 14 | ]; 15 | } 16 | -------------------------------------------------------------------------------- /src/components/modals/send-bulk-modal/transaction-sent-step.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import TransactionSent from "@components/transaction-sent-confirmation"; 3 | 4 | export const TransactionSentStep = ({ sentTxId, onClose }) => ( 5 | 6 | ); 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nosft 2 | 3 | bitcoin web wallet connected to your nostr key, designed to hold ordinal inscription NFTs 4 | 5 | live at [deezy.place](https://deezy.place) 6 | 7 | Use node > 17 8 | 9 | ## to run locally: 10 | 11 | ``` 12 | git clone https://github.com/dannydeezy/nosft.git 13 | cd nosft 14 | npm install 15 | npm run dev 16 | ``` 17 | -------------------------------------------------------------------------------- /src/assets/scss/elements/_live_offers.scss: -------------------------------------------------------------------------------- 1 | .live-offers .item-enter { 2 | opacity: 0; 3 | } 4 | .live-offers .item-enter-active { 5 | opacity: 1; 6 | transition: opacity 300ms; 7 | } 8 | 9 | .live-offers .item-exit { 10 | opacity: 1; 11 | } 12 | .live-offers .item-exit-active { 13 | opacity: 0; 14 | transition: opacity 300ms; 15 | } 16 | -------------------------------------------------------------------------------- /src/hooks/use-flyout-search.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | 3 | function useFlyoutSearch() { 4 | const [search, setSearch] = useState(false); 5 | 6 | const searchHandler = () => { 7 | setSearch((prev) => !prev); 8 | }; 9 | 10 | return { search, searchHandler }; 11 | } 12 | 13 | export default useFlyoutSearch; 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | // import App from './pages'; 3 | // import { createRoot } from 'react-dom/client'; 4 | // // Importing the Bootstrap CSS 5 | // import 'bootstrap/dist/css/bootstrap.min.css'; 6 | 7 | // const container = document.getElementById('root'); 8 | // const root = createRoot(container); 9 | // root.render(); 10 | -------------------------------------------------------------------------------- /src/hooks/use-offcanvas.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | 3 | function useOffcanvas() { 4 | const [offcanvas, setOffcanvas] = useState(false); 5 | 6 | const offcanvasHandler = () => { 7 | setOffcanvas((prev) => !prev); 8 | }; 9 | 10 | return { offcanvas, offcanvasHandler, setOffcanvas }; 11 | } 12 | 13 | export default useOffcanvas; 14 | -------------------------------------------------------------------------------- /src/components/ui/offcanvas/body.js: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import PropTypes from "prop-types"; 3 | 4 | const OffcanvasBody = ({ children, className }) =>
{children}
; 5 | 6 | OffcanvasBody.propTypes = { 7 | className: PropTypes.node, 8 | children: PropTypes.node.isRequired, 9 | }; 10 | 11 | export default OffcanvasBody; 12 | -------------------------------------------------------------------------------- /src/assets/scss/elements/_animated-text.scss: -------------------------------------------------------------------------------- 1 | .motion-text-animation { 2 | color: #fff; 3 | } 4 | .motion-text-animation span { 5 | position: relative; 6 | font-size: 50px; 7 | font-weight: 600; 8 | text-transform: uppercase; 9 | } 10 | .motion-center { 11 | position: absolute; 12 | top: 50%; 13 | left: 50%; 14 | transform: translate(-50%, -50%); 15 | } 16 | -------------------------------------------------------------------------------- /src/utils/time.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable object-shorthand */ 2 | export const duration = { 3 | seconds: function (val) { 4 | return val; 5 | }, 6 | minutes: function (val) { 7 | return val * this.seconds(60); 8 | }, 9 | hours: function (val) { 10 | return val * this.minutes(60); 11 | }, 12 | days: function (val) { 13 | return val * this.hours(24); 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/assets/scss/elements/_input-range.scss: -------------------------------------------------------------------------------- 1 | .input-range { 2 | .slider-track-container { 3 | height: 4px; 4 | border-radius: 5px; 5 | } 6 | .slider-thumb { 7 | width: 10px; 8 | height: 10px; 9 | background: var(--color-primary); 10 | border-radius: 50%; 11 | margin-top: -3px; 12 | transition: left 0.3s ease-out, width 0.3s ease-out; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/context/wallet-context.js: -------------------------------------------------------------------------------- 1 | import { createContext, useContext } from "react"; 2 | 3 | const WalletContext = createContext(null); 4 | 5 | const useWallet = () => { 6 | const context = useContext(WalletContext); 7 | 8 | if (context === null) { 9 | throw new Error("useWallet must be used within a WalletContext.Provider"); 10 | } 11 | 12 | return context; 13 | }; 14 | 15 | export { WalletContext, useWallet }; 16 | -------------------------------------------------------------------------------- /src/hooks/use-header-height.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | const useHeaderHeight = (ref, initialHeight = 148) => { 4 | const [headerHeight, setHeaderHeight] = useState(initialHeight); 5 | 6 | useEffect(() => { 7 | if (ref.current) { 8 | setHeaderHeight(ref.current.clientHeight); 9 | } 10 | }, [ref]); 11 | 12 | return headerHeight; 13 | }; 14 | 15 | export default useHeaderHeight; 16 | -------------------------------------------------------------------------------- /src/assets/scss/elements/_date-picker.scss: -------------------------------------------------------------------------------- 1 | .date-picker-custom { 2 | color: red; 3 | 4 | label { 5 | color: white !important; 6 | } 7 | 8 | .MuiInputBase-formControl { 9 | color: white !important; 10 | border: 1px solid white; 11 | } 12 | 13 | .MuiIconButton-root { 14 | color: white !important; 15 | } 16 | 17 | .MuiOutlinedInput-notchedOutline { 18 | border: 0px !important; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/services/deezy.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | async function buyOrdinalWithLightning({ psbt, receive_address, on_chain_fee_rate, refund_lightning_address }) { 4 | const { data } = await axios.post(`https://api.deezy.io/v1/inscriptions/buy`, { 5 | psbt, 6 | receive_address, 7 | on_chain_fee_rate, 8 | refund_lightning_address, 9 | }); 10 | 11 | return data.bolt11_invoice; 12 | } 13 | 14 | export { buyOrdinalWithLightning }; 15 | -------------------------------------------------------------------------------- /src/components/ui/burger-button/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import clsx from "clsx"; 3 | 4 | const BurgerButton = ({ className, onClick }) => ( 5 | 8 | ); 9 | 10 | BurgerButton.propTypes = { 11 | className: PropTypes.string, 12 | onClick: PropTypes.func, 13 | }; 14 | 15 | export default BurgerButton; 16 | -------------------------------------------------------------------------------- /public/images/logo/ordinals-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/layouts/wrapper.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ScrollToTop from "@ui/scroll-to-top"; 3 | import PropTypes from "prop-types"; 4 | import { ToastContainer } from "react-toastify"; 5 | 6 | const Wrapper = ({ children }) => ( 7 | <> 8 | {children} 9 | 10 | 11 | 12 | ); 13 | 14 | Wrapper.propTypes = { 15 | children: PropTypes.node.isRequired, 16 | }; 17 | 18 | export default Wrapper; 19 | -------------------------------------------------------------------------------- /src/hooks/use-bitcoin-price.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { fetchBitcoinPrice } from "@services/nosft"; 3 | 4 | const useBitcoinPrice = ({ nostrOrdinalsAddress }) => { 5 | const [bitcoinPrice, setBitcoinPrice] = useState("-"); 6 | 7 | useEffect(() => { 8 | const getPrice = async () => { 9 | const btcPrice = await fetchBitcoinPrice(); 10 | setBitcoinPrice(btcPrice); 11 | }; 12 | 13 | getPrice(); 14 | }, [nostrOrdinalsAddress]); 15 | 16 | return { bitcoinPrice }; 17 | }; 18 | 19 | export default useBitcoinPrice; 20 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [vcbuild.bat] 12 | end_of_line = crlf 13 | 14 | [Makefile] 15 | indent_size = 8 16 | indent_style = tab 17 | 18 | [{deps}/**] 19 | charset = unset 20 | end_of_line = unset 21 | indent_size = unset 22 | indent_style = unset 23 | trim_trailing_whitespace = unset 24 | 25 | [{test/fixtures,deps,tools/node_modules,tools/gyp,tools/icu,tools/msvs}/**] 26 | insert_final_newline = false 27 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next 13 | .next 14 | /public 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | \*.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | yarn-error.log\* 28 | 29 | # local env files 30 | .env.local 31 | .env.development.local 32 | .env.test.local 33 | .env.production.local 34 | 35 | # vercel 36 | .vercel 37 | -------------------------------------------------------------------------------- /src/components/loading-animation/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | // import Lottie from "lottie-react"; 3 | // import checkAnimation from "./loading-bar.json"; 4 | import { TailSpin } from "react-loading-icons"; 5 | 6 | const LoadingAnimation = () => { 7 | return ; 8 | // return ( 9 | // 15 | // ); 16 | }; 17 | 18 | LoadingAnimation.propTypes = {}; 19 | 20 | export default LoadingAnimation; 21 | -------------------------------------------------------------------------------- /src/components/menu/mobile-menu/submenu.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import Anchor from "@ui/anchor"; 3 | 4 | const SubMenu = ({ menu }) => ( 5 |
    6 | {menu.map((nav) => ( 7 |
  • 8 | 9 | {nav.text} 10 | {nav?.icon && } 11 | 12 |
  • 13 | ))} 14 |
15 | ); 16 | 17 | SubMenu.propTypes = { 18 | menu: PropTypes.arrayOf(PropTypes.shape({})), 19 | }; 20 | 21 | export default SubMenu; 22 | -------------------------------------------------------------------------------- /src/components/menu/main-menu/submenu.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import Anchor from "@ui/anchor"; 3 | 4 | const SubMenu = ({ menu }) => ( 5 |
    6 | {menu.map((nav) => ( 7 |
  • 8 | 9 | {nav.text} 10 | {nav?.icon && } 11 | 12 |
  • 13 | ))} 14 |
15 | ); 16 | 17 | SubMenu.propTypes = { 18 | menu: PropTypes.arrayOf(PropTypes.shape({})), 19 | }; 20 | 21 | export default SubMenu; 22 | -------------------------------------------------------------------------------- /src/hooks/use-offer-filters.js: -------------------------------------------------------------------------------- 1 | import { HIDE_TEXT_UTXO_OPTION } from "@lib/constants.config"; 2 | import { useState } from "react"; 3 | 4 | export default function useOfferFilters(type) { 5 | const [activeSort, setActiveSort] = useState("date"); 6 | const [sortAsc, setSortAsc] = useState(false); 7 | const [searchQuery, setSearchQuery] = useState(""); 8 | 9 | const [utxosType, setUtxosType] = useState( 10 | type === "bidding" ? "" : HIDE_TEXT_UTXO_OPTION, 11 | ); 12 | 13 | return { 14 | activeSort, 15 | setActiveSort, 16 | sortAsc, 17 | setSortAsc, 18 | searchQuery, 19 | setSearchQuery, 20 | utxosType, 21 | setUtxosType, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/assets/scss/elements/_sign-message.scss: -------------------------------------------------------------------------------- 1 | #sign-message { 2 | .form { 3 | display: flex; 4 | gap: 30px; 5 | flex-direction: column; 6 | } 7 | 8 | .form-action { 9 | display: flex; 10 | flex-direction: row-reverse; 11 | } 12 | .form-control { 13 | background: var(--background-color-1); 14 | border-radius: 5px; 15 | border: 2px solid transparent; 16 | font-size: 1.5rem; 17 | color: var(--color-white); 18 | width: 100%; 19 | 20 | &:focus { 21 | border: 2px solid var(--color-primary); 22 | } 23 | } 24 | 25 | .signed-message-result { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/assets/scss/default/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin clearfix() { 2 | &::after { 3 | content: ""; 4 | clear: both; 5 | display: table; 6 | } 7 | } 8 | 9 | @mixin config-bg-colors($prefix, $bg-color-...) { 10 | @each $i in $bg-color- { 11 | .#{$prefix}#{nth($i, 1)} { 12 | background: nth($i, 2); 13 | } 14 | } 15 | } 16 | 17 | @mixin placeholder { 18 | &::-webkit-input-placeholder { 19 | @content; 20 | } 21 | 22 | &:-moz-placeholder { 23 | @content; 24 | } 25 | 26 | &::-moz-placeholder { 27 | @content; 28 | } 29 | 30 | &:-ms-input-placeholder { 31 | @content; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/components/ui/offcanvas/header.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import clsx from "clsx"; 3 | 4 | const OffcanvasHeader = ({ className, onClick, children }) => ( 5 |
6 | {children} 7 |
8 | 11 |
12 |
13 | ); 14 | 15 | OffcanvasHeader.propTypes = { 16 | children: PropTypes.node.isRequired, 17 | className: PropTypes.string, 18 | onClick: PropTypes.func.isRequired, 19 | }; 20 | 21 | export default OffcanvasHeader; 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | # .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | # Local Netlify folder 37 | .netlify 38 | .vscode/ 39 | 40 | .env 41 | 42 | labs/ 43 | 44 | # Sentry Auth Token 45 | .sentryclirc 46 | 47 | *.bk.js 48 | 49 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | // "@assets/*": ["src/assets/*"], 6 | "@ui/*": ["src/components/ui/*"], 7 | "@components/*": ["src/components/*"], 8 | "@widgets/*": ["src/components/widgets/*"], 9 | "@lib/*": ["src/lib/*"], 10 | "@containers/*": ["src/containers/*"], 11 | "@layout/*": ["src/layouts/*"], 12 | "@utils/*": ["src/utils/*"], 13 | "@hooks": ["src/hooks"], 14 | "@data/*": ["src/data/*"], 15 | "@services/*": ["src/services/*"], 16 | "@context/*": ["src/context/*"] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/hooks/use-delay-unmount.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | function useDelayUnmount(isMounted, delayTime) { 4 | const [showDiv, setShowDiv] = useState(false); 5 | useEffect(() => { 6 | let timeoutId; 7 | if (isMounted && !showDiv) { 8 | setShowDiv(true); 9 | } else if (!isMounted && showDiv) { 10 | timeoutId = setTimeout(() => setShowDiv(false), delayTime); // delay our unmount 11 | } 12 | return () => clearTimeout(timeoutId); // cleanup mechanism for effects , the use of setTimeout generate a sideEffect 13 | }, [isMounted, delayTime, showDiv]); 14 | return showDiv; 15 | } 16 | 17 | export default useDelayUnmount; 18 | -------------------------------------------------------------------------------- /src/data/ordinals.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "title": "Preatent", 5 | "slug": "preatent", 6 | "description": "6/30", 7 | "price": { 8 | "amount": 0.241, 9 | "currency": "Sats" 10 | }, 11 | "likeCount": 322, 12 | "images": [ 13 | { 14 | "src": "/images/portfolio/lg/portfolio-01.jpg" 15 | } 16 | ], 17 | "authors": [ 18 | { 19 | "name": "Mark Jordan", 20 | "slug": "/author", 21 | "image": { 22 | "src": "/images/client/client-2.png" 23 | } 24 | } 25 | ], 26 | "utxo": 15 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /src/hooks/use-sticky.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | function useSticky() { 4 | const [sticky, setSticky] = useState(false); 5 | 6 | useEffect(() => { 7 | const scrollHandler = () => { 8 | const scrollPos = window.scrollY; 9 | if (scrollPos > 50) { 10 | setSticky(true); 11 | } 12 | 13 | if (scrollPos < 50) { 14 | setSticky(false); 15 | } 16 | }; 17 | 18 | window.addEventListener("scroll", scrollHandler); 19 | return () => { 20 | window.removeEventListener("scroll", scrollHandler); 21 | }; 22 | }, [sticky]); 23 | 24 | return sticky; 25 | } 26 | 27 | export default useSticky; 28 | -------------------------------------------------------------------------------- /src/data/general/footer.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "footer-data", 3 | "logo-widget": { 4 | "logo": [ 5 | { 6 | "src": "/images/logo/logo-white.svg", 7 | "alt": "logo" 8 | } 9 | ], 10 | "text": "Launch your own collection in collaboration with Deezy." 11 | }, 12 | "quicklink-widget": { 13 | "title": "Deezy Marketplace", 14 | "menu": [ 15 | { 16 | "id": 1, 17 | "text": "Astral Babes", 18 | "path": "https://astralbabes.ai/" 19 | }, 20 | { 21 | "id": 2, 22 | "text": "About", 23 | "path": "https://github.com/dannydeezy/nosft" 24 | } 25 | ] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/components/product-details/title.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import clsx from "clsx"; 3 | // import ShareDropdown from "../share-dropdown"; 4 | 5 | const ProductTitle = ({ className, title }) => ( 6 |
7 |

{title}

8 | {/* TODO: IMPLEMENT SHARE, NOW THAT WE HAVE SPECIFIC INSCRIPTION PAGES */} 9 | {/*
10 |
11 | 12 | Share 13 |
14 |
*/} 15 |
16 | ); 17 | 18 | ProductTitle.propTypes = { 19 | className: PropTypes.string, 20 | title: PropTypes.string.isRequired, 21 | }; 22 | 23 | ProductTitle.defaultProps = {}; 24 | 25 | export default ProductTitle; 26 | -------------------------------------------------------------------------------- /src/hooks/use-scroll-to-top.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | 3 | function useScrollToTop() { 4 | const [stick, setStick] = useState(false); 5 | const onClickHandler = () => { 6 | window.scrollTo({ top: 0, behavior: "smooth" }); 7 | }; 8 | 9 | useEffect(() => { 10 | const scrollHandler = () => { 11 | const scrollPos = window.pageYOffset; 12 | if (scrollPos > 50) { 13 | setStick(true); 14 | } else { 15 | setStick(false); 16 | } 17 | }; 18 | 19 | window.addEventListener("scroll", scrollHandler); 20 | return () => { 21 | window.removeEventListener("scroll", scrollHandler); 22 | }; 23 | }, [stick]); 24 | 25 | return { stick, onClickHandler }; 26 | } 27 | 28 | export default useScrollToTop; 29 | -------------------------------------------------------------------------------- /src/assets/scss/elements/_wallet.scss: -------------------------------------------------------------------------------- 1 | .wallet { 2 | .wallet-title { 3 | display: flex; 4 | align-items: baseline; 5 | } 6 | 7 | .balance-info { 8 | .price { 9 | color: var(--color-primary); 10 | } 11 | } 12 | } 13 | 14 | .btc-transaction-tree svg { 15 | width: 100%; 16 | height: auto; 17 | } 18 | 19 | .btc-transaction-tree .tooltip { 20 | position: absolute; 21 | text-align: center; 22 | width: auto; 23 | height: auto; 24 | padding: 8px; 25 | font: 12px sans-serif; 26 | background: lightsteelblue; 27 | border: 0px; 28 | border-radius: 8px; 29 | pointer-events: none; 30 | opacity: 0; 31 | transition: opacity 0.5s; 32 | } 33 | 34 | .btc-text-white { 35 | fill: white; 36 | } 37 | 38 | .btc-fee-text { 39 | span { 40 | color: var(--color-primary); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/hooks/index.js: -------------------------------------------------------------------------------- 1 | export { default as useOffcanvas } from "./use-offcanvas"; 2 | export { default as useSticky } from "./use-sticky"; 3 | export { default as useFlyoutSearch } from "./use-flyout-search"; 4 | export { default as useScrollToTop } from "./use-scroll-to-top"; 5 | export { default as useConnectWallet } from "./use-connect-wallet"; 6 | export { default as useDelayUnmount } from "./use-delay-unmount"; 7 | export { default as useWalletState } from "./use-wallet-state"; 8 | export { default as useHeaderHeight } from "./use-header-height"; 9 | export { default as useDeezySockets } from "./use-sockets"; 10 | export { default as useMarketplace } from "./use-marketplace"; 11 | export { default as useOfferFilters } from "./use-offer-filters"; 12 | export { default as useHome } from "./use-home"; 13 | export { default as useAuctions } from "./use-auctions"; 14 | export { default as useRunes } from "./use-runes"; 15 | -------------------------------------------------------------------------------- /src/hooks/use-output.js: -------------------------------------------------------------------------------- 1 | import { getOutput, getRuneData } from "@services/nosft"; 2 | import { useAsync } from "react-use"; 3 | 4 | function useOutput(output) { 5 | const state = useAsync(async () => { 6 | if (!output) return undefined; 7 | const data = await getOutput(output); 8 | const [txid = "", vout = ""] = output.split(":"); 9 | console.log("[useOutput]", { ...data, output, txid, vout }); 10 | 11 | // Fetch rune data for this output 12 | let runeData = null; 13 | try { 14 | runeData = await getRuneData(output); 15 | } catch (error) { 16 | console.error("Error fetching rune data:", error); 17 | } 18 | 19 | return { 20 | ...data, 21 | output, 22 | txid, 23 | vout: parseInt(vout), 24 | runes: runeData?.runes || [] 25 | }; 26 | }, [output]); 27 | 28 | return state; 29 | } 30 | 31 | export default useOutput; 32 | -------------------------------------------------------------------------------- /src/components/ui/offcanvas/offcanvas.js: -------------------------------------------------------------------------------- 1 | import { memo } from "react"; 2 | import clsx from "clsx"; 3 | import PropTypes from "prop-types"; 4 | 5 | const Offcanvas = memo(({ children, className, isOpen, onClick }) => ( 6 |
13 |
e.stopPropagation()} onKeyPress={onClick} role="button" tabIndex={0}> 14 | {children} 15 |
16 |
17 | )); 18 | 19 | Offcanvas.displayName = "Offcanvas"; 20 | 21 | Offcanvas.propTypes = { 22 | children: PropTypes.node.isRequired, 23 | className: PropTypes.node, 24 | isOpen: PropTypes.bool.isRequired, 25 | onClick: PropTypes.func.isRequired, 26 | }; 27 | 28 | export default Offcanvas; 29 | -------------------------------------------------------------------------------- /src/components/product-details/collection.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import clsx from "clsx"; 3 | import Anchor from "@ui/anchor"; 4 | 5 | const InscriptionCollection = ({ className, collection }) => ( 6 |
7 | Collection 8 |
9 | {`collection-${collection.slug}`} 10 | 11 |
{collection.name}
12 |
13 |
14 |
15 | ); 16 | 17 | InscriptionCollection.propTypes = { 18 | className: PropTypes.string, 19 | collection: PropTypes.shape({ 20 | name: PropTypes.string, 21 | slug: PropTypes.string, 22 | icon: PropTypes.string, 23 | }), 24 | }; 25 | 26 | export default InscriptionCollection; 27 | -------------------------------------------------------------------------------- /src/components/seo.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Head from "next/head"; 3 | import PropTypes from "prop-types"; 4 | 5 | const SEO = ({ pageTitle }) => { 6 | const title = `${pageTitle} Marketplace`; 7 | return ( 8 | 9 | {title} 10 | 11 | 15 | 16 | 17 | 18 | 19 | ); 20 | }; 21 | 22 | SEO.propTypes = { 23 | pageTitle: PropTypes.string.isRequired, 24 | }; 25 | 26 | export default SEO; 27 | -------------------------------------------------------------------------------- /src/components/section-title/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from "prop-types"; 2 | import clsx from "clsx"; 3 | import { TailSpin } from "react-loading-icons"; 4 | 5 | const SectionTitle = ({ title, className, disableAnimation, isLoading, ...restProps }) => ( 6 |
7 |

15 | {isLoading && } 16 |

17 | ); 18 | 19 | SectionTitle.propTypes = { 20 | title: PropTypes.string.isRequired, 21 | subtitle: PropTypes.string, 22 | className: PropTypes.string, 23 | disableAnimation: PropTypes.bool, 24 | isLoading: PropTypes.bool, 25 | }; 26 | 27 | export default SectionTitle; 28 | -------------------------------------------------------------------------------- /src/pages/_document.js: -------------------------------------------------------------------------------- 1 | import Document, { Html, Head, Main, NextScript } from "next/document"; 2 | 3 | class MyDocument extends Document { 4 | static async getInitialProps(ctx) { 5 | const initialProps = await Document.getInitialProps(ctx); 6 | return { ...initialProps }; 7 | } 8 | 9 | render() { 10 | return ( 11 | 12 | 13 | 14 |
15 | 16 | 17 |