Skip to content

Commit

Permalink
Merge pull request #11267 from Jarsen136/issue-11149
Browse files Browse the repository at this point in the history
feat: Enhanced Bulk Minting: Add Support for Onchain Attributes
  • Loading branch information
Jarsen136 authored Dec 24, 2024
2 parents ffb41c6 + e4cedce commit 9d4da0d
Show file tree
Hide file tree
Showing 15 changed files with 92 additions and 22 deletions.
2 changes: 1 addition & 1 deletion components/common/EditNftModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ import { NeoButton, NeoField, NeoInput, NeoModal } from '@kodadot1/brick'
import type { OpenSeaAttribute as Attribute } from '@kodadot1/hyperdata'
import type { ActionMetadataSetMetadata } from '@/composables/transaction/types'
import ModalBody from '@/components/shared/modals/ModalBody.vue'
import CustomAttributeInput from '@/components/rmrk/Create/CustomAttributeInput.vue'
import CustomAttributeInput from '@/components/create/CustomAttributeInput.vue'
import type { Metadata } from '@/services/nftStorage'
const emit = defineEmits(['submit'])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<NeoButton
v-if="!disabled"
no-shadow
class="self-center"
size="medium"
icon-left="times"
data-testid="attribute-button-remove"
Expand Down
2 changes: 1 addition & 1 deletion components/create/CreateNft.vue
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ import CreateNftPreview from './CreateNftPreview.vue'
import type { ActionMintToken, ActionList, TokenToList } from '@/composables/transaction/types'
import ChooseCollectionDropdown from '@/components/common/ChooseCollectionDropdown.vue'
import BasicSwitch from '@/components/shared/form/BasicSwitch.vue'
import CustomAttributeInput from '@/components/rmrk/Create/CustomAttributeInput.vue'
import CustomAttributeInput from '@/components/create/CustomAttributeInput.vue'
import RoyaltyForm from '@/components/bsx/Create/RoyaltyForm.vue'
import MintConfirmModal from '@/components/create/Confirm/MintConfirmModal.vue'
import resolveQueryPath from '@/utils/queryPathResolver'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<CollapseWrapper
:visible="visible"
:hidden="hidden"
:default-open="defaultOpen"
>
<div
v-for="(attribute, index) in attributes"
Expand Down Expand Up @@ -32,20 +33,22 @@
<script lang="ts" setup>
import type { OpenSeaAttribute as Attribute } from '@kodadot1/hyperdata'
import { NeoButton } from '@kodadot1/brick'
import AttributeInput from './AttributeInput.vue'
import AttributeInput from '@/components/create/AttributeInput.vue'
const props = withDefaults(
defineProps<{
modelValue?: Attribute[]
max: number
visible?: string
hidden?: string
defaultOpen?: boolean
}>(),
{
max: 0,
visible: 'collapse.collection.attributes.show',
hidden: 'collapse.collection.attributes.hide',
modelValue: () => [],
defaultOpen: false,
},
)
Expand All @@ -57,14 +60,14 @@ const disabled = computed(
const addAttribute = () => {
if (!props.max || attributes.value.length < props.max) {
attributes.value.push({
attributes.value = [...attributes.value, {
value: '',
trait_type: '',
})
}]
}
}
const removeAttribute = (index: number) => attributes.value.splice(index, 1)
const removeAttribute = (index: number) => attributes.value = attributes.value.filter((_, i) => i !== index)
</script>

<style scoped>
Expand Down
23 changes: 16 additions & 7 deletions components/massmint/EditPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
:on-cancel="closePanel"
>
<div
class="border-l bg-background-color navbar-margin p-5 flex flex-col items-center justify-between h-full"
class="border-l bg-background-color navbar-margin p-5 flex flex-col items-center justify-between h-full overflow-y-auto"
>
<div class="flex w-full flex-col justify-between items-center">
<div class="flex w-full">
Expand All @@ -32,7 +32,7 @@
:name="nft?.name || `${nft?.id}`"
:size="128"
:placeholder="placeholder"
class="my-5"
class="my-5 overflow-hidden"
/>
<form class="w-full">
<NeoField
Expand All @@ -58,6 +58,13 @@
height="10rem"
/>
</NeoField>
<NeoField :label="`${$t('nft.properties.label')}`">
<CustomAttributeInput
v-model="attributes"
:max="10"
default-open
/>
</NeoField>
<NeoField
:label="$t('massmint.price')"
class="w-full"
Expand Down Expand Up @@ -100,6 +107,7 @@ import {
NeoSidebar,
} from '@kodadot1/brick'
import type { NFT } from './types'
import CustomAttributeInput from '@/components/create/CustomAttributeInput.vue'
const props = defineProps<{
nft?: NFT
Expand All @@ -112,14 +120,14 @@ const { placeholder } = useTheme()
const { unit } = useChain()
const internalNfT = ref<Partial<NFT>>({})
const dirty = ref({ name: false, description: false, price: false })
const dirty = ref({ name: false, description: false, price: false, attributes: false })
const createField = fieldName =>
const createField = (fieldName: string, defaultValue: string | unknown = '') =>
computed({
get: () =>
dirty.value[fieldName]
? internalNfT.value[fieldName]
: props.nft?.[fieldName] || '',
: props.nft?.[fieldName] || defaultValue,
set: (value) => {
internalNfT.value = {
...internalNfT.value,
Expand All @@ -133,12 +141,13 @@ const createField = fieldName =>
const name = createField('name')
const description = createField('description')
const price = createField('price')
const attributes = createField('attributes', [])
const emit = defineEmits(['close', 'save'])
const closePanel = () => {
internalNfT.value = {}
dirty.value = { name: false, description: false, price: false }
dirty.value = { name: false, description: false, price: false, attributes: false }
emit('close')
}
Expand All @@ -154,7 +163,7 @@ const save = () => {

<style lang="scss" scoped>
.navbar-margin {
margin-top: 83px;
margin-top: 80px;
}
.cover {
Expand Down
7 changes: 1 addition & 6 deletions components/massmint/OnBoarding.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
:source="
descriptionTabs[activeDescriptionTab].fileStructureDescription
"
class="fixed-height white-space-break-spaces-mobile"
class="h-[180px] max-w-[678px] overflow-auto white-space-break-spaces-mobile"
/>
<div class="flex justify-end mt-2">
<NeoButton
Expand Down Expand Up @@ -269,11 +269,6 @@ $card-width: clamp($min-card-width, $card-width-percents, $max-card-width);
}
}
.fixed-height {
height: 180px;
overflow-y: auto;
}
.carousel-dot {
@apply w-2.5 h-2.5 transition-[background-color] duration-[0.2s] ease-[ease-in-out] rounded-[25%];
Expand Down
17 changes: 17 additions & 0 deletions components/massmint/OverviewTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
<div class="column is-3 text-k-grey">
{{ $t('massmint.description') }}
</div>
<div class="column is-3 text-k-grey">
{{ $t('nft.properties.label') }}
</div>
<div class="column text-k-grey">
{{ $t('massmint.price') }}
</div>
Expand Down Expand Up @@ -71,6 +74,17 @@
{{ nft.description || $t('massmint.descriptionMissing') }}
</div>
</div>
<div class="column is-3 flex items-center">
<div
class="cursor-pointer overflow-hidden text-ellipsis whitespace-nowrap max-w-[90%]"
:class="{
'text-k-orange': !nft.attributes?.length,
}"
@click="openSideBarWith(nft)"
>
{{ nft.attributes?.length ? getNftAttributesOverview(nft) : $t('massmint.attributesMissing') }}
</div>
</div>
<div class="column flex items-center">
<div
class="cursor-pointer"
Expand Down Expand Up @@ -199,5 +213,8 @@ const handleIntersection = (entries: IntersectionObserverEntry[]) => {
const getNativeNftPrice = (nft: NFT): string =>
String((nft?.price || 0) * Math.pow(10, decimals.value))
const getNftAttributesOverview = (nft: NFT): string | undefined =>
nft.attributes?.map(attribute => attribute.value).join(', ')
useIntersectionObserver(sentinel, handleIntersection, { threshold: 0.66 })
</script>
16 changes: 16 additions & 0 deletions components/massmint/descriptionTabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,25 @@ export const descriptionTabs = {
"file": "file1.jpg",
"name": "Image1",
"description": "This is an image",
"attributes": [{
"value": "white",
"trait_type": "color"
}, {
"value": "happy",
"trait_type": "expression"
}],
"price": 2.45
},
{
"file": "file2.jpg",
"name": "Image2",
"attributes": [{
"value": "blue",
"trait_type": "color"
}, {
"value": "shy",
"trait_type": "expression"
}],
"price": 200
},
{
Expand Down Expand Up @@ -47,10 +61,12 @@ export const descriptionTabs = {
file: file1.jpg
name: Image1
description: This is an image
attributes: [{"value": "white","trait_type": "color"},{"value": "happy","trait_type": "expression"}]
price: 100 KSM
file: file2.jpg
name: Image2
attributes: [{"value": "blue","trait_type": "color"},{"value": "shy","trait_type": "expression"}]
price: 200
file: file3.jpg
Expand Down
4 changes: 3 additions & 1 deletion components/shared/collapse/CollapseWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,16 @@ const cprops = withDefaults(
hidden: string
bottom?: boolean
isSelectable?: boolean
defaultOpen?: boolean
}>(),
{
visible: 'Show',
hidden: 'Hide',
bottom: false,
isSelectable: false,
defaultOpen: false,
},
)
const isOpen = ref(false)
const isOpen = ref(cprops.defaultOpen)
const position = computed(() => (cprops.bottom ? 'bottom' : 'top'))
</script>
4 changes: 4 additions & 0 deletions composables/massmint/parsers/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export const isValidEntry = (entry: Partial<Entry>): boolean => {
return false
}

if (entry.attributes && !Array.isArray(entry.attributes)) {
return false
}

return true
}

Expand Down
2 changes: 1 addition & 1 deletion composables/massmint/parsers/parseJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function parseJson(jsonData: string): Record<string, Entry> {
name: item.name || undefined,
description: item.description || undefined,
price: item.price !== undefined ? parseFloat(item.price) : undefined,
attributes: item.attributes || [],
attributes: item.attributes,
}

if (!entry.file) {
Expand Down
6 changes: 5 additions & 1 deletion composables/massmint/parsers/parseTxt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function parseField(
): { fieldName: string, fieldValue: string } | null {
const colon = '\\s*:\\s*'
const fieldNameRegex = new RegExp(
`^(?<fieldName>file|name|description|price)${colon}`,
`^(?<fieldName>file|name|description|attributes|price)${colon}`,
'i',
)
const fieldNameMatch = fieldNameRegex.exec(line)
Expand Down Expand Up @@ -69,6 +69,9 @@ const updateEntry = (entry, line) => {
entry.price = price
entry.currency = currency
}
else if (fieldName === 'attributes') {
entry.attributes = JSON.parse(fieldValue)
}
else {
entry[fieldName] = fieldValue
}
Expand All @@ -91,6 +94,7 @@ const updateEntries = (entries, block) => {
file: entry.file,
name: entry.name,
description: entry.description,
attributes: entry.attributes,
price: entry.price,
currency: entry.currency,
valid: isValidEntry(entry),
Expand Down
1 change: 1 addition & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,7 @@
"markdownSupported": "Markdown supported",
"massmint": {
"areYouSureDelete": "Are you sure you want to delete",
"attributesMissing": "Attributes Missing",
"backToOnbaording": "Back To Onboarding",
"cancel": "Cancel",
"cantMintNote": "NOTE: You cannot mint unless you fill in the required information or delete incomplete files.",
Expand Down
16 changes: 16 additions & 0 deletions public/massmint/template.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,29 @@
"file": "art1.png",
"name": "Art #1",
"description": "Description for the Art #1",
"attributes": [{
"value": "white",
"trait_type": "color"
}, {
"value": "happy",
"trait_type": "expression"
}],
"price": 1

},
{
"file": "art2.png",
"name": "Art #2",
"description": "Description for the Art #2",
"attributes": [{
"value": "blue",
"trait_type": "color"
}, {
"value": "shy",
"trait_type": "expression"
}],
"price": 1

},
{
"file": "art3.png",
Expand Down
2 changes: 2 additions & 0 deletions public/massmint/template.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
file: art1.png
name: Art #1
description: Description for the Art #1
attributes: [{"value": "white","trait_type": "color"},{"value": "happy","trait_type": "expression"}]
price: 1


file: art2.png
name: Art #2
description: Description for the Art #2
attributes: [{"value": "blue","trait_type": "color"},{"value": "shy","trait_type": "expression"}]
price: 1


Expand Down

0 comments on commit 9d4da0d

Please sign in to comment.