Compare commits
No commits in common. 'master' and 'vue' have entirely different histories.
39 changed files with 818 additions and 2554 deletions
@ -1,5 +1,5 @@ |
|||||||
{ |
{ |
||||||
"url": "https://tonski-an7.pages.dev", |
"url": "https://agorata.io/", |
||||||
"name": "Agorata", |
"name": "Agorata", |
||||||
"iconUrl": "https://front.agorata.io/favicon.png" |
"iconUrl": "https://front.agorata.io/favicon.png" |
||||||
} |
} |
||||||
|
@ -1,71 +1,30 @@ |
|||||||
import axios from "axios"; |
import axios from 'axios' |
||||||
|
|
||||||
declare var process: { |
declare var process : { |
||||||
env: { |
env: { |
||||||
NODE_ENV: string; |
NODE_ENV: string |
||||||
}; |
} |
||||||
}; |
} |
||||||
|
|
||||||
export class Api { |
export class Api { |
||||||
public readonly api_url: string; |
public readonly api_url: string; |
||||||
public readonly ton_api_url: string; |
public agorata_adnl: string = "ed4f2afebb5e49dda9684a474c5771141be1f7d85a2fa39f1823844dd476c52d"; |
||||||
public readonly tonscan_url: string; |
|
||||||
public agorata_adnl: string = |
|
||||||
"ed4f2afebb5e49dda9684a474c5771141be1f7d85a2fa39f1823844dd476c52d"; |
|
||||||
public readonly tonviewer_url: string; |
|
||||||
|
|
||||||
constructor() { |
constructor() { |
||||||
if (process.env.NODE_ENV === "development") { |
if (process.env.NODE_ENV === 'development') { |
||||||
this.api_url = "http://localhost:5170/"; |
this.api_url = 'http://localhost:5170/'; |
||||||
this.ton_api_url = "https://testnet.tonapi.io/v2/"; |
} else { |
||||||
this.tonscan_url = "https://testnet.tonscan.org/"; |
this.api_url = 'https://api.agorata.io/'; |
||||||
this.tonviewer_url = "https://testnet.tonviewer.com/"; |
} |
||||||
} else { |
|
||||||
this.api_url = "https://agorata.io/api/"; |
|
||||||
this.ton_api_url = "https://tonapi.io/v2/"; |
|
||||||
this.tonscan_url = "https://tonscan.org/"; |
|
||||||
this.tonviewer_url = "https://testnet.tonviewer.com/"; |
|
||||||
} |
} |
||||||
} |
|
||||||
} |
} |
||||||
|
|
||||||
export const config = new Api(); |
export const config = new Api(); |
||||||
|
|
||||||
export async function call_api(url: string) { |
export async function call_api(url: string) { |
||||||
return (await axios.get(config.api_url + url)).data; |
return (await axios.get(config.api_url + url)).data; |
||||||
} |
} |
||||||
|
|
||||||
export async function call_api_post(url: string, data: any) { |
export async function call_api_post(url: string, data: any) { |
||||||
return (await axios.post(config.api_url + url, data)).data; |
return (await axios.post(config.api_url + url, data)).data; |
||||||
} |
|
||||||
|
|
||||||
export async function get_templates(url: string) { |
|
||||||
return await new Promise((resolve) => |
|
||||||
resolve([ |
|
||||||
{ |
|
||||||
title: "", |
|
||||||
description: "", |
|
||||||
links: [{ telegram: "", mail: "", site: "" }], |
|
||||||
preview: "https://api.agorata.io/static/mountain.jpg", |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: "", |
|
||||||
description: "", |
|
||||||
links: [{ telegram: "", mail: "", site: "" }], |
|
||||||
preview: "https://api.agorata.io/static/mountain.jpg", |
|
||||||
}, |
|
||||||
{ |
|
||||||
title: "", |
|
||||||
description: "", |
|
||||||
links: [{ telegram: "", mail: "", site: "" }], |
|
||||||
preview: "https://api.agorata.io/static/mountain.jpg", |
|
||||||
}, |
|
||||||
// {
|
|
||||||
// title: "",
|
|
||||||
// description: "",
|
|
||||||
// links: [{ telegram: "", mail: "", site: "" }],
|
|
||||||
// preview: "https://api.agorata.io/static/mountain.jpg",
|
|
||||||
// },
|
|
||||||
]) |
|
||||||
); |
|
||||||
} |
} |
||||||
|
@ -1,196 +1,197 @@ |
|||||||
@import "./base.css"; |
@import './base.css'; |
||||||
|
|
||||||
@tailwind base; |
@tailwind base; |
||||||
@tailwind components; |
@tailwind components; |
||||||
@tailwind utilities; |
@tailwind utilities; |
||||||
|
|
||||||
#app { |
#app { |
||||||
margin: 0 auto; |
margin: 0 auto; |
||||||
padding: 0; |
padding: 0; |
||||||
min-width: 100vw; |
min-width: 100vw; |
||||||
min-height: 100vh; |
min-height: 100vh; |
||||||
} |
} |
||||||
|
|
||||||
a, |
a, |
||||||
.green { |
.green { |
||||||
text-decoration: none; |
text-decoration: none; |
||||||
color: hsl(201, 100%, 37%); |
color: hsl(201, 100%, 37%); |
||||||
transition: 0.4s; |
transition: 0.4s; |
||||||
} |
} |
||||||
|
|
||||||
@media (min-width: 1024px) { |
@media (min-width: 1024px) { |
||||||
body { |
body { |
||||||
display: flex; |
display: flex; |
||||||
place-items: center; |
place-items: center; |
||||||
} |
} |
||||||
|
|
||||||
#app { |
#app { |
||||||
display: grid; |
display: grid; |
||||||
grid-template-columns: 1fr 1fr; |
grid-template-columns: 1fr 1fr; |
||||||
padding: 0; |
padding: 0; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
.b { |
.b { |
||||||
border: 2px solid transparent; |
border: 2px solid transparent; |
||||||
border-radius: 5px; |
border-radius: 5px; |
||||||
padding: 16px 26px; |
padding: 16px 26px; |
||||||
text-align: center; |
text-align: center; |
||||||
text-decoration: none; |
text-decoration: none; |
||||||
display: inline-block; |
display: inline-block; |
||||||
font-size: 1.55rem; |
font-size: 1.55rem; |
||||||
margin: 4px 2px; |
margin: 4px 2px; |
||||||
cursor: pointer; |
cursor: pointer; |
||||||
font-weight: bold; |
font-weight: bold; |
||||||
} |
} |
||||||
|
|
||||||
@media (max-width: 800px) { |
@media (max-width: 800px) { |
||||||
.b { |
.b { |
||||||
font-size: 1.4rem; |
font-size: 1.4rem; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
.b.white { |
.b.white { |
||||||
background-color: white; |
background-color: white; |
||||||
color: #282e46; |
color: #282e46; |
||||||
} |
} |
||||||
|
|
||||||
.b.white:hover { |
.b.white:hover { |
||||||
background-color: #282e46; |
background-color: #282e46; |
||||||
color: white; |
color: white; |
||||||
border: 2px solid white; |
border: 2px solid white; |
||||||
} |
} |
||||||
|
|
||||||
.b.blue { |
.b.blue { |
||||||
background-color: #0088cc; |
background-color: #0088cc; |
||||||
color: white; |
color: white; |
||||||
border-radius: 1rem; |
border-radius: 1rem; |
||||||
} |
} |
||||||
|
|
||||||
.b > img:first-child { |
.b > img:first-child { |
||||||
max-height: 1.4rem; |
max-height: 1.4rem; |
||||||
margin-right: 0.7rem; |
margin-right: 0.7rem; |
||||||
} |
} |
||||||
|
|
||||||
.b > img:not(:first-child) { |
.b > img:not(:first-child) { |
||||||
max-height: 1.4rem; |
max-height: 1.4rem; |
||||||
margin-left: 2rem; |
margin-left: 2rem; |
||||||
} |
} |
||||||
|
|
||||||
.wide.b { |
.wide.b { |
||||||
min-width: 16rem; |
min-width: 16rem; |
||||||
margin: 0.5rem; |
margin: 0.5rem; |
||||||
} |
} |
||||||
|
|
||||||
/* A #edeef1 box with rounded corners with black content color and content centered vertically and horizontally */ |
/* A #edeef1 box with rounded corners with black content color and content centered vertically and horizontally */ |
||||||
.rbox { |
.rbox { |
||||||
background-color: #edeef1; |
background-color: #edeef1; |
||||||
border-radius: 2rem; |
border-radius: 2rem; |
||||||
padding: 2.5rem 32px; |
padding: 2.5rem 32px; |
||||||
text-align: center; |
text-align: center; |
||||||
display: flex; |
display: flex; |
||||||
align-items: center; |
align-items: center; |
||||||
place-content: center; |
place-content: center; |
||||||
justify-content: center; |
justify-content: center; |
||||||
font-size: 1.6rem; |
font-size: 1.6rem; |
||||||
font-weight: bold; |
font-weight: bold; |
||||||
color: #282e46; |
color: #282e46; |
||||||
min-width: 16rem; |
min-width: 16rem; |
||||||
margin: 0.5rem 3rem; |
margin: 0.5rem 3rem; |
||||||
} |
} |
||||||
|
|
||||||
/* small margin on mobile */ |
/* small margin on mobile */ |
||||||
@media (max-width: 800px) { |
@media (max-width: 800px) { |
||||||
.rbox { |
.rbox { |
||||||
margin: 0.5rem 0.5rem; |
margin: 0.5rem 0.5rem; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
.rbox > p:not(:first-child) { |
.rbox > p:not(:first-child) { |
||||||
margin-top: 1rem; |
margin-top: 1rem; |
||||||
} |
} |
||||||
|
|
||||||
.center { |
.center { |
||||||
display: flex; |
display: flex; |
||||||
justify-content: center; |
justify-content: center; |
||||||
align-items: center; |
align-items: center; |
||||||
place-items: center; |
place-items: center; |
||||||
flex-direction: column; |
flex-direction: column; |
||||||
} |
} |
||||||
|
|
||||||
.b.darkish { |
.b.darkish { |
||||||
background-color: #4e5a88; |
background-color: #4e5a88; |
||||||
color: white; |
color: white; |
||||||
border-radius: 0.5rem; |
border-radius: 0.5rem; |
||||||
font-size: 1rem; |
font-size: 1rem; |
||||||
} |
} |
||||||
|
|
||||||
.mono { |
.mono { |
||||||
font-family: "Inconsolata", monospace; |
font-family: 'Inconsolata', monospace; |
||||||
} |
} |
||||||
|
|
||||||
:root { |
:root { |
||||||
--popper-theme-background-color: #fff; |
--popper-theme-background-color: #fff; |
||||||
--popper-theme-background-color-hover: #fff; |
--popper-theme-background-color-hover: #fff; |
||||||
--popper-theme-text-color: black; |
--popper-theme-text-color: black; |
||||||
--popper-theme-border-width: 0px; |
--popper-theme-border-width: 0px; |
||||||
--popper-theme-border-style: solid; |
--popper-theme-border-style: solid; |
||||||
--popper-theme-border-radius: 6px; |
--popper-theme-border-radius: 6px; |
||||||
--popper-theme-padding: 4px; |
--popper-theme-padding: 4px; |
||||||
--popper-theme-box-shadow: 0 6px 30px -6px rgba(0, 0, 0, 0.25); |
--popper-theme-box-shadow: 0 6px 30px -6px rgba(0, 0, 0, 0.25); |
||||||
} |
} |
||||||
|
|
||||||
.popper { |
.popper { |
||||||
font-size: 0.8rem; |
font-size: 0.8rem; |
||||||
font-family: "Inconsolata", monospace; |
font-family: 'Inconsolata', monospace; |
||||||
} |
} |
||||||
|
|
||||||
.mobile-scale { |
.mobile-scale { |
||||||
scale: 100%; |
scale: 100%; |
||||||
} |
} |
||||||
|
|
||||||
@media (max-width: 800px) { |
@media (max-width: 800px) { |
||||||
.mobile-scale { |
.mobile-scale { |
||||||
scale: 80%; |
scale: 80%; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
.get_b { |
.get_b { |
||||||
background-color: #e36464; |
background-color: #e36464; |
||||||
color: #363e5e; |
color: #363e5e; |
||||||
border-radius: 0.5rem; |
border-radius: 0.5rem; |
||||||
padding: 0.2rem 0.8rem; |
padding: 0.2rem 0.8rem; |
||||||
cursor: pointer; |
margin-left: 0.9rem; |
||||||
|
cursor: pointer; |
||||||
} |
} |
||||||
|
|
||||||
@media only screen and (max-width: 800px) { |
@media only screen and (max-width: 800px) { |
||||||
.get_b { |
.get_b { |
||||||
margin-left: 0.1rem; |
margin-left: 0.1rem; |
||||||
padding-left: 0.4rem; |
padding-left: 0.4rem; |
||||||
padding-right: 0.4rem; |
padding-right: 0.4rem; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
.flex { |
.flex { |
||||||
display: flex; |
display: flex; |
||||||
} |
} |
||||||
|
|
||||||
.b.back { |
.b.back { |
||||||
font-family: "Inconsolata", monospace; |
font-family: 'Inconsolata', monospace; |
||||||
font-size: 1.5rem; |
font-size: 1.5rem; |
||||||
padding: 0.8rem; |
padding: 0.8rem; |
||||||
} |
} |
||||||
|
|
||||||
.b.back > img { |
.b.back > img { |
||||||
max-height: 1rem; |
max-height: 1rem; |
||||||
margin-right: 0.4rem; |
margin-right: 0.4rem; |
||||||
} |
} |
||||||
|
|
||||||
.material-icons.language { |
.material-icons.language { |
||||||
position: relative; |
position:relative; |
||||||
display: inline-block; |
display:inline-block; |
||||||
} |
} |
||||||
|
|
||||||
.material-icons.language:after { |
.material-icons.language:after { |
||||||
content: "language"; |
content: "language"; |
||||||
} |
} |
||||||
|
@ -1,98 +0,0 @@ |
|||||||
<template> |
|
||||||
<div class="drag-drop-uploader"> |
|
||||||
<div class="drag-drop-area" @dragover="handleDragOver" @drop="handleDrop"> |
|
||||||
<template v-if="uploadedFiles.length === 0"> |
|
||||||
<button class="button" type="button" @click="openFileInput"> |
|
||||||
Add File |
|
||||||
</button> |
|
||||||
<p>...or drag and drop a file.</p> |
|
||||||
</template> |
|
||||||
<template v-else> |
|
||||||
<button |
|
||||||
class="button" |
|
||||||
type="button" |
|
||||||
v-if="uploadedFiles.length > 0" |
|
||||||
@click="openFileInput" |
|
||||||
> |
|
||||||
Change |
|
||||||
</button> |
|
||||||
<p>{{ uploadedFiles.at(-1).name }}</p> |
|
||||||
</template> |
|
||||||
</div> |
|
||||||
<input |
|
||||||
type="file" |
|
||||||
ref="fileInput" |
|
||||||
style="display: none" |
|
||||||
@change="handleFileInput" |
|
||||||
multiple |
|
||||||
/> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
|
|
||||||
<script> |
|
||||||
export default { |
|
||||||
data() { |
|
||||||
return { |
|
||||||
uploadedFiles: [], |
|
||||||
}; |
|
||||||
}, |
|
||||||
methods: { |
|
||||||
handleDragOver(event) { |
|
||||||
event.preventDefault(); |
|
||||||
}, |
|
||||||
handleDrop(event) { |
|
||||||
event.preventDefault(); |
|
||||||
const files = event.dataTransfer.files; |
|
||||||
this.uploadFiles(files); |
|
||||||
}, |
|
||||||
openFileInput() { |
|
||||||
this.$refs.fileInput.click(); |
|
||||||
}, |
|
||||||
handleFileInput(event) { |
|
||||||
const files = event.target.files; |
|
||||||
this.uploadFiles(files); |
|
||||||
}, |
|
||||||
uploadFiles(files) { |
|
||||||
console.log(files); |
|
||||||
for (let i = 0; i < files.length; i++) { |
|
||||||
this.uploadedFiles.push(files[i]); |
|
||||||
} |
|
||||||
}, |
|
||||||
change() { |
|
||||||
this.openFileInput(); |
|
||||||
}, |
|
||||||
}, |
|
||||||
}; |
|
||||||
</script> |
|
||||||
|
|
||||||
<style scoped> |
|
||||||
.drag-drop-uploader { |
|
||||||
margin: 0 auto; |
|
||||||
} |
|
||||||
|
|
||||||
.drag-drop-area { |
|
||||||
display: grid; |
|
||||||
align-content: center; |
|
||||||
border: 2px dashed #ccc; |
|
||||||
border-radius: 10px; |
|
||||||
padding: 20px; |
|
||||||
text-align: center; |
|
||||||
} |
|
||||||
|
|
||||||
ul { |
|
||||||
margin-top: 20px; |
|
||||||
} |
|
||||||
|
|
||||||
.button { |
|
||||||
justify-self: center; |
|
||||||
border: 0; |
|
||||||
border-radius: 0.5rem; |
|
||||||
height: 3rem; |
|
||||||
background-color: #e36464; |
|
||||||
color: #363e5e; |
|
||||||
font-size: 1.3rem; |
|
||||||
font-weight: 500; |
|
||||||
padding: 0 1rem; |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
</style> |
|
@ -1,198 +0,0 @@ |
|||||||
<template> |
|
||||||
<table class="table_outer"> |
|
||||||
<tbody class="table_content"> |
|
||||||
<tr v-for="item in items"> |
|
||||||
<td> |
|
||||||
<div style="display: flex; align-items: center; gap: 12px"> |
|
||||||
<img |
|
||||||
style="border-radius: 10px" |
|
||||||
width="50" |
|
||||||
height="50" |
|
||||||
:src="item.previews[1].url" |
|
||||||
:alt="item?.metadata?.name" |
|
||||||
/> |
|
||||||
|
|
||||||
<Tooltip text="View in explorer"> |
|
||||||
<a |
|
||||||
target="_blank" |
|
||||||
:href="`${config.tonscan_url}address/${item?.address}`" |
|
||||||
> |
|
||||||
<img src="@/assets/icons/link.svg" /> |
|
||||||
</a> |
|
||||||
</Tooltip> |
|
||||||
<span |
|
||||||
style=" |
|
||||||
white-space: nowrap; |
|
||||||
overflow: hidden; |
|
||||||
text-overflow: ellipsis; |
|
||||||
" |
|
||||||
> |
|
||||||
{{ item?.metadata?.name }} |
|
||||||
</span> |
|
||||||
</div> |
|
||||||
</td> |
|
||||||
<td> |
|
||||||
<Tooltip text="Go to site"> |
|
||||||
<a target="_blank" :href="item?.dns"> |
|
||||||
<img |
|
||||||
src="@/assets/icons/globe.svg" |
|
||||||
style="display: flex" |
|
||||||
cursor="pointer" |
|
||||||
/> |
|
||||||
</a> |
|
||||||
</Tooltip> |
|
||||||
</td> |
|
||||||
<td> |
|
||||||
<button @click="onManageClick(item)" class="button">Manage</button> |
|
||||||
</td> |
|
||||||
</tr> |
|
||||||
</tbody> |
|
||||||
</table> |
|
||||||
<div class="center"> |
|
||||||
<RotateSquare2 |
|
||||||
v-if="isLoading" |
|
||||||
style="width: 5rem; height: 5rem; margin-top: 3rem" |
|
||||||
/> |
|
||||||
<p v-if="error">{{ error }}</p> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
|
|
||||||
<script setup lang="ts"> |
|
||||||
import type { CollectionItem } from "@/types"; |
|
||||||
import axios, { AxiosError } from "axios"; |
|
||||||
import { computed, onMounted, ref, watch } from "vue"; |
|
||||||
import Tooltip from "./Tooltip.vue"; |
|
||||||
import { useRouter } from "vue-router"; |
|
||||||
import { get_zones } from "@/result"; |
|
||||||
import type { Zone } from "@/zone"; |
|
||||||
import { convertAddress } from "@/utils"; |
|
||||||
import { useStore } from "vuex"; |
|
||||||
import { config } from "@/api"; |
|
||||||
import RotateSquare2 from "../components/RotateSquare2.vue"; |
|
||||||
|
|
||||||
const store = useStore(); |
|
||||||
|
|
||||||
const { push } = useRouter(); |
|
||||||
|
|
||||||
const onManageClick = (item: CollectionItem) => { |
|
||||||
push({ name: "Explore", params: { domain: item.metadata.name } }); |
|
||||||
}; |
|
||||||
|
|
||||||
const zonesAddresses = ref<(string | undefined)[]>([]); |
|
||||||
|
|
||||||
const items = ref<CollectionItem[]>([]); |
|
||||||
|
|
||||||
const isLoading = ref(false); |
|
||||||
const error = ref(""); |
|
||||||
|
|
||||||
const address = computed(() => |
|
||||||
store.getters.address ? convertAddress(store.getters.address) : "" |
|
||||||
); |
|
||||||
|
|
||||||
const fetchDomains = async () => { |
|
||||||
if (address.value) { |
|
||||||
isLoading.value = true; |
|
||||||
|
|
||||||
const zones = (await get_zones()) as Zone[]; |
|
||||||
|
|
||||||
zonesAddresses.value = zones.map(({ address }) => address?.toLowerCase()); |
|
||||||
|
|
||||||
try { |
|
||||||
const [ |
|
||||||
resultNfts = { data: { nft_items: [] } }, |
|
||||||
resultTonNfts = { data: { nft_items: [] } }, |
|
||||||
] = await Promise.all([ |
|
||||||
axios.get<{ nft_items: CollectionItem[] }>( |
|
||||||
`${config.ton_api_url}accounts/${address.value}/nfts` |
|
||||||
), |
|
||||||
axios.get<{ nft_items: CollectionItem[] }>( |
|
||||||
`${config.ton_api_url}accounts/${address.value}/nfts`, |
|
||||||
{ |
|
||||||
params: { |
|
||||||
collection: "EQC3dNlesgVD8YbAazcauIrXBPfiVhMMr5YYk2in0Mtsz0Bz", |
|
||||||
}, |
|
||||||
} |
|
||||||
), |
|
||||||
]); |
|
||||||
|
|
||||||
items.value = [ |
|
||||||
...resultTonNfts.data.nft_items, |
|
||||||
...resultNfts.data.nft_items |
|
||||||
.map((item) => ({ |
|
||||||
...item, |
|
||||||
formattedCollectionAddress: item.collection?.address |
|
||||||
? convertAddress(item.collection?.address).toLowerCase() |
|
||||||
: "", |
|
||||||
})) |
|
||||||
.filter(({ formattedCollectionAddress }) => |
|
||||||
zonesAddresses.value.includes(formattedCollectionAddress) |
|
||||||
), |
|
||||||
]; |
|
||||||
} catch (e) { |
|
||||||
if ((e as AxiosError).response?.status) { |
|
||||||
error.value = "You have made too many requests, please try again later"; |
|
||||||
console.log("too many requests"); |
|
||||||
} |
|
||||||
} finally { |
|
||||||
isLoading.value = false; |
|
||||||
} |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
onMounted(fetchDomains); |
|
||||||
|
|
||||||
watch(address, fetchDomains); |
|
||||||
</script> |
|
||||||
|
|
||||||
<style scoped> |
|
||||||
.table_outer { |
|
||||||
background-color: #4e5a88; |
|
||||||
border-radius: 0.5rem; |
|
||||||
} |
|
||||||
|
|
||||||
td { |
|
||||||
padding: 8px 16px; |
|
||||||
} |
|
||||||
|
|
||||||
td:first-child { |
|
||||||
max-width: 400px; |
|
||||||
} |
|
||||||
|
|
||||||
a { |
|
||||||
color: white; |
|
||||||
} |
|
||||||
|
|
||||||
@media only screen and (max-width: 800px) { |
|
||||||
td.zone { |
|
||||||
font-size: 1.1rem; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
th { |
|
||||||
padding: 4px 8px; |
|
||||||
} |
|
||||||
|
|
||||||
.table_content { |
|
||||||
padding: 1rem; |
|
||||||
min-height: 10rem; |
|
||||||
} |
|
||||||
|
|
||||||
.button { |
|
||||||
border: 0; |
|
||||||
border-radius: 0.5rem; |
|
||||||
height: 3rem; |
|
||||||
background-color: #e36464; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
align-items: center; |
|
||||||
place-items: center; |
|
||||||
color: #363e5e; |
|
||||||
font-size: 1.3rem; |
|
||||||
font-weight: 500; |
|
||||||
padding: 0 1rem; |
|
||||||
cursor: pointer; |
|
||||||
margin-left: 1rem; |
|
||||||
margin-top: 1rem; |
|
||||||
margin-bottom: 1rem; |
|
||||||
} |
|
||||||
</style> |
|
@ -1,56 +0,0 @@ |
|||||||
<template> |
|
||||||
<div class="constr-switcher"> |
|
||||||
<div |
|
||||||
v-for="item in items" |
|
||||||
@click="$emit('change', item)" |
|
||||||
:class="['constr-switch', { inactive: activeName !== item.name }]" |
|
||||||
> |
|
||||||
{{ item.name }} |
|
||||||
</div> |
|
||||||
<slot name="suffix" /> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
|
|
||||||
<script setup lang="ts"> |
|
||||||
type Item = { name: string }; |
|
||||||
|
|
||||||
defineProps<{ items: Item[]; activeName: string }>(); |
|
||||||
|
|
||||||
defineEmits<{ |
|
||||||
(e: "change", item: Item): void; |
|
||||||
}>(); |
|
||||||
</script> |
|
||||||
|
|
||||||
<style scoped> |
|
||||||
/* The switcher with two buttons - create from template or use custom */ |
|
||||||
.constr-switcher { |
|
||||||
display: flex; |
|
||||||
justify-content: space-between; |
|
||||||
align-items: center; |
|
||||||
margin-bottom: 1rem; |
|
||||||
border-radius: 1.3rem; |
|
||||||
padding: 1rem; |
|
||||||
background-color: #4e5a88; |
|
||||||
} |
|
||||||
|
|
||||||
/* The button inside the switcher */ |
|
||||||
.constr-switch { |
|
||||||
padding: 0.5rem 1rem; |
|
||||||
border-radius: 0.7rem; |
|
||||||
background-color: #cdcee8; |
|
||||||
color: #282e46; |
|
||||||
width: 13rem; |
|
||||||
cursor: default; |
|
||||||
} |
|
||||||
|
|
||||||
.constr-switch:not(:last-child) { |
|
||||||
margin-right: 1rem; |
|
||||||
} |
|
||||||
|
|
||||||
.constr-switch.inactive { |
|
||||||
/*background-color: #5d5f79;*/ |
|
||||||
background-color: #6a6e95; |
|
||||||
color: #cecddb; |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
</style> |
|
@ -1,294 +0,0 @@ |
|||||||
<template> |
|
||||||
<div v-for="template in templates"> |
|
||||||
<div v-if="template.name === activeTemplateName"> |
|
||||||
<img class="preview" width="280" height="280" :src="template.preview" /> |
|
||||||
<div style="display: flex; width: 100%"> |
|
||||||
<p style="width: 9rem">Title:</p> |
|
||||||
<contenteditable |
|
||||||
class="record-inp" |
|
||||||
tag="div" |
|
||||||
:no-hl="true" |
|
||||||
:no-html="true" |
|
||||||
spellcheck="false" |
|
||||||
v-model="constructor_params.title" |
|
||||||
></contenteditable> |
|
||||||
</div> |
|
||||||
<div style="display: flex; width: 100%"> |
|
||||||
<p style="width: 9rem">Description:</p> |
|
||||||
<contenteditable |
|
||||||
class="record-inp" |
|
||||||
tag="div" |
|
||||||
:no-hl="true" |
|
||||||
:no-html="true" |
|
||||||
spellcheck="false" |
|
||||||
v-model="constructor_params.description" |
|
||||||
></contenteditable> |
|
||||||
</div> |
|
||||||
<div style="display: flex; width: 100%"> |
|
||||||
<p style="width: 9rem">Picture:</p> |
|
||||||
<contenteditable |
|
||||||
class="record-inp" |
|
||||||
tag="div" |
|
||||||
:no-hl="true" |
|
||||||
:no-html="true" |
|
||||||
spellcheck="false" |
|
||||||
v-model="constructor_params.picture" |
|
||||||
></contenteditable> |
|
||||||
</div> |
|
||||||
<div style="display: flex; width: 100%"> |
|
||||||
<p style="width: 9rem">Add link:</p> |
|
||||||
<div |
|
||||||
v-for="link_type in link_types" |
|
||||||
:key="link_type" |
|
||||||
class="link-type" |
|
||||||
@click="addLink(link_type)" |
|
||||||
> |
|
||||||
<i class="link-type-icon add" :class="link_icons[link_type]"></i> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<!-- The links themselves (editing constructor_params.contacts[link_type] for each key) --> |
|
||||||
<div v-for="contact in contacts" :key="contact[0]" class="link-type"> |
|
||||||
<div style="display: flex; width: 100%"> |
|
||||||
<!-- the icon as a label --> |
|
||||||
<i |
|
||||||
style="width: 9rem" |
|
||||||
class="link-type-icon" |
|
||||||
:class="link_icons[contact[0]]" |
|
||||||
></i> |
|
||||||
<!-- editing the link - constructor_params.contacts[link_type] --> |
|
||||||
<contenteditable |
|
||||||
class="record-inp" |
|
||||||
tag="div" |
|
||||||
:no-hl="true" |
|
||||||
:no-html="true" |
|
||||||
spellcheck="false" |
|
||||||
v-model="constructor_params.contacts[contact[0]]" |
|
||||||
></contenteditable> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<div class="save_container center"> |
|
||||||
<div |
|
||||||
:class="{ |
|
||||||
'record-submit': true, |
|
||||||
get_b: true, |
|
||||||
inactive: !siteChanged, |
|
||||||
signing: signingSite, |
|
||||||
}" |
|
||||||
@click="$emit('save-constructor')" |
|
||||||
> |
|
||||||
<template v-if="!signingSite">Save and host</template> |
|
||||||
<template v-else> |
|
||||||
<Socket |
|
||||||
secondary-color="#a7aab3" |
|
||||||
color="#282e46" |
|
||||||
size="50px" |
|
||||||
style="min-width: 3rem" |
|
||||||
/> |
|
||||||
Confirm in the wallet... |
|
||||||
</template> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
|
|
||||||
<script> |
|
||||||
import Socket from "./Socket.vue"; |
|
||||||
import contenteditable from "vue-contenteditable"; |
|
||||||
import { config } from "../api"; |
|
||||||
import { default_links, SiteConstructorParams } from "../result"; |
|
||||||
import { link_types, link_icons } from "../result"; |
|
||||||
|
|
||||||
export default { |
|
||||||
name: "TemplatesList", |
|
||||||
components: { Socket, contenteditable }, |
|
||||||
props: { |
|
||||||
site_rec_init: { |
|
||||||
default: null, |
|
||||||
}, |
|
||||||
siteChanged: { |
|
||||||
type: Boolean, |
|
||||||
default: false, |
|
||||||
}, |
|
||||||
constructorChanged: { |
|
||||||
type: Boolean, |
|
||||||
default: false, |
|
||||||
}, |
|
||||||
signingSite: { |
|
||||||
type: Boolean, |
|
||||||
default: false, |
|
||||||
}, |
|
||||||
templates: { |
|
||||||
default: [], |
|
||||||
}, |
|
||||||
activeTemplateName: "", |
|
||||||
}, |
|
||||||
data() { |
|
||||||
let site_rec = this.site_rec_init; |
|
||||||
if (!site_rec) site_rec = config.agorata_adnl; |
|
||||||
let constructor_site = |
|
||||||
site_rec.toLowerCase() === config.agorata_adnl.toLowerCase(); |
|
||||||
return { |
|
||||||
site_rec, |
|
||||||
constructor_site, |
|
||||||
constructor_params: new SiteConstructorParams(""), |
|
||||||
saved_constructor_params: new SiteConstructorParams(""), |
|
||||||
contacts: [], |
|
||||||
}; |
|
||||||
}, |
|
||||||
watch: { |
|
||||||
site_rec_patched() { |
|
||||||
this.$emit("change", this.site_rec_patched); |
|
||||||
}, |
|
||||||
constructor_params: { |
|
||||||
handler: function (newVal) { |
|
||||||
this.$emit("change-constructor", newVal); |
|
||||||
}, |
|
||||||
deep: true, |
|
||||||
}, |
|
||||||
saved_constructor_params: { |
|
||||||
handler: function (newVal, oldVal) { |
|
||||||
if (newVal === oldVal) return; |
|
||||||
this.constructor_params = newVal.copy(); |
|
||||||
this.contacts = Object.entries(newVal.contacts); |
|
||||||
}, |
|
||||||
deep: true, |
|
||||||
}, |
|
||||||
contacts: { |
|
||||||
handler: function (newVal) { |
|
||||||
this.constructor_params.contacts = new Map(); |
|
||||||
for (let contact of newVal) { |
|
||||||
this.constructor_params.contacts[contact[0]] = contact[1]; |
|
||||||
} |
|
||||||
}, |
|
||||||
deep: true, |
|
||||||
}, |
|
||||||
}, |
|
||||||
computed: { |
|
||||||
site_rec_patched() { |
|
||||||
if (this.constructor_site) { |
|
||||||
return config.agorata_adnl; |
|
||||||
} else { |
|
||||||
return this.site_rec; |
|
||||||
} |
|
||||||
}, |
|
||||||
link_types() { |
|
||||||
// return the types from link_types that are not in the constructor_params.contacts |
|
||||||
return link_types.filter( |
|
||||||
(link_type) => !(link_type in this.constructor_params.contacts) |
|
||||||
); |
|
||||||
}, |
|
||||||
link_icons() { |
|
||||||
return link_icons; |
|
||||||
}, |
|
||||||
// used_link_types() { |
|
||||||
// return Object.keys(this.constructor_params.contacts); |
|
||||||
// }, |
|
||||||
}, |
|
||||||
methods: { |
|
||||||
set_site_rec(site_rec) { |
|
||||||
this.site_rec = site_rec; |
|
||||||
}, |
|
||||||
addLink(link_type) { |
|
||||||
console.log("adding link", link_type); |
|
||||||
// If there's already a link of this type, don't add it |
|
||||||
if (link_type in this.constructor_params.contacts) return; |
|
||||||
this.contacts.push([link_type, default_links[link_type]]); |
|
||||||
this.constructor_params.contacts[link_type] = default_links[link_type]; |
|
||||||
}, |
|
||||||
}, |
|
||||||
}; |
|
||||||
</script> |
|
||||||
|
|
||||||
<style scoped> |
|
||||||
.record-inp { |
|
||||||
padding: 0.3rem; |
|
||||||
margin-left: 0.5rem; |
|
||||||
border-radius: 0.3rem; |
|
||||||
background-color: #4e5a88; |
|
||||||
color: white; |
|
||||||
min-width: 50vw; |
|
||||||
width: 100%; |
|
||||||
} |
|
||||||
|
|
||||||
.rec-field:not(:last-child) { |
|
||||||
margin-bottom: 1rem; |
|
||||||
} |
|
||||||
|
|
||||||
.get_b.inactive { |
|
||||||
opacity: 0.5; |
|
||||||
cursor: default; |
|
||||||
} |
|
||||||
|
|
||||||
.get_b.signing { |
|
||||||
/* Center elements inside horizontally, allow rows */ |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
align-items: center; |
|
||||||
flex-direction: column; |
|
||||||
background-color: white; |
|
||||||
font-size: 1.4rem; |
|
||||||
} |
|
||||||
|
|
||||||
.constructor-form > div > div > div:not(:last-child) { |
|
||||||
margin-bottom: 1rem; |
|
||||||
} |
|
||||||
|
|
||||||
/* The switcher with two buttons - create from template or use custom */ |
|
||||||
.constr-switcher { |
|
||||||
display: flex; |
|
||||||
justify-content: space-between; |
|
||||||
align-items: center; |
|
||||||
margin-bottom: 1rem; |
|
||||||
border-radius: 1.3rem; |
|
||||||
padding: 1rem; |
|
||||||
max-width: 35rem; |
|
||||||
background-color: #4e5a88; |
|
||||||
} |
|
||||||
|
|
||||||
/* The button inside the switcher */ |
|
||||||
.constr-switch { |
|
||||||
padding: 0.5rem 1rem; |
|
||||||
border-radius: 0.7rem; |
|
||||||
background-color: #cdcee8; |
|
||||||
color: #282e46; |
|
||||||
width: 13rem; |
|
||||||
cursor: default; |
|
||||||
} |
|
||||||
|
|
||||||
.constr-switch:not(:last-child) { |
|
||||||
margin-right: 1rem; |
|
||||||
} |
|
||||||
|
|
||||||
.constr-switch.inactive { |
|
||||||
/*background-color: #5d5f79;*/ |
|
||||||
background-color: #6a6e95; |
|
||||||
color: #cecddb; |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
|
|
||||||
.site-record-field { |
|
||||||
font-family: "Inconsolata", monospace; |
|
||||||
} |
|
||||||
|
|
||||||
.link-type:not(:last-child) { |
|
||||||
margin-right: 1rem; |
|
||||||
} |
|
||||||
|
|
||||||
.link-type-icon.add { |
|
||||||
font-size: 2rem; |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
|
|
||||||
.link-type-icon.add:hover { |
|
||||||
color: #e88484; |
|
||||||
} |
|
||||||
|
|
||||||
.link-type-icon { |
|
||||||
font-size: 2.5rem; |
|
||||||
} |
|
||||||
|
|
||||||
.preview { |
|
||||||
border-radius: 1.5rem; |
|
||||||
} |
|
||||||
</style> |
|
@ -1,78 +0,0 @@ |
|||||||
<template> |
|
||||||
<div |
|
||||||
@mouseleave="onMouseLeave" |
|
||||||
@mouseenter="onMouseEnter" |
|
||||||
class="tooltip-container" |
|
||||||
> |
|
||||||
<slot /> |
|
||||||
<div |
|
||||||
v-if="showTooltip" |
|
||||||
:class="{ tooltip: true, top: position === 'top' }" |
|
||||||
:style="width ? `width: ${width}px` : ''" |
|
||||||
> |
|
||||||
<slot name="content" /> |
|
||||||
{{ text }} |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
|
|
||||||
<script> |
|
||||||
import { ref } from "vue"; |
|
||||||
|
|
||||||
export default { |
|
||||||
name: "Tooltip", |
|
||||||
props: { |
|
||||||
text: { |
|
||||||
type: String, |
|
||||||
required: true, |
|
||||||
}, |
|
||||||
position: { |
|
||||||
type: String, |
|
||||||
}, |
|
||||||
width: { |
|
||||||
type: Number, |
|
||||||
}, |
|
||||||
}, |
|
||||||
setup(props) { |
|
||||||
const showTooltip = ref(false); |
|
||||||
|
|
||||||
function onMouseEnter() { |
|
||||||
showTooltip.value = true; |
|
||||||
} |
|
||||||
|
|
||||||
function onMouseLeave() { |
|
||||||
showTooltip.value = false; |
|
||||||
} |
|
||||||
|
|
||||||
return { |
|
||||||
showTooltip, |
|
||||||
onMouseEnter, |
|
||||||
onMouseLeave, |
|
||||||
}; |
|
||||||
}, |
|
||||||
}; |
|
||||||
</script> |
|
||||||
|
|
||||||
<style> |
|
||||||
.tooltip-container { |
|
||||||
position: relative; |
|
||||||
} |
|
||||||
|
|
||||||
.tooltip { |
|
||||||
min-width: 100px; |
|
||||||
font-size: large; |
|
||||||
z-index: 1; |
|
||||||
position: absolute; |
|
||||||
top: 100%; |
|
||||||
left: 50%; |
|
||||||
transform: translateX(-50%); |
|
||||||
background-color: #333; |
|
||||||
color: #fff; |
|
||||||
padding: 0.5rem; |
|
||||||
border-radius: 0.25rem; |
|
||||||
|
|
||||||
&.top { |
|
||||||
transform: translate(-50%, calc(-100% - 24px)); |
|
||||||
} |
|
||||||
} |
|
||||||
</style> |
|
@ -1,112 +1,100 @@ |
|||||||
import { createApp } from "vue"; |
import {createApp} from 'vue' |
||||||
import App from "./App.vue"; |
import App from './App.vue' |
||||||
import router from "./router"; |
import router from './router' |
||||||
import { createStore } from "vuex"; |
import {createStore} from 'vuex' |
||||||
import TonConnect from "@tonconnect/sdk"; |
import TonConnect from '@tonconnect/sdk'; |
||||||
import { isWalletInfoInjected } from "@tonconnect/sdk"; |
import {isWalletInfoInjected} from '@tonconnect/sdk'; |
||||||
import type { |
import type {WalletInfo, WalletInfoInjected, WalletInfoRemote} from '@tonconnect/sdk'; |
||||||
WalletInfo, |
import './assets/main.css' |
||||||
WalletInfoInjected, |
|
||||||
WalletInfoRemote, |
|
||||||
} from "@tonconnect/sdk"; |
|
||||||
import "./assets/main.css"; |
|
||||||
|
|
||||||
const app = createApp(App); |
const app = createApp(App) |
||||||
|
|
||||||
class State { |
class State { |
||||||
connector: TonConnect; |
connector: TonConnect; |
||||||
walletList: WalletInfo[] = []; |
walletList: WalletInfo[] = []; |
||||||
initialization: Promise<void>; |
initialization: Promise<void>; |
||||||
|
|
||||||
constructor() { |
constructor() { |
||||||
this.connector = new TonConnect({ |
this.connector = new TonConnect({manifestUrl: 'https://front.agorata.io/tonconnect-manifest.json'}); |
||||||
manifestUrl: "https://agorata.io/tonconnect-manifest.json", |
this.initialization = this.initialize(); |
||||||
}); |
} |
||||||
this.initialization = this.initialize(); |
|
||||||
} |
|
||||||
|
|
||||||
async initialize() { |
async initialize() { |
||||||
await this.connector.restoreConnection(); |
await this.connector.restoreConnection(); |
||||||
this.walletList = await this.connector.getWallets(); |
this.walletList = await this.connector.getWallets(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
const store = createStore({ |
const store = createStore({ |
||||||
state() { |
state() { |
||||||
return new State(); |
return new State() |
||||||
}, |
|
||||||
mutations: { |
|
||||||
set_connector(state, connector) { |
|
||||||
state.connector = connector; |
|
||||||
}, |
}, |
||||||
}, |
mutations: { |
||||||
getters: { |
set_connector(state, connector) { |
||||||
is_connected(state) { |
state.connector = connector |
||||||
return state.connector.connected; |
} |
||||||
}, |
|
||||||
address(state) { |
|
||||||
if ( |
|
||||||
state.connector.account !== null && |
|
||||||
state.connector.account.address !== undefined |
|
||||||
) { |
|
||||||
return state.connector.account.address; |
|
||||||
} else { |
|
||||||
return ""; |
|
||||||
} |
|
||||||
}, |
}, |
||||||
connector(state) { |
getters: { |
||||||
return state.connector; |
is_connected(state) { |
||||||
|
return state.connector.connected; |
||||||
|
}, |
||||||
|
address(state) { |
||||||
|
if (state.connector.account !== null && state.connector.account.address !== undefined) { |
||||||
|
return state.connector.account.address; |
||||||
|
} else { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
} |
||||||
}, |
}, |
||||||
}, |
actions: { |
||||||
actions: { |
async connect_embedded({state}) { |
||||||
async connect_embedded({ state }) { |
const walletsList = await TonConnect.getWallets(); |
||||||
const walletsList = await TonConnect.getWallets(); |
let connector = state.connector; |
||||||
let connector = state.connector; |
const embeddedWallet = walletsList.find( |
||||||
const embeddedWallet = walletsList.find( |
wallet => isWalletInfoInjected(wallet) && wallet.embedded |
||||||
(wallet) => isWalletInfoInjected(wallet) && wallet.embedded |
) as WalletInfoInjected; |
||||||
) as WalletInfoInjected; |
console.log(walletsList, embeddedWallet); |
||||||
console.log(walletsList, embeddedWallet); |
|
||||||
|
|
||||||
if (embeddedWallet) { |
if (embeddedWallet) { |
||||||
connector.connect({ jsBridgeKey: embeddedWallet.jsBridgeKey }); |
connector.connect({jsBridgeKey: embeddedWallet.jsBridgeKey}); |
||||||
} |
} |
||||||
}, |
}, |
||||||
/* Connect embedded wallet if it exists, otherwise get connection url for a QR code unless we're already connected */ |
/* Connect embedded wallet if it exists, otherwise get connection url for a QR code unless we're already connected */ |
||||||
async get_connection_url({ state }): Promise<string | null> { |
async get_connection_url({state}): Promise<string | null> { |
||||||
await state.initialization; |
await state.initialization; |
||||||
await this.dispatch("connect_embedded"); |
await this.dispatch('connect_embedded'); |
||||||
if (state.connector.connected) { |
if (state.connector.connected) { |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
let walletList = this.state.walletList as WalletInfo[]; |
let walletList = this.state.walletList as WalletInfo[]; |
||||||
if (walletList.length === 0) { |
if (walletList.length === 0) { |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
/* iterate through wallets and do try-catch */ |
/* iterate through wallets and do try-catch */ |
||||||
for (let wallet of walletList) { |
for (let wallet of walletList) { |
||||||
try { |
try { |
||||||
let wallet_r = wallet as WalletInfoRemote; |
let wallet_r = wallet as WalletInfoRemote; |
||||||
let wallet_desc = { |
let wallet_desc = { |
||||||
bridgeUrl: wallet_r.bridgeUrl, |
bridgeUrl: wallet_r.bridgeUrl, |
||||||
universalLink: wallet_r.universalLink, |
universalLink: wallet_r.universalLink |
||||||
}; |
} |
||||||
let res = await state.connector.connect(wallet_desc); |
let res = await state.connector.connect(wallet_desc); |
||||||
if (typeof res === "string") { |
if (typeof res === 'string') { |
||||||
return res; |
return res; |
||||||
} |
} |
||||||
} catch (e) { |
} catch (e) { |
||||||
console.log(wallet, e); |
console.log(wallet, e) |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
}, |
||||||
|
async disconnect({state}) { |
||||||
|
await state.connector.disconnect(); |
||||||
} |
} |
||||||
} |
} |
||||||
return null; |
}) |
||||||
}, |
|
||||||
async disconnect({ state }) { |
|
||||||
await state.connector.disconnect(); |
|
||||||
}, |
|
||||||
}, |
|
||||||
}); |
|
||||||
|
|
||||||
app.use(router); |
app.use(router) |
||||||
app.use(store); |
app.use(store) |
||||||
|
|
||||||
app.mount("#app"); |
app.mount('#app') |
||||||
|
@ -1,3 +0,0 @@ |
|||||||
export const myDomains = "my-domains"; |
|
||||||
export const mintCollection = "mint-collection"; |
|
||||||
export const addTemplate = "add-template"; |
|
@ -1,24 +0,0 @@ |
|||||||
export type Collection = { |
|
||||||
address: string; |
|
||||||
metadata: { |
|
||||||
description: string; |
|
||||||
image: string; |
|
||||||
name: string; |
|
||||||
}; |
|
||||||
next_item_index: number; |
|
||||||
raw_collection_content: string; |
|
||||||
}; |
|
||||||
|
|
||||||
export type CollectionItem = { |
|
||||||
address: string; |
|
||||||
metadata: { |
|
||||||
name: string; |
|
||||||
description: string; |
|
||||||
image: string; |
|
||||||
}; |
|
||||||
collection: { |
|
||||||
address: string; |
|
||||||
}; |
|
||||||
dns: string; |
|
||||||
previews: { resolution: string; url: string }[]; |
|
||||||
}; |
|
@ -1,134 +0,0 @@ |
|||||||
<template> |
|
||||||
<DarkLayout> |
|
||||||
<form class="form"> |
|
||||||
<div class="input-wrapper"> |
|
||||||
<label for="template-name">Template name</label> |
|
||||||
<input v-model="name" class="input" id="template-name" type="text" /> |
|
||||||
</div> |
|
||||||
<DragDropUploader class="dnd" /> |
|
||||||
<div v-for="(_, i) in fields" class="input-wrapper"> |
|
||||||
<div class="fields-wrapper"> |
|
||||||
<div class="input-wrapper"> |
|
||||||
<label :for="`field-${i}`">Field {{ i + 1 }}</label> |
|
||||||
<input |
|
||||||
placeholder="Name" |
|
||||||
v-model="fields[i].name" |
|
||||||
class="input" |
|
||||||
:id="`field-${i}`" |
|
||||||
type="text" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
<div> |
|
||||||
<input |
|
||||||
placeholder="Value" |
|
||||||
v-model="fields[i].value" |
|
||||||
class="input" |
|
||||||
:id="`field-${i}`" |
|
||||||
type="text" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
<button |
|
||||||
class="button button-plus" |
|
||||||
style="justify-self: start" |
|
||||||
type="button" |
|
||||||
@click="fields.push({ name: '', value: '' })" |
|
||||||
> |
|
||||||
+ |
|
||||||
</button> |
|
||||||
<button class="button" type="button">Submit</button> |
|
||||||
</form> |
|
||||||
<template v-slot:header> |
|
||||||
<router-link to="/find"> |
|
||||||
<button class="b darkish back"> |
|
||||||
<img src="@/assets/icons/ton_left.svg" alt="TON" /> |
|
||||||
Back |
|
||||||
</button> |
|
||||||
</router-link> |
|
||||||
</template> |
|
||||||
</DarkLayout> |
|
||||||
</template> |
|
||||||
|
|
||||||
<script lang="ts" setup> |
|
||||||
import { ref } from "vue"; |
|
||||||
import DarkLayout from "../components/DarkLayout.vue"; |
|
||||||
import DragDropUploader from "@/components/DnD.vue"; |
|
||||||
|
|
||||||
const name = ref(""); |
|
||||||
|
|
||||||
const fields = ref([{ name: "", value: "" }]); |
|
||||||
</script> |
|
||||||
|
|
||||||
<style> |
|
||||||
.input-wrapper { |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
align-items: start; |
|
||||||
} |
|
||||||
|
|
||||||
.input { |
|
||||||
display: block; |
|
||||||
width: 100%; |
|
||||||
min-height: 40px; |
|
||||||
border: 0; |
|
||||||
border-radius: 10px; |
|
||||||
padding: 12px 24px; |
|
||||||
background-color: #4e5a88; |
|
||||||
color: white; |
|
||||||
font-size: 24px; |
|
||||||
font-family: "Raleway", serif; |
|
||||||
} |
|
||||||
|
|
||||||
input::-webkit-outer-spin-button, |
|
||||||
input::-webkit-inner-spin-button { |
|
||||||
-webkit-appearance: none; |
|
||||||
margin: 0; |
|
||||||
} |
|
||||||
|
|
||||||
.form { |
|
||||||
display: grid; |
|
||||||
gap: 24px; |
|
||||||
min-width: 600px; |
|
||||||
} |
|
||||||
|
|
||||||
.button { |
|
||||||
border: 0; |
|
||||||
border-radius: 0.5rem; |
|
||||||
height: 3rem; |
|
||||||
background-color: #e36464; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
align-items: center; |
|
||||||
place-items: center; |
|
||||||
justify-self: end; |
|
||||||
color: #363e5e; |
|
||||||
font-size: 1.3rem; |
|
||||||
font-weight: 500; |
|
||||||
padding: 0 1rem; |
|
||||||
cursor: pointer; |
|
||||||
} |
|
||||||
|
|
||||||
.button-plus { |
|
||||||
background-color: #4e5a88; |
|
||||||
color: white; |
|
||||||
} |
|
||||||
|
|
||||||
.info { |
|
||||||
width: 600px; |
|
||||||
font-size: 16px; |
|
||||||
text-align: right; |
|
||||||
margin-top: 40px; |
|
||||||
} |
|
||||||
|
|
||||||
.fields-wrapper { |
|
||||||
display: grid; |
|
||||||
grid-template-columns: 1fr 1fr; |
|
||||||
align-items: end; |
|
||||||
gap: 40px; |
|
||||||
} |
|
||||||
|
|
||||||
.dnd { |
|
||||||
width: 600px; |
|
||||||
} |
|
||||||
</style> |
|
@ -1,139 +0,0 @@ |
|||||||
<template> |
|
||||||
<DarkLayout> |
|
||||||
<form class="form"> |
|
||||||
<div class="input-wrapper"> |
|
||||||
<label for="collection-name">Collection name</label> |
|
||||||
<input v-model="name" class="input" id="collection-name" type="text" /> |
|
||||||
</div> |
|
||||||
<div class="input-wrapper"> |
|
||||||
<label for="first-domen-price">Domen price with 3 symbols</label> |
|
||||||
<input |
|
||||||
v-model="firstPrice" |
|
||||||
class="input" |
|
||||||
id="first-domen-price" |
|
||||||
type="number" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
<div class="input-wrapper"> |
|
||||||
<label for="second-domen-price">Domen price with 8 symbols</label> |
|
||||||
<input |
|
||||||
v-model="secondPrice" |
|
||||||
class="input" |
|
||||||
id="second-domen-price" |
|
||||||
type="number" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
<p class="info" v-show="firstPrice && secondPrice && name"> |
|
||||||
By pressing the Mint button, you create an NFT collection with the name |
|
||||||
"{{ name }}" and the price: {{ firstPrice }} ({{ |
|
||||||
secondPrice |
|
||||||
}}).<br />Any users also will be able to buy domains from this |
|
||||||
collection. |
|
||||||
</p> |
|
||||||
<button @click="mint()" class="button" type="button">Mint</button> |
|
||||||
</form> |
|
||||||
<template v-slot:header> |
|
||||||
<router-link to="/find"> |
|
||||||
<button class="b darkish back"> |
|
||||||
<img src="@/assets/icons/ton_left.svg" alt="TON" /> |
|
||||||
Back |
|
||||||
</button> |
|
||||||
</router-link> |
|
||||||
</template> |
|
||||||
</DarkLayout> |
|
||||||
</template> |
|
||||||
|
|
||||||
<script lang="ts" setup> |
|
||||||
import { ref } from "vue"; |
|
||||||
import DarkLayout from "../components/DarkLayout.vue"; |
|
||||||
import { useStore } from "vuex"; |
|
||||||
import { call_api } from "@/api"; |
|
||||||
|
|
||||||
const store = useStore(); |
|
||||||
|
|
||||||
const mint = async () => { |
|
||||||
const message = await call_api(`set-record/wallet/${store.getters.address}`); |
|
||||||
|
|
||||||
const d = new Date(); |
|
||||||
const validness = parseInt((d.getTime() / 1000).toFixed(0)) + 360000; |
|
||||||
const transaction = { |
|
||||||
validUntil: validness, |
|
||||||
messages: [ |
|
||||||
{ |
|
||||||
amount: (0.05 * 1000000000).toString(), |
|
||||||
address: store.getters.address, |
|
||||||
payload: message, |
|
||||||
}, |
|
||||||
], |
|
||||||
}; |
|
||||||
|
|
||||||
const result = await store.state.connector.sendTransaction(transaction); |
|
||||||
|
|
||||||
console.log(result); |
|
||||||
}; |
|
||||||
|
|
||||||
const name = ref(""); |
|
||||||
const firstPrice = ref(0); |
|
||||||
const secondPrice = ref(0); |
|
||||||
</script> |
|
||||||
|
|
||||||
<style> |
|
||||||
.input-wrapper { |
|
||||||
display: flex; |
|
||||||
flex-direction: column; |
|
||||||
align-items: start; |
|
||||||
} |
|
||||||
|
|
||||||
.input { |
|
||||||
display: block; |
|
||||||
width: 100%; |
|
||||||
min-height: 40px; |
|
||||||
border: 0; |
|
||||||
border-radius: 10px; |
|
||||||
padding: 12px 24px; |
|
||||||
background-color: #4e5a88; |
|
||||||
color: white; |
|
||||||
font-size: 24px; |
|
||||||
font-family: "Raleway", serif; |
|
||||||
} |
|
||||||
|
|
||||||
input::-webkit-outer-spin-button, |
|
||||||
input::-webkit-inner-spin-button { |
|
||||||
-webkit-appearance: none; |
|
||||||
margin: 0; |
|
||||||
} |
|
||||||
|
|
||||||
.form { |
|
||||||
display: grid; |
|
||||||
gap: 24px; |
|
||||||
min-width: 600px; |
|
||||||
} |
|
||||||
|
|
||||||
.button { |
|
||||||
border: 0; |
|
||||||
border-radius: 0.5rem; |
|
||||||
height: 3rem; |
|
||||||
background-color: #e36464; |
|
||||||
display: flex; |
|
||||||
justify-content: center; |
|
||||||
align-items: center; |
|
||||||
place-items: center; |
|
||||||
justify-self: end; |
|
||||||
min-width: 150px; |
|
||||||
color: #363e5e; |
|
||||||
font-size: 1.3rem; |
|
||||||
font-weight: 500; |
|
||||||
padding: 0 1rem; |
|
||||||
cursor: pointer; |
|
||||||
margin-left: 1rem; |
|
||||||
margin-top: 1rem; |
|
||||||
margin-bottom: 1rem; |
|
||||||
} |
|
||||||
|
|
||||||
.info { |
|
||||||
width: 600px; |
|
||||||
font-size: 16px; |
|
||||||
text-align: right; |
|
||||||
margin-top: 40px; |
|
||||||
} |
|
||||||
</style> |
|
@ -1,18 +0,0 @@ |
|||||||
<template> |
|
||||||
<DarkLayout> |
|
||||||
<DomainTable /> |
|
||||||
<template v-slot:header> |
|
||||||
<router-link to="/find"> |
|
||||||
<button class="b darkish back"> |
|
||||||
<img src="@/assets/icons/ton_left.svg" alt="TON" /> |
|
||||||
Back |
|
||||||
</button> |
|
||||||
</router-link> |
|
||||||
</template> |
|
||||||
</DarkLayout> |
|
||||||
</template> |
|
||||||
|
|
||||||
<script setup> |
|
||||||
import DarkLayout from "../components/DarkLayout.vue"; |
|
||||||
import DomainTable from "@/components/DomainTable.vue"; |
|
||||||
</script> |
|
@ -1,13 +1,14 @@ |
|||||||
import { fileURLToPath, URL } from "node:url"; |
import { fileURLToPath, URL } from 'node:url' |
||||||
import { defineConfig } from "vite"; |
|
||||||
import vue from "@vitejs/plugin-vue"; |
import { defineConfig } from 'vite' |
||||||
|
import vue from '@vitejs/plugin-vue' |
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({ |
export default defineConfig({ |
||||||
plugins: [vue()], |
plugins: [vue()], |
||||||
resolve: { |
resolve: { |
||||||
alias: { |
alias: { |
||||||
"@": fileURLToPath(new URL("./src", import.meta.url)), |
'@': fileURLToPath(new URL('./src', import.meta.url)) |
||||||
}, |
} |
||||||
}, |
} |
||||||
}); |
}) |
||||||
|
Loading…
Reference in new issue