Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add support for text mints #411

Merged
merged 30 commits into from
Jun 6, 2024
Merged
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9497134
feat: Add support for typed based nfts
kittypurrry Mar 28, 2024
a5f11b0
Some updates to display token's displayuri instead of artifact
kittypurrry Apr 7, 2024
3ddd0b6
Update Monotype art to use 'IBM Mono Plex' to be consistent with type…
kittypurrry Apr 7, 2024
8aa8566
Remove monaco
kittypurrry Apr 7, 2024
9baff04
Merge branch 'teia-community:main' into feat/typed-nft
kittypurrry Apr 8, 2024
4328cc0
Fix lint errors
kittypurrry Apr 13, 2024
1c48db3
Merge branch 'teia-community:main' into feat/typed-nft
kittypurrry Apr 14, 2024
8fef7bc
Fix some UI issues while minting - switching between preview and edit…
kittypurrry Apr 14, 2024
9616958
Minor UI updates for very long text mints
kittypurrry Apr 14, 2024
6424135
Some minor adjustments
kittypurrry Apr 16, 2024
4e81265
Replace UltimateTextToImage with canvas solution
kittypurrry Apr 21, 2024
629db11
Merge branch 'main' into feat/typed-nft
kittypurrry Apr 21, 2024
b219adf
chore: ♻️ apply format
melMass May 2, 2024
3b836bf
fix: ✨ minor edits
melMass May 2, 2024
c7feab5
Fix font issue for generated thumbnail and changed mono font to Iosevka
kittypurrry May 5, 2024
aaea30c
Add comments and refactor thumbnail generation a bit
kittypurrry May 5, 2024
5777d40
Update char length before ellipsis since text size can accomodate for…
kittypurrry May 5, 2024
25ab072
Merge branch 'main' into feat/typed-nft
melMass May 11, 2024
b993686
style: 💎 fix various styles issues
melMass May 11, 2024
dbcf13d
chore: 🧹 convert typed_art utils to ts
melMass May 11, 2024
324478f
refactor: 📦 image generation logic
melMass May 11, 2024
9f21675
fix: 🐛 issues reported by CI
melMass May 11, 2024
1ebe8a1
fix: preview generation
melMass May 20, 2024
45e243e
chore: 🧹 prefer const
melMass May 20, 2024
8934d88
hide scrollbars and add text feed to the menu
Zir0h May 26, 2024
f5afa3c
disable description in preview cards for text/plain tokens
Zir0h May 26, 2024
7190069
use overflow:scroll
Zir0h Jun 5, 2024
e15a53f
mess around with overflow / whitespace
Zir0h Jun 6, 2024
481c8cf
Merge branch 'main' into feat/typed-nft
Zir0h Jun 6, 2024
747143a
added padding
Zir0h Jun 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: Add support for typed based nfts
- Create new textarea input component for typed based nfts that renders the correct fonts to be displayed correctly on OBJKT
- Modify existing FormFields to include new select options for user to specify if it's a typed nft and whether it requires monospace font
- Auto generate cover image based on typed input
  • Loading branch information
