Compare commits
20 Commits
Author | SHA1 | Date |
---|---|---|
Lev | 57a4be9f81 | 2 months ago |
Aleksandr Bautin | 2b06910a6f | 11 months ago |
Aleksandr Bautin | 2fa6006913 | 11 months ago |
Aleksandr Bautin | bb8500204e | 11 months ago |
Aleksandr Bautin | 0a69c37140 | 12 months ago |
Aleksandr Bautin | f9cac6b4de | 1 year ago |
Aleksandr Bautin | 3b97e20146 | 1 year ago |
Aleksandr Bautin | b1e3658eb7 | 1 year ago |
Aleksandr Bautin | 59e8a2b7a2 | 1 year ago |
Aleksandr Bautin | 34b767d631 | 1 year ago |
Aleksandr Bautin | 51730dc347 | 1 year ago |
Lev | 52ad71712e | 1 year ago |
Lev | f97fef7164 | 1 year ago |
Lev | e4ce4e189d | 1 year ago |
Lev | 3b28d9a1d5 | 1 year ago |
Aleksandr Bautin | 7a5e80722b | 1 year ago |
Aleksandr Bautin | 8279679046 | 1 year ago |
Aleksandr Bautin | 72a7d725f0 | 1 year ago |
Aleksandr Bautin | a8a105fc03 | 1 year ago |
Lev | 60b5b4e657 | 1 year ago |
39 changed files with 2554 additions and 818 deletions
@ -1,5 +1,5 @@
|
||||
{ |
||||
"url": "https://agorata.io/", |
||||
"url": "https://tonski-an7.pages.dev", |
||||
"name": "Agorata", |
||||
"iconUrl": "https://front.agorata.io/favicon.png" |
||||
} |
||||
|
@ -1,30 +1,71 @@
|
||||
import axios from 'axios' |
||||
import axios from "axios"; |
||||
|
||||
declare var process : { |
||||
declare var process: { |
||||
env: { |
||||
NODE_ENV: string |
||||
} |
||||
} |
||||
NODE_ENV: string; |
||||
}; |
||||
}; |
||||
|
||||
export class Api { |
||||
public readonly api_url: string; |
||||
public agorata_adnl: string = "ed4f2afebb5e49dda9684a474c5771141be1f7d85a2fa39f1823844dd476c52d"; |
||||
public readonly api_url: string; |
||||
public readonly ton_api_url: string; |
||||
public readonly tonscan_url: string; |
||||
public agorata_adnl: string = |
||||
"ed4f2afebb5e49dda9684a474c5771141be1f7d85a2fa39f1823844dd476c52d"; |
||||
public readonly tonviewer_url: string; |
||||
|
||||
constructor() { |
||||
if (process.env.NODE_ENV === 'development') { |
||||
this.api_url = 'http://localhost:5170/'; |
||||
} else { |
||||
this.api_url = 'https://api.agorata.io/'; |
||||
} |
||||
constructor() { |
||||
if (process.env.NODE_ENV === "development") { |
||||
this.api_url = "http://localhost:5170/"; |
||||
this.ton_api_url = "https://testnet.tonapi.io/v2/"; |
||||
this.tonscan_url = "https://testnet.tonscan.org/"; |
||||
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 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) { |
||||
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,197 +1,196 @@
|
||||
@import './base.css'; |
||||
@import "./base.css"; |
||||
|
||||
@tailwind base; |
||||
@tailwind components; |
||||
@tailwind utilities; |
||||
|
||||
#app { |
||||
margin: 0 auto; |
||||
padding: 0; |
||||
min-width: 100vw; |
||||
min-height: 100vh; |
||||
margin: 0 auto; |
||||
padding: 0; |
||||
min-width: 100vw; |
||||
min-height: 100vh; |
||||
} |
||||
|
||||
a, |
||||
.green { |
||||
text-decoration: none; |
||||
color: hsl(201, 100%, 37%); |
||||
transition: 0.4s; |
||||
text-decoration: none; |
||||
color: hsl(201, 100%, 37%); |
||||
transition: 0.4s; |
||||
} |
||||
|
||||
@media (min-width: 1024px) { |
||||
body { |
||||
display: flex; |
||||
place-items: center; |
||||
} |
||||
body { |
||||
display: flex; |
||||
place-items: center; |
||||
} |
||||
|
||||
#app { |
||||
display: grid; |
||||
grid-template-columns: 1fr 1fr; |
||||
padding: 0; |
||||
} |
||||
#app { |
||||
display: grid; |
||||
grid-template-columns: 1fr 1fr; |
||||
padding: 0; |
||||
} |
||||
} |
||||
|
||||
.b { |
||||
border: 2px solid transparent; |
||||
border-radius: 5px; |
||||
padding: 16px 26px; |
||||
text-align: center; |
||||
text-decoration: none; |
||||
display: inline-block; |
||||
font-size: 1.55rem; |
||||
margin: 4px 2px; |
||||
cursor: pointer; |
||||
font-weight: bold; |
||||
border: 2px solid transparent; |
||||
border-radius: 5px; |
||||
padding: 16px 26px; |
||||
text-align: center; |
||||
text-decoration: none; |
||||
display: inline-block; |
||||
font-size: 1.55rem; |
||||
margin: 4px 2px; |
||||
cursor: pointer; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
@media (max-width: 800px) { |
||||
.b { |
||||
font-size: 1.4rem; |
||||
} |
||||
.b { |
||||
font-size: 1.4rem; |
||||
} |
||||
} |
||||
|
||||
.b.white { |
||||
background-color: white; |
||||
color: #282e46; |
||||
background-color: white; |
||||
color: #282e46; |
||||
} |
||||
|
||||
.b.white:hover { |
||||
background-color: #282e46; |
||||
color: white; |
||||
border: 2px solid white; |
||||
background-color: #282e46; |
||||
color: white; |
||||
border: 2px solid white; |
||||
} |
||||
|
||||
.b.blue { |
||||
background-color: #0088cc; |
||||
color: white; |
||||
border-radius: 1rem; |
||||
background-color: #0088cc; |
||||
color: white; |
||||
border-radius: 1rem; |
||||
} |
||||
|
||||
.b > img:first-child { |
||||
max-height: 1.4rem; |
||||
margin-right: 0.7rem; |
||||
max-height: 1.4rem; |
||||
margin-right: 0.7rem; |
||||
} |
||||
|
||||
.b > img:not(:first-child) { |
||||
max-height: 1.4rem; |
||||
margin-left: 2rem; |
||||
max-height: 1.4rem; |
||||
margin-left: 2rem; |
||||
} |
||||
|
||||
.wide.b { |
||||
min-width: 16rem; |
||||
margin: 0.5rem; |
||||
min-width: 16rem; |
||||
margin: 0.5rem; |
||||
} |
||||
|
||||
/* A #edeef1 box with rounded corners with black content color and content centered vertically and horizontally */ |
||||
.rbox { |
||||
background-color: #edeef1; |
||||
border-radius: 2rem; |
||||
padding: 2.5rem 32px; |
||||
text-align: center; |
||||
display: flex; |
||||
align-items: center; |
||||
place-content: center; |
||||
justify-content: center; |
||||
font-size: 1.6rem; |
||||
font-weight: bold; |
||||
color: #282e46; |
||||
min-width: 16rem; |
||||
margin: 0.5rem 3rem; |
||||
background-color: #edeef1; |
||||
border-radius: 2rem; |
||||
padding: 2.5rem 32px; |
||||
text-align: center; |
||||
display: flex; |
||||
align-items: center; |
||||
place-content: center; |
||||
justify-content: center; |
||||
font-size: 1.6rem; |
||||
font-weight: bold; |
||||
color: #282e46; |
||||
min-width: 16rem; |
||||
margin: 0.5rem 3rem; |
||||
} |
||||
|
||||
/* small margin on mobile */ |
||||
@media (max-width: 800px) { |
||||
.rbox { |
||||
margin: 0.5rem 0.5rem; |
||||
} |
||||
.rbox { |
||||
margin: 0.5rem 0.5rem; |
||||
} |
||||
} |
||||
|
||||
.rbox > p:not(:first-child) { |
||||
margin-top: 1rem; |
||||
margin-top: 1rem; |
||||
} |
||||
|
||||
.center { |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
place-items: center; |
||||
flex-direction: column; |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: center; |
||||
place-items: center; |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.b.darkish { |
||||
background-color: #4e5a88; |
||||
color: white; |
||||
border-radius: 0.5rem; |
||||
font-size: 1rem; |
||||
background-color: #4e5a88; |
||||
color: white; |
||||
border-radius: 0.5rem; |
||||
font-size: 1rem; |
||||
} |
||||
|
||||
.mono { |
||||
font-family: 'Inconsolata', monospace; |
||||
font-family: "Inconsolata", monospace; |
||||
} |
||||
|
||||
:root { |
||||
--popper-theme-background-color: #fff; |
||||
--popper-theme-background-color-hover: #fff; |
||||
--popper-theme-text-color: black; |
||||
--popper-theme-border-width: 0px; |
||||
--popper-theme-border-style: solid; |
||||
--popper-theme-border-radius: 6px; |
||||
--popper-theme-padding: 4px; |
||||
--popper-theme-box-shadow: 0 6px 30px -6px rgba(0, 0, 0, 0.25); |
||||
--popper-theme-background-color: #fff; |
||||
--popper-theme-background-color-hover: #fff; |
||||
--popper-theme-text-color: black; |
||||
--popper-theme-border-width: 0px; |
||||
--popper-theme-border-style: solid; |
||||
--popper-theme-border-radius: 6px; |
||||
--popper-theme-padding: 4px; |
||||
--popper-theme-box-shadow: 0 6px 30px -6px rgba(0, 0, 0, 0.25); |
||||
} |
||||
|
||||
.popper { |
||||
font-size: 0.8rem; |
||||
font-family: 'Inconsolata', monospace; |
||||
font-size: 0.8rem; |
||||
font-family: "Inconsolata", monospace; |
||||
} |
||||
|
||||
.mobile-scale { |
||||
scale: 100%; |
||||
scale: 100%; |
||||
} |
||||
|
||||
@media (max-width: 800px) { |
||||
.mobile-scale { |
||||
scale: 80%; |
||||
} |
||||
.mobile-scale { |
||||
scale: 80%; |
||||
} |
||||
} |
||||
|
||||
.get_b { |
||||
background-color: #e36464; |
||||
color: #363e5e; |
||||
border-radius: 0.5rem; |
||||
padding: 0.2rem 0.8rem; |
||||
margin-left: 0.9rem; |
||||
cursor: pointer; |
||||
background-color: #e36464; |
||||
color: #363e5e; |
||||
border-radius: 0.5rem; |
||||
padding: 0.2rem 0.8rem; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
@media only screen and (max-width: 800px) { |
||||
.get_b { |
||||
margin-left: 0.1rem; |
||||
padding-left: 0.4rem; |
||||
padding-right: 0.4rem; |
||||
} |
||||
.get_b { |
||||
margin-left: 0.1rem; |
||||
padding-left: 0.4rem; |
||||
padding-right: 0.4rem; |
||||
} |
||||
} |
||||
|
||||
.flex { |
||||
display: flex; |
||||
display: flex; |
||||
} |
||||
|
||||
.b.back { |
||||
font-family: 'Inconsolata', monospace; |
||||
font-size: 1.5rem; |
||||
padding: 0.8rem; |
||||
font-family: "Inconsolata", monospace; |
||||
font-size: 1.5rem; |
||||
padding: 0.8rem; |
||||
} |
||||
|
||||
.b.back > img { |
||||
max-height: 1rem; |
||||
margin-right: 0.4rem; |
||||
max-height: 1rem; |
||||
margin-right: 0.4rem; |
||||
} |
||||
|
||||
.material-icons.language { |
||||
position:relative; |
||||
display:inline-block; |
||||
position: relative; |
||||
display: inline-block; |
||||
} |
||||
|
||||
.material-icons.language:after { |
||||
content: "language"; |
||||
content: "language"; |
||||
} |
||||
|
@ -0,0 +1,98 @@
|
||||
<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> |
@ -0,0 +1,198 @@
|
||||
<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> |
@ -0,0 +1,56 @@
|
||||
<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> |
@ -0,0 +1,294 @@
|
||||
<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> |
@ -0,0 +1,78 @@
|
||||
<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,100 +1,112 @@
|
||||
import {createApp} from 'vue' |
||||
import App from './App.vue' |
||||
import router from './router' |
||||
import {createStore} from 'vuex' |
||||
import TonConnect from '@tonconnect/sdk'; |
||||
import {isWalletInfoInjected} from '@tonconnect/sdk'; |
||||
import type {WalletInfo, WalletInfoInjected, WalletInfoRemote} from '@tonconnect/sdk'; |
||||
import './assets/main.css' |
||||
import { createApp } from "vue"; |
||||
import App from "./App.vue"; |
||||
import router from "./router"; |
||||
import { createStore } from "vuex"; |
||||
import TonConnect from "@tonconnect/sdk"; |
||||
import { isWalletInfoInjected } from "@tonconnect/sdk"; |
||||
import type { |
||||
WalletInfo, |
||||
WalletInfoInjected, |
||||
WalletInfoRemote, |
||||
} from "@tonconnect/sdk"; |
||||
import "./assets/main.css"; |
||||
|
||||
const app = createApp(App) |
||||
const app = createApp(App); |
||||
|
||||
class State { |
||||
connector: TonConnect; |
||||
walletList: WalletInfo[] = []; |
||||
initialization: Promise<void>; |
||||
connector: TonConnect; |
||||
walletList: WalletInfo[] = []; |
||||
initialization: Promise<void>; |
||||
|
||||
constructor() { |
||||
this.connector = new TonConnect({manifestUrl: 'https://front.agorata.io/tonconnect-manifest.json'}); |
||||
this.initialization = this.initialize(); |
||||
} |
||||
constructor() { |
||||
this.connector = new TonConnect({ |
||||
manifestUrl: "https://agorata.io/tonconnect-manifest.json", |
||||
}); |
||||
this.initialization = this.initialize(); |
||||
} |
||||
|
||||
async initialize() { |
||||
await this.connector.restoreConnection(); |
||||
this.walletList = await this.connector.getWallets(); |
||||
} |
||||
async initialize() { |
||||
await this.connector.restoreConnection(); |
||||
this.walletList = await this.connector.getWallets(); |
||||
} |
||||
} |
||||
|
||||
const store = createStore({ |
||||
state() { |
||||
return new State() |
||||
state() { |
||||
return new State(); |
||||
}, |
||||
mutations: { |
||||
set_connector(state, connector) { |
||||
state.connector = connector; |
||||
}, |
||||
mutations: { |
||||
set_connector(state, connector) { |
||||
state.connector = connector |
||||
} |
||||
}, |
||||
getters: { |
||||
is_connected(state) { |
||||
return state.connector.connected; |
||||
}, |
||||
getters: { |
||||
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 ''; |
||||
} |
||||
} |
||||
address(state) { |
||||
if ( |
||||
state.connector.account !== null && |
||||
state.connector.account.address !== undefined |
||||
) { |
||||
return state.connector.account.address; |
||||
} else { |
||||
return ""; |
||||
} |
||||
}, |
||||
connector(state) { |
||||
return state.connector; |
||||
}, |
||||
actions: { |
||||
async connect_embedded({state}) { |
||||
const walletsList = await TonConnect.getWallets(); |
||||
let connector = state.connector; |
||||
const embeddedWallet = walletsList.find( |
||||
wallet => isWalletInfoInjected(wallet) && wallet.embedded |
||||
) as WalletInfoInjected; |
||||
console.log(walletsList, embeddedWallet); |
||||
}, |
||||
actions: { |
||||
async connect_embedded({ state }) { |
||||
const walletsList = await TonConnect.getWallets(); |
||||
let connector = state.connector; |
||||
const embeddedWallet = walletsList.find( |
||||
(wallet) => isWalletInfoInjected(wallet) && wallet.embedded |
||||
) as WalletInfoInjected; |
||||
console.log(walletsList, embeddedWallet); |
||||
|
||||
if (embeddedWallet) { |
||||
connector.connect({jsBridgeKey: embeddedWallet.jsBridgeKey}); |
||||
} |
||||
}, |
||||
/* 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> { |
||||
await state.initialization; |
||||
await this.dispatch('connect_embedded'); |
||||
if (state.connector.connected) { |
||||
return null; |
||||
} |
||||
let walletList = this.state.walletList as WalletInfo[]; |
||||
if (walletList.length === 0) { |
||||
return null; |
||||
} |
||||
/* iterate through wallets and do try-catch */ |
||||
for (let wallet of walletList) { |
||||
try { |
||||
let wallet_r = wallet as WalletInfoRemote; |
||||
let wallet_desc = { |
||||
bridgeUrl: wallet_r.bridgeUrl, |
||||
universalLink: wallet_r.universalLink |
||||
} |
||||
let res = await state.connector.connect(wallet_desc); |
||||
if (typeof res === 'string') { |
||||
return res; |
||||
} |
||||
} catch (e) { |
||||
console.log(wallet, e) |
||||
} |
||||
} |
||||
return null; |
||||
}, |
||||
async disconnect({state}) { |
||||
await state.connector.disconnect(); |
||||
if (embeddedWallet) { |
||||
connector.connect({ jsBridgeKey: embeddedWallet.jsBridgeKey }); |
||||
} |
||||
}, |
||||
/* 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> { |
||||
await state.initialization; |
||||
await this.dispatch("connect_embedded"); |
||||
if (state.connector.connected) { |
||||
return null; |
||||
} |
||||
let walletList = this.state.walletList as WalletInfo[]; |
||||
if (walletList.length === 0) { |
||||
return null; |
||||
} |
||||
/* iterate through wallets and do try-catch */ |
||||
for (let wallet of walletList) { |
||||
try { |
||||
let wallet_r = wallet as WalletInfoRemote; |
||||
let wallet_desc = { |
||||
bridgeUrl: wallet_r.bridgeUrl, |
||||
universalLink: wallet_r.universalLink, |
||||
}; |
||||
let res = await state.connector.connect(wallet_desc); |
||||
if (typeof res === "string") { |
||||
return res; |
||||
} |
||||
} catch (e) { |
||||
console.log(wallet, e); |
||||
} |
||||
} |
||||
}) |
||||
} |
||||
return null; |
||||
}, |
||||
async disconnect({ state }) { |
||||
await state.connector.disconnect(); |
||||
}, |
||||
}, |
||||
}); |
||||
|
||||
app.use(router) |
||||
app.use(store) |
||||
app.use(router); |
||||
app.use(store); |
||||
|
||||
app.mount('#app') |
||||
app.mount("#app"); |
||||
|
@ -0,0 +1,3 @@
|
||||
export const myDomains = "my-domains"; |
||||
export const mintCollection = "mint-collection"; |
||||
export const addTemplate = "add-template"; |
@ -0,0 +1,24 @@
|
||||
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 }[]; |
||||
}; |
@ -0,0 +1,134 @@
|
||||
<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> |
@ -0,0 +1,139 @@
|
||||
<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> |
@ -0,0 +1,18 @@
|
||||
<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,14 +1,13 @@
|
||||
import { fileURLToPath, URL } from 'node:url' |
||||
|
||||
import { defineConfig } from 'vite' |
||||
import vue from '@vitejs/plugin-vue' |
||||
import { fileURLToPath, URL } from "node:url"; |
||||
import { defineConfig } from "vite"; |
||||
import vue from "@vitejs/plugin-vue"; |
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({ |
||||
plugins: [vue()], |
||||
resolve: { |
||||
alias: { |
||||
'@': fileURLToPath(new URL('./src', import.meta.url)) |
||||
} |
||||
} |
||||
}) |
||||
"@": fileURLToPath(new URL("./src", import.meta.url)), |
||||
}, |
||||
}, |
||||
}); |
||||
|
Loading…
Reference in new issue