kittypurrry committed Mar 28, 2024
commit 94971342bcbfa160b0b633b0c6ec87b68b8f9438
337 changes: 303 additions & 34 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -32,7 +32,8 @@
"react-use": "^17.4.0",
"react-use-clipboard": "^1.0.9",
"screenfull": "^6.0.2",
"swr": "^1.3.0"
"swr": "^1.3.0",
"ultimate-text-to-image": "^1.0.1"
},
"scripts": {
"analyze": "source-map-explorer 'build/assets/*.js'",
12 changes: 12 additions & 0 deletions src/components/form/FormFields.jsx
Original file line number Diff line number Diff line change
@@ -52,6 +52,18 @@ export const FormFields = ({ value, field, error, register, control }) => {
{error && <FieldError text error={error.message} />}
</Textarea>
)
case 'typed-textarea':
return (
<Textarea
className={styles.typed_field}
label={field.label}
placeholder={field.placeholder}
{...register(name, field.rules)}
>
<Line />
{error && <FieldError text error={error.message} />}
</Textarea>
)
case 'select':
case 'select-search':
return (
45 changes: 40 additions & 5 deletions src/components/form/MintForm.jsx
Original file line number Diff line number Diff line change
@@ -9,20 +9,47 @@ import { motion } from 'framer-motion'
import { useMintStore } from '@context/mintStore'
import { useFormContext, useFormState } from 'react-hook-form'
import { useModalStore } from '@context/modalStore'
import { processTypedInput } from '@utils/typed-art'

export default function MintForm() {
const { artifact, license, minterName, address, balance } = useOutletContext()
const {
artifact,
license,
minterName,
address,
balance,
isTyped,
isMonoType,
} = useOutletContext()
const navigate = useNavigate()
const { control } = useFormContext()
const { defaultValues } = useFormState({ control })
const [needsCover, setNeedsCover] = useState(false)
const [isTypedArt, setIsTypedArt] = useState(false)

useEffect(() => {
if (artifact) setNeedsCover(!artifact?.mimeType?.startsWith('image'))
}, [artifact])
if (artifact)
setNeedsCover(
!artifact?.mimeType?.startsWith('image') &&
artifact?.mimeType !== 'text/plain'
)

/** Typed */
setIsTypedArt(isTyped)

/** Render correct fonts */
let typedTextArea = document.querySelector("textarea[name='typedinput']")
if (isMonoType && typedTextArea) {
typedTextArea.style.fontFamily = 'Monaco'
} else if (typedTextArea) {
// default font to use for typed inputs
typedTextArea.style.fontFamily = 'Source Sans Pro'
}
}, [artifact, isTyped, isMonoType])

const onSubmit = async (data) => {
if (data.artifact) {
// other non-typed types that involves file upload
if (!isTyped && data.artifact) {
if (data.artifact.file?.size && data.artifact.file?.size / 1e6 > 2000) {
useModalStore
.getState()
@@ -32,6 +59,12 @@ export default function MintForm() {
const URL = window.URL || window.webkitURL
data.artifact.reader = URL.createObjectURL(data.artifact.file)
}

// typed input
else if (data.typedinput) {
data = await processTypedInput(data)
}

useMintStore.setState({ ...data, isValid: true })
navigate('preview')
}
@@ -40,9 +73,11 @@ export default function MintForm() {
const fields = useMemo(() => {
return mint_fields({
needsCover,
isTyped: isTypedArt,
showArtifact: !isTypedArt,
useCustomLicense: license?.value === 'custom',
})
}, [needsCover, license?.value])
}, [needsCover, isTypedArt, license?.value])
return (
<motion.div
style={{ width: '100%' }}
17 changes: 16 additions & 1 deletion src/components/form/index.module.scss
Original file line number Diff line number Diff line change
@@ -6,6 +6,21 @@
.error {
color: red;
}
.field {

.field,
.typed_field {
margin: 1em 0;
}

.typed_field textarea {
margin-top: 0.5em;
font-family: 'Source Sans Pro', sans-serif;
height: 20rem;
resize: auto;
border: 1px solid rgba(255, 255, 255, 0.6) !important;
padding: 0;
}

.typed_field textarea.mono {
font-family: 'Monaco', monospace !important;
}
11 changes: 11 additions & 0 deletions src/components/media-types/index.tsx
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ import { Container } from './container'
import { MD } from './md'
import { useMemo } from 'react'
import { NFT } from '@types'
import { TXT } from './text'

interface RenderMediaTypeProps {
/**The nft with the core fragments*/
@@ -184,6 +185,16 @@ export const RenderMediaType = ({
nft={nft}
/>
)

/** ASCII TYPED ART */
case MIMETYPE.TXT:
return (
<TXT
artifactUri={parsedArtifactUri}
displayUri={previewUri}
nft={nft}
/>
)

default:
return <UnknownComponent mimeType={nft.mime_type} />
64 changes: 64 additions & 0 deletions src/components/media-types/text/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { useRef } from 'react'
import styles from '@style'

import axios from 'axios'
/**
* @param {import("@types").MediaTypeProps} renderOptions - Th options for the media renderer
*/

export const TXT = ({
artifactUri,
displayUri,
displayView,
previewUri,
nft,
}) => {
const [content, setContent] = React.useState('')
const [isMonoType, setIsMonoType] = React.useState(false)
const htmlRef = useRef()

React.useEffect(() => {
const getTextContent = async () => {
await fetch(displayUri)
.then((response) => {
if (!response.ok) {
throw new Error('Error reading blob')
}
return response.text()
})
.then((text) => {
setContent(text)
})
.catch((error) => {
console.error('Error fetching the file:', error)
})
}

if (artifactUri) {
axios.get(artifactUri).then((res) => {
setContent(res.data)
})
} else if (displayUri) {
getTextContent()
setIsMonoType(nft.is_mono_type)
}
}, [artifactUri, previewUri, displayView, displayUri])

return (
<div ref={htmlRef} className={styles.container}>
<div className={styles.preview}>
<pre
style={{
fontFamily: isMonoType
? 'Monaco, monospace'
: 'Source Sans Pro, sans-serif',
}}
>
{content}
</pre>
</div>
</div>
)
}

export default TXT
81 changes: 81 additions & 0 deletions src/components/media-types/text/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
@import '@styles/layout.scss';
@import '@styles/mixins.scss';

// .html {
// @include embedObjktViewSizes;
// }

.container {
position: relative;
display: block;
width: 100%;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
max-height: 60vh;

&:after {
content: '';
display: block;
padding-bottom: 100%;
}

.preview {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: black;

img {
width: 100%;
height: auto;
}

.button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;

.gradient {
position: absolute;
top: 0;
right: 0;
transform: translateY(50%) translateY(-50%);
width: 200%;
height: 200%;
background: radial-gradient(
circle,
rgba(0, 0, 0, 0) 70%,
rgba(255, 255, 255, 0.2) 100%
);
}

svg {
position: absolute;
top: 6px;
right: 6px;
display: flex;
width: 30px;
height: auto;
margin: 0 auto;
z-index: 10;
}
}

pre {
width: fit-content;
margin: 0 auto;
}
}
}
6 changes: 4 additions & 2 deletions src/components/preview/index.jsx
Original file line number Diff line number Diff line change
@@ -52,6 +52,7 @@ export const Preview = () => {
photosensitiveSeizureWarning,
nsfw,
editions,
isMonoType,
] = useMintStore((st) => [
st.tags,
st.title,
@@ -65,10 +66,11 @@ export const Preview = () => {
st.photosensitive,
st.nsfw,
st.editions,
st.isMonoType,
])

const { ignoreUriMap } = useSettings()
const token_tags = tags
let token_tags = tags
? tags === ''
? []
: tags.replace(/\s/g, '').split(',')
@@ -99,7 +101,7 @@ export const Preview = () => {
<div className={styles.media}>
<RenderMediaType
displayView
nft={{ mime_type: artifact.mimeType }}
nft={{ mime_type: artifact.mimeType, is_mono_type: !!isMonoType }}
previewUri={artifact.reader}
previewDisplayUri={cover?.reader}
/>
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -47,6 +47,7 @@ export const MIMETYPE: { [key: string]: string } = {
ZIP: 'application/zip',
ZIP1: 'application/x-zip-compressed',
ZIP2: 'multipart/x-zip',
TXT: 'text/plain'
}

export const ALLOWED_MIMETYPES = Object.keys(MIMETYPE)
4 changes: 4 additions & 0 deletions src/context/mintStore.ts
Original file line number Diff line number Diff line change
@@ -42,6 +42,9 @@ interface MintState {
language?: SelectField
nsfw: boolean
photosensitive: boolean
isTyped: boolean
typedinput?: string /** for typed **/
isMonoType?: boolean
cover?: FileForm
artifact?: FileForm
thumbnail?: FileForm
@@ -104,6 +107,7 @@ export const useMintStore = create<MintState>()(
cover,
photosensitive,
nsfw,
isMonoType,
reset,
} = get()
const show = useModalStore.getState().show
Loading