Browse Source

added pages: MyDomains, MintCollection. Added configuring by templates

master
Aleksandr Bautin 1 year ago
parent
commit
a8a105fc03
No known key found for this signature in database
GPG Key ID: 9B3364A12DFE9211
  1. 364
      package-lock.json
  2. 1
      package.json
  3. 62
      src/api.ts
  4. 3
      src/assets/icons/globe.svg
  5. 3
      src/assets/icons/link.svg
  6. 154
      src/components/DomainTable.vue
  7. 31
      src/components/GetDomainBtn.vue
  8. 78
      src/components/Header.vue
  9. 159
      src/components/SiteSettings.vue
  10. 55
      src/components/Switcher.vue
  11. 287
      src/components/TemplatesList.vue
  12. 10
      src/components/TonButton.vue
  13. 63
      src/components/Tooltip.vue
  14. 21
      src/components/WhiteLayout.vue
  15. 107
      src/components/ZonePricing.vue
  16. 147
      src/router/index.ts
  17. 2
      src/router/routes.ts
  18. 24
      src/types.ts
  19. 62
      src/views/Checkout.vue
  20. 235
      src/views/Explore.vue
  21. 42
      src/views/Get.vue
  22. 42
      src/views/IHave.vue
  23. 35
      src/views/IKnow.vue
  24. 17
      src/views/Landing.vue
  25. 114
      src/views/MintCollection.vue
  26. 18
      src/views/MyDomains.vue
  27. 26
      src/views/TonDns.vue
  28. 45
      src/views/TonWeb.vue
  29. 18
      vite.config.ts

364
package-lock.json generated

@ -14,6 +14,7 @@
"bulma": "^0.9.4", "bulma": "^0.9.4",
"qr-code-styling": "^1.6.0-rc.1", "qr-code-styling": "^1.6.0-rc.1",
"sass": "^1.56.2", "sass": "^1.56.2",
"semver": "^7.3.8",
"tonweb": "^0.0.59", "tonweb": "^0.0.59",
"vue": "^3.2.45", "vue": "^3.2.45",
"vue-contenteditable": "^4.1.0", "vue-contenteditable": "^4.1.0",
@ -33,6 +34,7 @@
"tailwindcss": "^3.2.4", "tailwindcss": "^3.2.4",
"typescript": "~4.7.4", "typescript": "~4.7.4",
"vite": "^4.0.0", "vite": "^4.0.0",
"vite-svg-loader": "^4.0.0",
"vue-tsc": "^1.0.12" "vue-tsc": "^1.0.12"
} }
}, },
@ -5632,6 +5634,15 @@
"tweetnacl": "^1.0.3" "tweetnacl": "^1.0.3"
} }
}, },
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
"integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
"dev": true,
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/@types/istanbul-lib-coverage": { "node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
@ -6705,6 +6716,12 @@
"optional": true, "optional": true,
"peer": true "peer": true
}, },
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
"dev": true
},
"node_modules/bplist-creator": { "node_modules/bplist-creator": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
@ -7434,7 +7451,7 @@
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"optional": true, "devOptional": true,
"engines": { "engines": {
"node": ">= 10" "node": ">= 10"
} }
@ -7680,6 +7697,47 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/css-select": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
"dev": true,
"dependencies": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
"domhandler": "^5.0.2",
"domutils": "^3.0.1",
"nth-check": "^2.0.1"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/css-tree": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
"dev": true,
"dependencies": {
"mdn-data": "2.0.30",
"source-map-js": "^1.0.1"
},
"engines": {
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
}
},
"node_modules/css-what": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
"dev": true,
"engines": {
"node": ">= 6"
},
"funding": {
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/cssesc": { "node_modules/cssesc": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@ -7692,6 +7750,39 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/csso": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz",
"integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",
"dev": true,
"dependencies": {
"css-tree": "~2.2.0"
},
"engines": {
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/csso/node_modules/css-tree": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
"integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",
"dev": true,
"dependencies": {
"mdn-data": "2.0.28",
"source-map-js": "^1.0.1"
},
"engines": {
"node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/csso/node_modules/mdn-data": {
"version": "2.0.28",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz",
"integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
"dev": true
},
"node_modules/dag-map": { "node_modules/dag-map": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz", "resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz",
@ -7974,6 +8065,61 @@
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
"dev": true "dev": true
}, },
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"dev": true,
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
]
},
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"dev": true,
"dependencies": {
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/domutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"dev": true,
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -8014,6 +8160,18 @@
"once": "^1.4.0" "once": "^1.4.0"
} }
}, },
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"dev": true,
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/env-editor": { "node_modules/env-editor": {
"version": "0.4.2", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz", "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz",
@ -11361,6 +11519,12 @@
"optional": true, "optional": true,
"peer": true "peer": true
}, },
"node_modules/mdn-data": {
"version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
"dev": true
},
"node_modules/media-typer": { "node_modules/media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -12535,6 +12699,18 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"dev": true,
"dependencies": {
"boolbase": "^1.0.0"
},
"funding": {
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/nullthrows": { "node_modules/nullthrows": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
@ -15413,6 +15589,30 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/svgo": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz",
"integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==",
"dev": true,
"dependencies": {
"@trysound/sax": "0.2.0",
"commander": "^7.2.0",
"css-select": "^5.1.0",
"css-tree": "^2.2.1",
"csso": "^5.0.5",
"picocolors": "^1.0.0"
},
"bin": {
"svgo": "bin/svgo"
},
"engines": {
"node": ">=14.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/svgo"
}
},
"node_modules/tailwindcss": { "node_modules/tailwindcss": {
"version": "3.2.4", "version": "3.2.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz",
@ -16332,6 +16532,16 @@
} }
} }
}, },
"node_modules/vite-svg-loader": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/vite-svg-loader/-/vite-svg-loader-4.0.0.tgz",
"integrity": "sha512-0MMf1yzzSYlV4MGePsLVAOqXsbF5IVxbn4EEzqRnWxTQl8BJg/cfwIzfQNmNQxZp5XXwd4kyRKF1LytuHZTnqA==",
"dev": true,
"dependencies": {
"@vue/compiler-sfc": "^3.2.20",
"svgo": "^3.0.2"
}
},
"node_modules/vite/node_modules/rollup": { "node_modules/vite/node_modules/rollup": {
"version": "3.7.3", "version": "3.7.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.3.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.3.tgz",
@ -20995,6 +21205,12 @@
"tweetnacl": "^1.0.3" "tweetnacl": "^1.0.3"
} }
}, },
"@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
"integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
"dev": true
},
"@types/istanbul-lib-coverage": { "@types/istanbul-lib-coverage": {
"version": "2.0.4", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
@ -21904,6 +22120,12 @@
} }
} }
}, },
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
"dev": true
},
"bplist-creator": { "bplist-creator": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
@ -22453,7 +22675,7 @@
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"optional": true "devOptional": true
}, },
"commondir": { "commondir": {
"version": "1.0.1", "version": "1.0.1",
@ -22664,12 +22886,68 @@
"optional": true, "optional": true,
"peer": true "peer": true
}, },
"css-select": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
"integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==",
"dev": true,
"requires": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
"domhandler": "^5.0.2",
"domutils": "^3.0.1",
"nth-check": "^2.0.1"
}
},
"css-tree": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
"dev": true,
"requires": {
"mdn-data": "2.0.30",
"source-map-js": "^1.0.1"
}
},
"css-what": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
"integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
"dev": true
},
"cssesc": { "cssesc": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true "dev": true
}, },
"csso": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz",
"integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",
"dev": true,
"requires": {
"css-tree": "~2.2.0"
},
"dependencies": {
"css-tree": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
"integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",
"dev": true,
"requires": {
"mdn-data": "2.0.28",
"source-map-js": "^1.0.1"
}
},
"mdn-data": {
"version": "2.0.28",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz",
"integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
"dev": true
}
}
},
"dag-map": { "dag-map": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz", "resolved": "https://registry.npmjs.org/dag-map/-/dag-map-1.0.2.tgz",
@ -22880,6 +23158,43 @@
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
"dev": true "dev": true
}, },
"dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"dev": true,
"requires": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
}
},
"domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"dev": true
},
"domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"dev": true,
"requires": {
"domelementtype": "^2.3.0"
}
},
"domutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"dev": true,
"requires": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
}
},
"ee-first": { "ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -22917,6 +23232,12 @@
"once": "^1.4.0" "once": "^1.4.0"
} }
}, },
"entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"dev": true
},
"env-editor": { "env-editor": {
"version": "0.4.2", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz", "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz",
@ -25490,6 +25811,12 @@
"optional": true, "optional": true,
"peer": true "peer": true
}, },
"mdn-data": {
"version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
"dev": true
},
"media-typer": { "media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -26467,6 +26794,15 @@
"path-key": "^2.0.0" "path-key": "^2.0.0"
} }
}, },
"nth-check": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"dev": true,
"requires": {
"boolbase": "^1.0.0"
}
},
"nullthrows": { "nullthrows": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
@ -28705,6 +29041,20 @@
"version": "1.0.0", "version": "1.0.0",
"devOptional": true "devOptional": true
}, },
"svgo": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz",
"integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==",
"dev": true,
"requires": {
"@trysound/sax": "0.2.0",
"commander": "^7.2.0",
"css-select": "^5.1.0",
"css-tree": "^2.2.1",
"csso": "^5.0.5",
"picocolors": "^1.0.0"
}
},
"tailwindcss": { "tailwindcss": {
"version": "3.2.4", "version": "3.2.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz",
@ -29407,6 +29757,16 @@
} }
} }
}, },
"vite-svg-loader": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/vite-svg-loader/-/vite-svg-loader-4.0.0.tgz",
"integrity": "sha512-0MMf1yzzSYlV4MGePsLVAOqXsbF5IVxbn4EEzqRnWxTQl8BJg/cfwIzfQNmNQxZp5XXwd4kyRKF1LytuHZTnqA==",
"dev": true,
"requires": {
"@vue/compiler-sfc": "^3.2.20",
"svgo": "^3.0.2"
}
},
"vlq": { "vlq": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz",

1
package.json

@ -36,6 +36,7 @@
"tailwindcss": "^3.2.4", "tailwindcss": "^3.2.4",
"typescript": "~4.7.4", "typescript": "~4.7.4",
"vite": "^4.0.0", "vite": "^4.0.0",
"vite-svg-loader": "^4.0.0",
"vue-tsc": "^1.0.12" "vue-tsc": "^1.0.12"
} }
} }

62
src/api.ts

@ -1,30 +1,62 @@
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 agorata_adnl: string = "ed4f2afebb5e49dda9684a474c5771141be1f7d85a2fa39f1823844dd476c52d"; public agorata_adnl: string =
"ed4f2afebb5e49dda9684a474c5771141be1f7d85a2fa39f1823844dd476c52d";
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/";
} else { } else {
this.api_url = 'https://api.agorata.io/'; this.api_url = "https://api.agorata.io/";
}
} }
}
} }
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",
},
])
);
} }

3
src/assets/icons/globe.svg

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 12C21 16.9706 16.9706 21 12 21M21 12C21 7.02944 16.9706 3 12 3M21 12H3M12 21C7.02944 21 3 16.9706 3 12M12 21C13.6569 21 15 16.9706 15 12C15 7.02944 13.6569 3 12 3M12 21C10.3431 21 9 16.9706 9 12C9 7.02944 10.3431 3 12 3M3 12C3 7.02944 7.02944 3 12 3" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 455 B

3
src/assets/icons/link.svg

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13 2C12.4477 2 12 1.55228 12 1C12 0.447715 12.4477 0 13 0H19C19.5523 0 20 0.447715 20 1V7C20 7.55228 19.5523 8 19 8C18.4477 8 18 7.55228 18 7V3.41421L8.70711 12.7071C8.31658 13.0976 7.68342 13.0976 7.29289 12.7071C6.90237 12.3166 6.90237 11.6834 7.29289 11.2929L16.5858 2H13ZM3 5C2.73478 5 2.48043 5.10536 2.29289 5.29289C2.10536 5.48043 2 5.73478 2 6V17C2 17.2652 2.10536 17.5196 2.29289 17.7071C2.48043 17.8946 2.73478 18 3 18H14C14.2652 18 14.5196 17.8946 14.7071 17.7071C14.8946 17.5196 15 17.2652 15 17V11C15 10.4477 15.4477 10 16 10C16.5523 10 17 10.4477 17 11V17C17 17.7957 16.6839 18.5587 16.1213 19.1213C15.5587 19.6839 14.7957 20 14 20H3C2.20435 20 1.44129 19.6839 0.87868 19.1213C0.31607 18.5587 0 17.7957 0 17V6C0 5.20435 0.31607 4.44129 0.87868 3.87868C1.44129 3.31607 2.20435 3 3 3H9C9.55229 3 10 3.44772 10 4C10 4.55228 9.55229 5 9 5H3Z" fill="currentColor" />
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

154
src/components/DomainTable.vue

@ -0,0 +1,154 @@
<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="`https://tonscan.org/address/${item?.address}`"
>
<Link cursor="pointer" />
</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">
<Globe style="display: flex" cursor="pointer" />
</a>
</Tooltip>
</td>
<td>
<button @click="onManageClick(item)" class="button">Manage</button>
</td>
</tr>
</tbody>
</table>
<!-- <div v-if="items.length" ref="target"></div> -->
</template>
<script setup lang="ts">
import type { CollectionItem } from "@/types";
import axios from "axios";
import { computed, onMounted, ref, watch } from "vue";
import Link from "@/assets/icons/link.svg";
import Tooltip from "./Tooltip.vue";
import Globe from "@/assets/icons/globe.svg";
import { useRouter } from "vue-router";
import { get_zones } from "@/result";
import type { Zone } from "@/zone";
import { convertAddress } from "@/utils";
import { useStore } from "vuex";
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 address = computed(() =>
store.getters.address ? convertAddress(store.getters.address) : ""
);
onMounted(async () => {
const zones = (await get_zones()) as Zone[];
zonesAddresses.value = zones.map(({ address }) => address?.toLowerCase());
if (address.value) {
const { data } = await axios.get<{ nft_items: CollectionItem[] }>(
`https://testnet.tonapi.io/v2/accounts/${address.value}/nfts`
);
items.value = data.nft_items
.map((item) => ({
...item,
formattedCollectionAddress: item.collection?.address
? convertAddress(item.collection?.address).toLowerCase()
: "",
}))
.filter(({ formattedCollectionAddress }) =>
zonesAddresses.value.includes(formattedCollectionAddress)
);
}
});
</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>

31
src/components/GetDomainBtn.vue

@ -1,14 +1,16 @@
<template> <template>
<div class="get-domain"> <div class="get-domain">
Get<br/> Get<br />
<p class="domain">{{ domain }}</p> <p class="domain">{{ domain }}</p>
for<br/> for<br />
<span class="price"> <span class="price">
{{ price }} {{ price }}
<img src="@/assets/icons/ton_bottom.svg" class="ton_img" alt="TON"/> <img src="../assets/icons/ton_bottom.svg" class="ton_img" alt="TON" />
</span> </span>
<template v-if="collection_required !== undefined && collection_required !== null"> <template
<br/> v-if="collection_required !== undefined && collection_required !== null"
>
<br />
<div class="collection_required"> <div class="collection_required">
for owners of for owners of
<div class="collection">{{ collection_required.name }}</div> <div class="collection">{{ collection_required.name }}</div>
@ -23,18 +25,18 @@ export default {
props: { props: {
domain: { domain: {
type: String, type: String,
required: true required: true,
}, },
price: { price: {
type: Number, type: Number,
required: true required: true,
}, },
collection_required: { collection_required: {
// type: Collection | null, // type: Collection | null,
default: null default: null,
} },
} },
} };
</script> </script>
<style scoped> <style scoped>
@ -54,12 +56,11 @@ export default {
width: 90vw; width: 90vw;
/* allow multiple rows with 0.5 spacing */ /* allow multiple rows with 0.5 spacing */
flex-wrap: wrap; flex-wrap: wrap;
} }
} }
.domain { .domain {
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
font-weight: bold; font-weight: bold;
font-size: 2.5rem; font-size: 2.5rem;
} }
@ -73,7 +74,7 @@ export default {
.price { .price {
font-size: 3rem; font-size: 3rem;
font-weight: bold; font-weight: bold;
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
} }
.price > img { .price > img {
@ -87,4 +88,4 @@ export default {
background-color: white; background-color: white;
color: #0088cc; color: #0088cc;
} }
</style> </style>

78
src/components/Header.vue

@ -1,7 +1,9 @@
<template> <template>
<header> <header>
<div class="wrapper flex" style="width: 100%"> <div class="wrapper flex" style="width: 100%">
<router-link to="/"><img class="logo" src="@/assets/logo.png" alt="Agorata"/></router-link> <router-link to="/">
<img class="logo" src="../assets/logo.png" alt="Agorata" />
</router-link>
<nav style="display: flex"> <nav style="display: flex">
<!-- <router-link to="/">Home</router-link>--> <!-- <router-link to="/">Home</router-link>-->
<!-- <router-link to="/about">About</router-link>--> <!-- <router-link to="/about">About</router-link>-->
@ -11,13 +13,27 @@
</div> </div>
<!-- right-aligned login button --> <!-- right-aligned login button -->
<div class="login-b" v-if="showLogin"> <div class="login-b" v-if="showLogin">
<button class="b blue wide" @click="$emit('login-modal')" v-if="!$store.getters.is_connected"> <button
class="b blue wide"
@click="$emit('login-modal')"
v-if="!$store.getters.is_connected"
>
<span>Login</span> <span>Login</span>
</button> </button>
<div v-else> <div v-else>
<div class="address"> <div class="address">
<span>{{address}}</span> <span>{{ address }}</span>
<img src="@/assets/icons/logout.svg" alt="Logout" @click="$emit('logout')" class="logout-icon"/> <img
src="../assets/icons/logout.svg"
alt="Logout"
@click="$emit('logout')"
class="logout-icon"
/>
<div class="menu">
<router-link to="/my-domains">
<span class="menu-item">My domains</span>
</router-link>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -27,33 +43,33 @@
</template> </template>
<script> <script>
import {convertAddress} from "../utils.ts"; import { convertAddress } from "../utils.ts";
export default { export default {
name: "Header", name: "Header",
props: { props: {
showLogin: { showLogin: {
type: Boolean, type: Boolean,
default: true default: true,
} },
}, },
computed: { computed: {
address() { address() {
if (!this.$store.getters.is_connected) { if (!this.$store.getters.is_connected) {
return ''; return "";
} }
let address_raw = this.$store.getters.address; let address_raw = this.$store.getters.address;
if (address_raw === undefined) { if (address_raw === undefined) {
return ''; return "";
} }
let address = convertAddress(address_raw); let address = convertAddress(address_raw);
return address.slice(0, 5) + '...' + address.slice(-4); return address.slice(0, 5) + "..." + address.slice(-4);
} },
} },
} };
</script> </script>
<style scoped> <style lang="scss" scoped>
header { header {
line-height: 1.5; line-height: 1.5;
max-height: 10rem; max-height: 10rem;
@ -78,12 +94,40 @@ nav {
text-align: center; text-align: center;
} }
.menu {
background-color: #4e5a88;
position: absolute;
bottom: -30px;
right: 0;
text-align: center;
left: 0;
display: none;
border-bottom-left-radius: 0.5rem;
border-bottom-right-radius: 0.5rem;
border-top: 1px solid #363e5e;
}
.menu-item {
display: block;
padding: 4px 16px;
color: white;
}
.address { .address {
color: white; color: white;
background-color: #4e5a88; background-color: #4e5a88;
border-radius: 0.5rem; border-radius: 0.5rem;
padding: 0.5rem 1rem; padding: 0.5rem 1rem;
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
position: relative;
&:hover {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
& .menu {
display: block;
}
}
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
@ -127,4 +171,4 @@ nav {
display: flex; display: flex;
align-items: center; align-items: center;
} }
</style> </style>

159
src/components/SiteSettings.vue

@ -1,119 +1,119 @@
<template> <template>
<div class="center"> <div class="center">
<div class="constr-switcher"> <div class="constr-switcher">
<div @click="constructor_site = true" <div
:class="{'inactive': !constructor_site, 'constr-switch': true}"> @click="constructor_site = true"
:class="{ inactive: !constructor_site, 'constr-switch': true }"
>
By template By template
</div> </div>
<div @click="constructor_site = false" <div
:class="{'inactive': constructor_site, 'constr-switch': true}"> @click="constructor_site = false"
:class="{ inactive: constructor_site, 'constr-switch': true }"
>
Host your own Host your own
</div> </div>
</div> </div>
<div id="site_input" class="rec-field" v-if="!constructor_site"> <div id="site_input" class="rec-field" v-if="!constructor_site">
<div style="display: flex; width: 100%"> <div style="display: flex; width: 100%">
<p style="width: 9rem;">Site:</p> <p style="width: 9rem">Site:</p>
<contenteditable class="record-inp site-record-field" tag="div" :no-hl="true" :no-html="true" spellcheck="false" <contenteditable
v-model="site_rec"></contenteditable> class="record-inp site-record-field"
<div :class="{'record-submit': true, 'get_b': true, 'inactive': !siteChanged, 'signing': signingSite}" tag="div"
@click="$emit('save')"> :no-hl="true"
:no-html="true"
spellcheck="false"
v-model="site_rec"
></contenteditable>
<div
:class="{
'record-submit': true,
get_b: true,
inactive: !siteChanged,
signing: signingSite,
}"
@click="$emit('save')"
>
<template v-if="!signingSite">Save</template> <template v-if="!signingSite">Save</template>
<template v-else> <template v-else>
<Socket secondary-color="#a7aab3" color="#282e46" size="50px" style="min-width: 3rem"/> <Socket
secondary-color="#a7aab3"
color="#282e46"
size="50px"
style="min-width: 3rem"
/>
Confirm in the wallet... Confirm in the wallet...
</template> </template>
</div> </div>
</div> </div>
</div> </div>
<div v-else class="constructor-form"> <div v-else class="constructor-form">
<div style="display: flex; width: 100%"> <Switcher
<p style="width: 9rem;">Title:</p> :items="templates"
<contenteditable class="record-inp" tag="div" :no-hl="true" :no-html="true" spellcheck="false" @change="(item) => (activeTemplateName = item.name)"
v-model="constructor_params.title"></contenteditable> :active-name="activeTemplateName"
</div> />
<div style="display: flex; width: 100%"> <TemplatesList
<p style="width: 9rem;">Description:</p> :templates="templates"
<contenteditable class="record-inp" tag="div" :no-hl="true" :no-html="true" spellcheck="false" :active-template-name="activeTemplateName"
v-model="constructor_params.description"></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</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>
</div> </div>
</template> </template>
<script> <script>
import Socket from "./Socket.vue"; import Socket from "./Socket.vue";
import contenteditable from 'vue-contenteditable'; import contenteditable from "vue-contenteditable";
import {config} from "../api"; import { config, get_templates } from "../api";
import {default_links, SiteConstructorParams} from "../result"; import { default_links, SiteConstructorParams } from "../result";
import {link_types, link_icons} from "../result"; import { link_types, link_icons } from "../result";
import TemplatesList from "./TemplatesList.vue";
import Switcher from "./Switcher.vue";
export default { export default {
name: "SiteSettings", name: "SiteSettings",
components: {Socket, contenteditable}, components: { Socket, contenteditable, TemplatesList, Switcher },
props: { props: {
site_rec_init: { site_rec_init: {
default: null default: null,
}, },
siteChanged: { siteChanged: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
constructorChanged: { constructorChanged: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
signingSite: { signingSite: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
}, },
data() { data() {
let site_rec = this.site_rec_init; let site_rec = this.site_rec_init;
if (!site_rec) site_rec = config.agorata_adnl; if (!site_rec) site_rec = config.agorata_adnl;
let constructor_site = site_rec.toLowerCase() === config.agorata_adnl.toLowerCase(); let constructor_site =
site_rec.toLowerCase() === config.agorata_adnl.toLowerCase();
return { return {
site_rec, site_rec,
constructor_site, constructor_site,
constructor_params: new SiteConstructorParams(''), constructor_params: new SiteConstructorParams(""),
saved_constructor_params: new SiteConstructorParams(''), saved_constructor_params: new SiteConstructorParams(""),
contacts: [] contacts: [],
} templates: [],
activeTemplateName: "Template #1",
};
}, },
watch: { watch: {
site_rec_patched() { site_rec_patched() {
this.$emit('change', this.site_rec_patched); this.$emit("change", this.site_rec_patched);
}, },
constructor_params: { constructor_params: {
handler: function (newVal) { handler: function (newVal) {
this.$emit('change-constructor', newVal); this.$emit("change-constructor", newVal);
}, },
deep: true deep: true,
}, },
saved_constructor_params: { saved_constructor_params: {
handler: function (newVal, oldVal) { handler: function (newVal, oldVal) {
@ -121,7 +121,7 @@ export default {
this.constructor_params = newVal.copy(); this.constructor_params = newVal.copy();
this.contacts = Object.entries(newVal.contacts); this.contacts = Object.entries(newVal.contacts);
}, },
deep: true deep: true,
}, },
contacts: { contacts: {
handler: function (newVal) { handler: function (newVal) {
@ -130,7 +130,7 @@ export default {
this.constructor_params.contacts[contact[0]] = contact[1]; this.constructor_params.contacts[contact[0]] = contact[1];
} }
}, },
deep: true deep: true,
}, },
}, },
computed: { computed: {
@ -143,7 +143,9 @@ export default {
}, },
link_types() { link_types() {
// return the types from link_types that are not in the constructor_params.contacts // 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)); return link_types.filter(
(link_type) => !(link_type in this.constructor_params.contacts)
);
}, },
link_icons() { link_icons() {
return link_icons; return link_icons;
@ -157,14 +159,24 @@ export default {
this.site_rec = site_rec; this.site_rec = site_rec;
}, },
addLink(link_type) { addLink(link_type) {
console.log('adding link', link_type); console.log("adding link", link_type);
// If there's already a link of this type, don't add it // If there's already a link of this type, don't add it
if (link_type in this.constructor_params.contacts) return; if (link_type in this.constructor_params.contacts) return;
this.contacts.push([link_type, default_links[link_type]]) this.contacts.push([link_type, default_links[link_type]]);
this.constructor_params.contacts[link_type] = default_links[link_type]; this.constructor_params.contacts[link_type] = default_links[link_type];
}, },
} async setTemplates() {
} this.templates = await get_templates();
this.templates = this.templates.map((template, i) => ({
...template,
name: `Template #${i + 1}`,
}));
},
},
mounted() {
this.setTemplates();
},
};
</script> </script>
<style scoped> <style scoped>
@ -201,7 +213,7 @@ export default {
max-width: 8rem; max-width: 8rem;
} }
.constructor-form > div:not(:last-child) { .constructor-form > div > div:not(:last-child) {
margin-bottom: 1rem; margin-bottom: 1rem;
} }
@ -213,7 +225,6 @@ export default {
margin-bottom: 1rem; margin-bottom: 1rem;
border-radius: 1.3rem; border-radius: 1.3rem;
padding: 1rem; padding: 1rem;
max-width: 35rem;
background-color: #4e5a88; background-color: #4e5a88;
} }
@ -239,7 +250,7 @@ export default {
} }
.site-record-field { .site-record-field {
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
} }
.link-type:not(:last-child) { .link-type:not(:last-child) {
@ -258,4 +269,4 @@ export default {
.link-type-icon { .link-type-icon {
font-size: 2.5rem; font-size: 2.5rem;
} }
</style> </style>

55
src/components/Switcher.vue

@ -0,0 +1,55 @@
<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>
</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>

287
src/components/TemplatesList.vue

@ -0,0 +1,287 @@
<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">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</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;
}
.get_b {
max-width: 8rem;
}
.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>

10
src/components/TonButton.vue

@ -1,14 +1,14 @@
<template> <template>
<button class="b darkish mobile-scale"> <button class="b darkish mobile-scale">
<span><slot></slot></span> <span><slot></slot></span>
<img src="@/assets/icons/ton_bottom.svg" alt="TON"/> <img src="../assets/icons/ton_bottom.svg" alt="TON" />
</button> </button>
</template> </template>
<script> <script>
export default { export default {
name: "TonButton" name: "TonButton",
} };
</script> </script>
<style scoped> <style scoped>
@ -16,7 +16,7 @@ button.b.darkish {
width: 4rem; width: 4rem;
height: 2rem; height: 2rem;
padding: 0.3rem; padding: 0.3rem;
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
font-weight: bold; font-weight: bold;
font-size: 1.15rem; font-size: 1.15rem;
cursor: default; cursor: default;
@ -34,4 +34,4 @@ button > img:not(:first-child) {
padding: 0.15rem; padding: 0.15rem;
} }
} }
</style> </style>

63
src/components/Tooltip.vue

@ -0,0 +1,63 @@
<template>
<div
@mouseleave="onMouseLeave"
@mouseenter="onMouseEnter"
class="tooltip-container"
>
<slot />
<div v-if="showTooltip" class="tooltip">
{{ text }}
</div>
</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "Tooltip",
props: {
text: {
type: String,
required: true,
},
},
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;
}
</style>

21
src/components/WhiteLayout.vue

@ -1,6 +1,6 @@
<template> <template>
<div style="width: 100vw"> <div style="width: 100vw">
<Header :show-login="false"/> <Header :show-login="false" />
<div class="header-logo"> <div class="header-logo">
<slot name="header"></slot> <slot name="header"></slot>
</div> </div>
@ -14,8 +14,8 @@
<router-link :to="next"> <router-link :to="next">
<!-- "Next" button of class "bblue wide" with @/assets/icons/ton_right.svg icon on the right --> <!-- "Next" button of class "bblue wide" with @/assets/icons/ton_right.svg icon on the right -->
<button class="b blue wide"> <button class="b blue wide">
<span>{{nexttext}}</span> <span>{{ nexttext }}</span>
<img src="@/assets/icons/ton_right.svg" alt="Next"/> <img src="../assets/icons/ton_right.svg" alt="Next" />
</button> </button>
</router-link> </router-link>
</slot> </slot>
@ -28,17 +28,17 @@ import Header from "../components/Header.vue";
export default { export default {
name: "WhiteLayout", name: "WhiteLayout",
components: {Header}, components: { Header },
props: { props: {
next: { next: {
type: String type: String,
}, },
nexttext: { nexttext: {
type: String, type: String,
default: "Next" default: "Next",
} },
} },
} };
</script> </script>
<style scoped> <style scoped>
@ -59,11 +59,10 @@ export default {
align-items: center; align-items: center;
place-items: center; place-items: center;
/* Center the buttons */ /* Center the buttons */
} }
.rbox { .rbox {
min-width: 90%; min-width: 90%;
margin: auto 3%; margin: auto 3%;
} }
</style> </style>

107
src/components/ZonePricing.vue

@ -10,79 +10,98 @@
--> -->
<table> <table>
<thead> <thead>
<tr> <tr>
<th></th> <th></th>
<th v-if="zone.canAuction()"> <th v-if="zone.canAuction()">
<Popper content="Buy on auction" placement="left" :hover="true" :arrow="true" class="mobile-scale"> <Popper
<img src="@/assets/icons/buy.svg" class="buy_img" alt="Buy on auction"/> content="Buy on auction"
</Popper> placement="left"
</th> :hover="true"
<th v-if="zone.canBuy()"> :arrow="true"
<Popper content="Buy instantly" placement="right" :hover="true" :arrow="true" class="mobile-scale"> class="mobile-scale"
<img src="@/assets/icons/instant_buy.svg" class="buy_img" alt="Instant Buy"/> >
</Popper> <img
</th> src="../assets/icons/buy.svg"
</tr> class="buy_img"
alt="Buy on auction"
/>
</Popper>
</th>
<th v-if="zone.canBuy()">
<Popper
content="Buy instantly"
placement="right"
:hover="true"
:arrow="true"
class="mobile-scale"
>
<img
src="../assets/icons/instant_buy.svg"
class="buy_img"
alt="Instant Buy"
/>
</Popper>
</th>
</tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td>{{ '*'.repeat(zone.length_1) + '.' + zone.zone }}</td> <td>{{ "*".repeat(zone.length_1) + "." + zone.zone }}</td>
<td v-if="zone.canAuction()"> <td v-if="zone.canAuction()">
<TonButton>{{ zone.price_auction_1 }}</TonButton> <TonButton>{{ zone.price_auction_1 }}</TonButton>
</td> </td>
<td v-if="zone.canBuy()"> <td v-if="zone.canBuy()">
<TonButton>{{ zone.price_buy_1 }}</TonButton> <TonButton>{{ zone.price_buy_1 }}</TonButton>
</td> </td>
</tr> </tr>
<tr> <tr>
<td>{{ '*'.repeat(zone.length_2) + '.' + zone.zone }}</td> <td>{{ "*".repeat(zone.length_2) + "." + zone.zone }}</td>
<td v-if="zone.canAuction()"> <td v-if="zone.canAuction()">
<TonButton>{{ zone.price_auction_2 }}</TonButton> <TonButton>{{ zone.price_auction_2 }}</TonButton>
</td> </td>
<td v-if="zone.canBuy()"> <td v-if="zone.canBuy()">
<TonButton>{{ zone.price_buy_2 }}</TonButton> <TonButton>{{ zone.price_buy_2 }}</TonButton>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<router-link :to="{name: 'Get', params: {domain_init: 'example', zone: zone.zone}}"> <router-link
<div v-if="has_get" class="get_b mobile-scale"> :to="{ name: 'Get', params: { domain_init: 'example', zone: zone.zone } }"
Get >
</div> <div v-if="has_get" class="get_b mobile-scale">Get</div>
</router-link> </router-link>
</div> </div>
</template> </template>
<script> <script>
import {Zone} from "../zone"; import { Zone } from "../zone";
import Popper from "vue3-popper"; import Popper from "vue3-popper";
import TonButton from "./TonButton.vue"; import TonButton from "./TonButton.vue";
export default { export default {
name: "ZonePricing", name: "ZonePricing",
components: {TonButton, Popper}, components: { TonButton, Popper },
props: { props: {
zone: { zone: {
type: Zone, type: Zone,
default: new Zone("example.ton", 3, 5) default: new Zone("example.ton", 3, 5),
}, },
// Whether to show the "Get" button // Whether to show the "Get" button
has_get: { has_get: {
type: Boolean, type: Boolean,
default: true default: true,
}, },
} },
} };
</script> </script>
<style scoped> <style scoped>
tr > td:first-child { tr > td:first-child {
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
padding-right: 1rem; padding-right: 1rem;
padding-left: 3rem; padding-left: 3rem;
} }
@media only screen and (max-width: 800px) { @media only screen and (max-width: 800px) {
tr > td:first-child { tr > td:first-child {
font-size: 0.9rem; font-size: 0.9rem;
@ -105,4 +124,4 @@ tr > th {
.get_b { .get_b {
margin-top: 2.1rem; margin-top: 2.1rem;
} }
</style> </style>

147
src/router/index.ts

@ -1,5 +1,6 @@
import {createRouter, createWebHistory} from 'vue-router' import { createRouter, createWebHistory } from "vue-router";
import Landing from '../views/Landing.vue' import Landing from "../views/Landing.vue";
import { mintCollection, myDomains } from "./routes";
/* /*
/find - bar + table /find - bar + table
@ -9,69 +10,81 @@ import Landing from '../views/Landing.vue'
*/ */
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: [ routes: [
{ {
path: '/', path: "/",
name: 'home', name: "home",
component: Landing component: Landing,
}, },
{ {
path: '/tonweb', path: "/tonweb",
name: 'tonweb', name: "tonweb",
component: () => import('../views/TonWeb.vue') component: () => import("../views/TonWeb.vue"),
}, },
{ {
path: '/i-know', path: "/i-know",
name: 'IKnow', name: "IKnow",
component: () => import('../views/IKnow.vue') component: () => import("../views/IKnow.vue"),
}, },
{ {
path: '/i-have', path: "/i-have",
name: 'IHave', name: "IHave",
component: () => import('../views/IHave.vue') component: () => import("../views/IHave.vue"),
}, },
{ {
path: '/tondns', path: "/tondns",
name: 'tondns', name: "tondns",
component: () => import('../views/TonDns.vue') component: () => import("../views/TonDns.vue"),
}, },
{ {
path: '/get/:zone', path: "/get/:zone",
name: 'GetZ', name: "GetZ",
component: () => import('../views/Get.vue'), component: () => import("../views/Get.vue"),
props: true props: true,
}, },
{ {
path: '/get/:zone/:domain_init', path: "/get/:zone/:domain_init",
name: 'Get', name: "Get",
component: () => import('../views/Get.vue'), component: () => import("../views/Get.vue"),
props: true props: true,
}, },
{ {
path: '/find', path: "/find",
name: 'Find', name: "Find",
component: () => import('../views/Find.vue') component: () => import("../views/Find.vue"),
}, },
{ {
path: '/checkout/:zone/:domain', path: "/checkout/:zone/:domain",
name: 'Checkout', name: "Checkout",
component: () => import('../views/Checkout.vue'), component: () => import("../views/Checkout.vue"),
props: true props: true,
}, },
{ {
path: '/find/:query', path: "/find/:query",
name: 'FindQ', name: "FindQ",
component: () => import('../views/FindQ.vue'), component: () => import("../views/FindQ.vue"),
props: true props: true,
}, },
{ {
path: '/explore/:domain', path: "/explore/:domain",
name: 'Explore', name: "Explore",
component: () => import('../views/Explore.vue'), component: () => import("../views/Explore.vue"),
props: true props: true,
} },
] {
}) path: "/my-domains",
name: myDomains,
component: () => import("../views/MyDomains.vue"),
props: true,
},
{
path: "/mint-collection",
name: mintCollection,
component: () => import("../views/MintCollection.vue"),
props: true,
},
],
});
export default router export default router;

2
src/router/routes.ts

@ -0,0 +1,2 @@
export const myDomains = "my-domains";
export const mintCollection = "mint-collection";

24
src/types.ts

@ -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 }[];
};

62
src/views/Checkout.vue

@ -1,19 +1,26 @@
<template> <template>
<DarkLayout> <DarkLayout>
<template v-slot:header> <template v-slot:header>
<router-link :to="{name: 'Get', params: {domain_init: domain, zone: zone}}"> <router-link
:to="{ name: 'Get', params: { domain_init: domain, zone: zone } }"
>
<button class="b darkish back"> <button class="b darkish back">
<img src="@/assets/icons/ton_left.svg" alt="TON"/> <img src="../assets/icons/ton_left.svg" alt="TON" />
Back Back
</button> </button>
</router-link> </router-link>
</template> </template>
<!-- todo: handle auction --> <!-- todo: handle auction -->
<div class="text">To buy</div> <div class="text">To buy</div>
<DomainBar :zone="'.' + zone" :value="domain" :has_button="false" :editable="false"/> <DomainBar
:zone="'.' + zone"
:value="domain"
:has_button="false"
:editable="false"
/>
<div class="text">Confirm the transaction in your wallet</div> <div class="text">Confirm the transaction in your wallet</div>
<div class="center"> <div class="center">
<Socket/> <Socket />
</div> </div>
</DarkLayout> </DarkLayout>
</template> </template>
@ -21,32 +28,32 @@
<script> <script>
import DarkLayout from "../components/DarkLayout.vue"; import DarkLayout from "../components/DarkLayout.vue";
import DomainBar from "../components/DomainBar.vue"; import DomainBar from "../components/DomainBar.vue";
import {get_domain_result, get_ton_link} from "../result"; import { get_domain_result, get_ton_link } from "../result";
import RotateSquare2 from "../components/RotateSquare2.vue"; import RotateSquare2 from "../components/RotateSquare2.vue";
import {qr_options} from "../utils"; import { qr_options } from "../utils";
import Socket from "../components/Socket.vue"; import Socket from "../components/Socket.vue";
export default { export default {
name: "Checkout", name: "Checkout",
components: {Socket, RotateSquare2, DomainBar, DarkLayout}, components: { Socket, RotateSquare2, DomainBar, DarkLayout },
props: { props: {
domain: { domain: {
type: String, type: String,
}, },
zone: { zone: {
type: String, type: String,
} },
}, },
data() { data() {
return { return {
result: null, result: null,
ton_link: null, ton_link: null,
qr_code: null, qr_code: null,
} };
}, },
methods: { methods: {
async get_result() { async get_result() {
this.result = await get_domain_result(this.domain + '.' + this.zone); this.result = await get_domain_result(this.domain + "." + this.zone);
this.ton_link = await get_ton_link(this.result); this.ton_link = await get_ton_link(this.result);
}, },
async sign_transaction() { async sign_transaction() {
@ -55,22 +62,27 @@ export default {
let validness = parseInt((d.getTime() / 1000).toFixed(0)) + 360000; let validness = parseInt((d.getTime() / 1000).toFixed(0)) + 360000;
const transaction = { const transaction = {
validUntil: validness, validUntil: validness,
messages: [ messages: [Object.assign({}, this.result.buy_msg)],
Object.assign({}, this.result.buy_msg) };
]
}
console.log("Signing the transaction", transaction); console.log("Signing the transaction", transaction);
const result = await this.$store.state.connector.sendTransaction(transaction); const result = await this.$store.state.connector.sendTransaction(
transaction
);
console.log(result); console.log(result);
if (result.boc === '') { if (result.boc === "") {
this.$router.push({name: 'Get', params: {domain_init: this.domain, zone: this.zone}}); this.$router.push({
name: "Get",
params: { domain_init: this.domain, zone: this.zone },
});
} }
this.$router.push({name: 'Explore', params: {domain: this.domain + '.' + this.zone}}); this.$router.push({
} name: "Explore",
params: { domain: this.domain + "." + this.zone },
});
},
}, },
mounted() { mounted() {
this.sign_transaction() this.sign_transaction();
}, },
computed: { computed: {
loaded() { loaded() {
@ -81,13 +93,13 @@ export default {
return null; return null;
} }
return qr_options(this.ton_link.getLink()); return qr_options(this.ton_link.getLink());
} },
} },
} };
</script> </script>
<style> <style>
.qr > div > svg { .qr > div > svg {
border-radius: 2rem; border-radius: 2rem;
} }
</style> </style>

235
src/views/Explore.vue

@ -1,58 +1,97 @@
<template> <template>
<DarkLayout> <DarkLayout>
<template v-slot:header> <template v-slot:header>
<router-link :to="{name: 'Get', params: {domain_init: core_domain, zone: zone}}"> <router-link
:to="{ name: 'Get', params: { domain_init: core_domain, zone: zone } }"
>
<button class="b darkish back"> <button class="b darkish back">
<img src="@/assets/icons/ton_left.svg" alt="TON"/> <img src="../assets/icons/ton_left.svg" alt="TON" />
Back Back
</button> </button>
</router-link> </router-link>
</template> </template>
<div style="min-width: 50%"> <div style="min-width: 50%">
<DomainBar :value="core_domain" :zone="'.' + zone" :has_button="false" :editable="false"/> <DomainBar
:value="core_domain"
:zone="'.' + zone"
:has_button="false"
:editable="false"
/>
<div v-if="loading" class="center"> <div v-if="loading" class="center">
<RotateSquare2 style="width: 5rem; height: 5rem; margin-top: 3rem;"/> <RotateSquare2 style="width: 5rem; height: 5rem; margin-top: 3rem" />
</div> </div>
<div v-else> <div v-else>
<div class="owned" v-if="result.owner && !isMine"> <div class="owned" v-if="result.owner && !isMine">
<p class="domain">{{ domain }}</p> <p class="domain">{{ domain }}</p>
<div>is owned by <div>
is owned by
<div class="owner-address">{{ ownerAddr }}</div> <div class="owner-address">{{ ownerAddr }}</div>
</div> </div>
<a :href="result.nft_info.explorer_link">View nft</a> <a :href="result.nft_info.explorer_link">View nft</a>
</div> </div>
<div v-else-if="isMine" class="owned"> <div v-else-if="isMine" class="owned">
<p class="domain">{{ domain }}</p> <p class="domain">{{ domain }}</p>
<div>is owned by <div>
is owned by
<div class="owner-address">you</div> <div class="owner-address">you</div>
</div> </div>
<a :href="result.nft_info.explorer_link">View nft</a> <a :href="result.nft_info.explorer_link">View nft</a>
<br/> <router-link :to="{ name: mintCollection }">
Mint a subdomain collection
</router-link>
<br />
<div id="wallet_input" class="rec-field"> <div id="wallet_input" class="rec-field">
<div style="display: flex; width: 100%"> <div style="display: flex; width: 100%">
<p style="width: 9rem">Wallet:</p> <p style="width: 9rem">Wallet:</p>
<contenteditable class="record-inp wallet-record-field" tag="div" :no-hl="true" :no-html="true" spellcheck="false" <contenteditable
v-model="wallet_rec"></contenteditable> class="record-inp wallet-record-field"
<div :class="{'record-submit': true, 'get_b': true, 'inactive': !walletChanged, 'signing': signingWallet}" @click="saveWallet()"> tag="div"
:no-hl="true"
:no-html="true"
spellcheck="false"
v-model="wallet_rec"
></contenteditable>
<div
:class="{
'record-submit': true,
get_b: true,
inactive: !walletChanged,
signing: signingWallet,
}"
@click="saveWallet()"
>
<template v-if="!signingWallet">Save</template> <template v-if="!signingWallet">Save</template>
<template v-else> <template v-else>
<Socket secondary-color="#a7aab3" color="#282e46" size="50px" style="min-width: 3rem"/> <Socket
secondary-color="#a7aab3"
color="#282e46"
size="50px"
style="min-width: 3rem"
/>
Confirm in the wallet... Confirm in the wallet...
</template> </template>
</div> </div>
</div> </div>
</div> </div>
<SiteSettings ref="site_settings" <SiteSettings
@save="saveSite()" @save-constructor="saveSiteConstr()" ref="site_settings"
@change="site_rec = $event" @change-constructor="constructor_params = $event" @save="saveSite()"
:site-changed="siteChanged" :signing-site="signingSite"/> @save-constructor="saveSiteConstr()"
@change="site_rec = $event"
@change-constructor="constructor_params = $event"
:site-changed="siteChanged"
:signing-site="signingSite"
/>
</div> </div>
<div v-else> <div v-else>
This domain is not owned. This domain is not owned.
<router-link :to="{name: 'Get', params: {domain_init: core_domain, zone: zone}}"> <router-link
<button class="b darkish back"> :to="{
Get it name: 'Get',
</button> params: { domain_init: core_domain, zone: zone },
}"
>
<button class="b darkish back">Get it</button>
</router-link> </router-link>
</div> </div>
</div> </div>
@ -64,58 +103,87 @@
import DarkLayout from "../components/DarkLayout.vue"; import DarkLayout from "../components/DarkLayout.vue";
import DomainBar from "../components/DomainBar.vue"; import DomainBar from "../components/DomainBar.vue";
import RotateSquare2 from "../components/RotateSquare2.vue"; import RotateSquare2 from "../components/RotateSquare2.vue";
import {get_constr_params, get_domain_result, get_records, SiteConstructorParams} from "../result"; import {
import {convertAddress} from "../utils"; get_constr_params,
import contenteditable from 'vue-contenteditable'; get_domain_result,
import {call_api, call_api_post, config} from "../api"; get_records,
SiteConstructorParams,
} from "../result";
import { convertAddress } from "../utils";
import contenteditable from "vue-contenteditable";
import { call_api, call_api_post, config } from "../api";
import Socket from "../components/Socket.vue"; import Socket from "../components/Socket.vue";
import SiteSettings from "../components/SiteSettings.vue"; import SiteSettings from "../components/SiteSettings.vue";
import { mintCollection } from "@/router/routes";
export default { export default {
name: "Explore", name: "Explore",
components: {SiteSettings, Socket, DomainBar, DarkLayout, RotateSquare2, contenteditable}, components: {
SiteSettings,
Socket,
DomainBar,
DarkLayout,
RotateSquare2,
contenteditable,
},
props: { props: {
domain: { domain: {
type: String, type: String,
} },
}, },
data() { data() {
let saved_constructor_params = new SiteConstructorParams(this.domain, this.domain); let saved_constructor_params = new SiteConstructorParams(
this.domain,
this.domain
);
return { return {
result: null, result: null,
records: {wallet: null, storage: null, uri: null, next_resolver: null, site: null}, records: {
wallet: null,
storage: null,
uri: null,
next_resolver: null,
site: null,
},
wallet_rec: null, wallet_rec: null,
site_rec: null, site_rec: null,
signingSite: false, signingSite: false,
signingWallet: false, signingWallet: false,
constructor_params: saved_constructor_params, constructor_params: saved_constructor_params,
saved_constructor_params, saved_constructor_params,
interval: null interval: null,
} };
}, },
mounted() { mounted() {
this.interval = setInterval(() => get_domain_result(this.domain, this.$store.getters.address).then(r => { this.interval = setInterval(
this.result = Object.assign({}, r); () =>
if (this.isMine) { get_domain_result(this.domain, this.$store.getters.address).then(
get_constr_params(this.domain).then(r => { (r) => {
this.constructor_params = r; this.result = Object.assign({}, r);
this.saved_constructor_params = r; if (this.isMine) {
this.updSettingsComponent(); get_constr_params(this.domain).then((r) => {
}); this.constructor_params = r;
get_records(r.nft_info.address).then(r => { this.saved_constructor_params = r;
this.records = r; this.updSettingsComponent();
// this.timer = setTimeout(this.updRecords, 10000); });
this.updSettingsComponent() get_records(r.nft_info.address).then((r) => {
}) this.records = r;
} // this.timer = setTimeout(this.updRecords, 10000);
}), 20000); this.updSettingsComponent();
});
}
}
),
20000
);
}, },
computed: { computed: {
core_domain() { core_domain() {
return this.domain.split('.')[0]; return this.domain.split(".")[0];
}, },
zone() { zone() {
return this.domain.split('.').slice(1).join('.'); return this.domain.split(".").slice(1).join(".");
}, },
loading() { loading() {
return this.result === null; return this.result === null;
@ -123,12 +191,13 @@ export default {
ownerAddr() { ownerAddr() {
let owner = this.result.owner; let owner = this.result.owner;
if (!owner instanceof String) { if (!owner instanceof String) {
return ''; return "";
} }
let address = convertAddress(owner); let address = convertAddress(owner);
return address.slice(0, 5) + '...' + address.slice(-4); return address.slice(0, 5) + "..." + address.slice(-4);
}, },
isMine() { isMine() {
console.log(this.result);
return this.result.owner === this.$store.getters.address; return this.result.owner === this.$store.getters.address;
}, },
walletChanged() { walletChanged() {
@ -137,13 +206,16 @@ export default {
siteChanged() { siteChanged() {
let constr_change = false; let constr_change = false;
if (this.site_rec === config.agorata_adnl) { if (this.site_rec === config.agorata_adnl) {
constr_change = this.constructor_params !== this.saved_constructor_params; constr_change =
this.constructor_params !== this.saved_constructor_params;
} }
return this.records && (this.site_rec !== this.records.site || constr_change); return (
this.records && (this.site_rec !== this.records.site || constr_change)
);
}, },
settingsCompLoaded() { settingsCompLoaded() {
return this.$refs.site_settings !== undefined; return this.$refs.site_settings !== undefined;
} },
}, },
methods: { methods: {
async saveWallet() { async saveWallet() {
@ -151,7 +223,7 @@ export default {
return; return;
} }
// get the message from api at /set-record/site/{site} and sign it with tonconnect (from storage) // get the message from api at /set-record/site/{site} and sign it with tonconnect (from storage)
let message = await call_api('set-record/wallet/' + this.wallet_rec); let message = await call_api("set-record/wallet/" + this.wallet_rec);
// send the message to tonconnect // send the message to tonconnect
let d = new Date(); let d = new Date();
let validness = parseInt((d.getTime() / 1000).toFixed(0)) + 360000; let validness = parseInt((d.getTime() / 1000).toFixed(0)) + 360000;
@ -161,13 +233,15 @@ export default {
{ {
amount: (0.05 * 1000000000).toString(), amount: (0.05 * 1000000000).toString(),
address: this.result.nft_info.address, address: this.result.nft_info.address,
payload: message payload: message,
} },
] ],
}; };
this.signingWallet = true; this.signingWallet = true;
console.log("Sending transaction", transaction); console.log("Sending transaction", transaction);
const result = await this.$store.state.connector.sendTransaction(transaction); const result = await this.$store.state.connector.sendTransaction(
transaction
);
this.signingWallet = false; this.signingWallet = false;
if (!result.boc) { if (!result.boc) {
// todo // todo
@ -179,7 +253,7 @@ export default {
return; return;
} }
// get the message from api at /set-record/site/{site} and sign it with tonconnect (from storage) // get the message from api at /set-record/site/{site} and sign it with tonconnect (from storage)
let message = await call_api('set-record/site/' + this.site_rec); let message = await call_api("set-record/site/" + this.site_rec);
// send the message to tonconnect // send the message to tonconnect
let d = new Date(); let d = new Date();
let validness = parseInt((d.getTime() / 1000).toFixed(0)) + 360000; let validness = parseInt((d.getTime() / 1000).toFixed(0)) + 360000;
@ -189,12 +263,14 @@ export default {
{ {
amount: (0.05 * 1000000000).toString(), amount: (0.05 * 1000000000).toString(),
address: this.result.nft_info.address, address: this.result.nft_info.address,
payload: message payload: message,
} },
] ],
}; };
this.signingSite = true; this.signingSite = true;
const result = await this.$store.state.connector.sendTransaction(transaction); const result = await this.$store.state.connector.sendTransaction(
transaction
);
this.signingSite = false; this.signingSite = false;
if (!result.boc) { if (!result.boc) {
// todo // todo
@ -205,21 +281,22 @@ export default {
if (this.site_rec !== this.records.site) { if (this.site_rec !== this.records.site) {
await this.saveSite(); await this.saveSite();
} }
await call_api_post('set-site-data', this.constructor_params); await call_api_post("set-site-data", this.constructor_params);
this.saved_constructor_params = this.constructor_params; this.saved_constructor_params = this.constructor_params;
this.updSettingsComponent(); this.updSettingsComponent();
}, },
updRecords() { updRecords() {
get_records(this.result.nft_info.address).then(r => { get_records(this.result.nft_info.address).then((r) => {
if (this.records.wallet !== r.wallet || this.records.site !== r.site) { if (this.records.wallet !== r.wallet || this.records.site !== r.site) {
this.records = r; this.records = r;
} }
}) });
}, },
updSettingsComponent() { updSettingsComponent() {
this.$refs.site_settings.set_site_rec(this.site_rec); this.$refs.site_settings.set_site_rec(this.site_rec);
this.$refs.site_settings.saved_constructor_params = this.saved_constructor_params; this.$refs.site_settings.saved_constructor_params =
} this.saved_constructor_params;
},
}, },
watch: { watch: {
records: function (val) { records: function (val) {
@ -228,33 +305,33 @@ export default {
this.site_rec = val.site; this.site_rec = val.site;
} }
}, },
site_rec () { site_rec() {
this.$refs.site_settings.set_site_rec(this.site_rec); this.$refs.site_settings.set_site_rec(this.site_rec);
}, },
saved_constructor_params () { saved_constructor_params() {
this.$refs.site_settings.saved_constructor_params = this.saved_constructor_params; this.$refs.site_settings.saved_constructor_params =
this.saved_constructor_params;
}, },
settingsCompLoaded () { settingsCompLoaded() {
if (!this.loading && this.settingsCompLoaded) { if (!this.loading && this.settingsCompLoaded) {
this.updSettingsComponent(); this.updSettingsComponent();
} }
}, },
loading () { loading() {
if (!this.loading && this.settingsCompLoaded) { if (!this.loading && this.settingsCompLoaded) {
this.updSettingsComponent(); this.updSettingsComponent();
} }
} },
}, },
unmounted() { unmounted() {
clearInterval(this.interval); clearInterval(this.interval);
} },
} };
</script> </script>
<style scoped> <style scoped>
.domain { .domain {
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
font-weight: bold; font-weight: bold;
font-size: 2rem; font-size: 2rem;
} }
@ -275,7 +352,7 @@ export default {
} }
.owner-address { .owner-address {
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
color: #c86161; color: #c86161;
font-size: 2rem; font-size: 2rem;
} }
@ -310,6 +387,6 @@ export default {
} }
.wallet-record-field { .wallet-record-field {
font-family: 'Inconsolata', monospace; font-family: "Inconsolata", monospace;
} }
</style> </style>

42
src/views/Get.vue

@ -1,15 +1,24 @@
<template> <template>
<DarkLayout ref="dl"> <DarkLayout ref="dl">
<template v-slot:header> <template v-slot:header>
<router-link :to="{name: 'Find'}"> <router-link :to="{ name: 'Find' }">
<button class="b darkish back"> <button class="b darkish back">
<img src="@/assets/icons/ton_left.svg" alt="TON"/> <img src="../assets/icons/ton_left.svg" alt="TON" />
All zones All zones
</button> </button>
</router-link> </router-link>
</template> </template>
<DomainBar :zone="'.' + zone" :value="domain" @search="search()" @input_d="handle_input($event)"/> <DomainBar
<DomainResult :domain="domain + '.' + zone" v-if="domain !== ''" @login="$refs.dl.login()"/> :zone="'.' + zone"
:value="domain"
@search="search()"
@input_d="handle_input($event)"
/>
<DomainResult
:domain="domain + '.' + zone"
v-if="domain !== ''"
@login="$refs.dl.login()"
/>
</DarkLayout> </DarkLayout>
</template> </template>
@ -25,30 +34,31 @@ export default {
}, },
zone: { zone: {
type: String, type: String,
} },
}, },
components: {DomainResult, DomainBar, DarkLayout}, components: { DomainResult, DomainBar, DarkLayout },
data() { data() {
return { return {
domain: this.domain_init domain: this.domain_init,
} };
}, },
methods: { methods: {
search() { search() {
this.$router.push({name: 'Get', params: {domain_init: this.domain, zone: this.zone}}); this.$router.push({
name: "Get",
params: { domain_init: this.domain, zone: this.zone },
});
}, },
handle_input(val) { handle_input(val) {
this.domain = val; this.domain = val;
} },
}, },
watch: { watch: {
domain_init: function (val) { domain_init: function (val) {
this.domain = val; this.domain = val;
} },
} },
} };
</script> </script>
<style scoped> <style scoped></style>
</style>

42
src/views/IHave.vue

@ -1,19 +1,37 @@
<template> <template>
<WhiteLayout next=""> <WhiteLayout next="">
<template v-slot:header> <template v-slot:header>
<img src="@/assets/headers/i-know.svg" style="max-height: 100%; max-width: 90%" alt="TON DNS"/> <img
src="../assets/headers/i-know.svg"
style="max-height: 100%; max-width: 90%"
alt="TON DNS"
/>
</template> </template>
<template v-slot:content> <template v-slot:content>
<div class="cont2"> <div class="cont2">
<div class="columns-3" style="display: flex; columns: 3; justify-content: center; align-items: center"> <div
<div> class="columns-3"
</div> style="
display: flex;
columns: 3;
justify-content: center;
align-items: center;
"
>
<div></div>
<div id="great"> <div id="great">
<p> <p>
Very good!<br/>We can help you host a website there or sell subdomains.<br/> Very good!<br />We can help you host a website there or sell
For now, you will have to <a href="https://t.me/ennucore">contact us on Telegram</a>. <br/> subdomains.<br />
We are especially interested in partnering with different projects and communities which are interested in distributing domains to their users.<br/> For now, you will have to
Also, you can always <router-link :to="{name: 'Find'}">buy another domain</router-link>. <a href="https://t.me/ennucore">contact us on Telegram</a>. <br />
We are especially interested in partnering with different projects
and communities which are interested in distributing domains to
their users.<br />
Also, you can always
<router-link :to="{ name: 'Find' }"
>buy another domain</router-link
>.
</p> </p>
</div> </div>
</div> </div>
@ -25,7 +43,7 @@
<span>Contact us</span> <span>Contact us</span>
</button> </button>
</a> </a>
<router-link :to="{name: 'Find'}"> <router-link :to="{ name: 'Find' }">
<button class="b blue wide"> <button class="b blue wide">
<span>Buy a domain</span> <span>Buy a domain</span>
</button> </button>
@ -39,8 +57,8 @@ import WhiteLayout from "../components/WhiteLayout.vue";
export default { export default {
name: "IHave", name: "IHave",
components: {WhiteLayout} components: { WhiteLayout },
} };
</script> </script>
<style scoped> <style scoped>
@ -67,4 +85,4 @@ export default {
align-items: center; align-items: center;
height: 100%; height: 100%;
} }
</style> </style>

35
src/views/IKnow.vue

@ -1,29 +1,40 @@
<template> <template>
<WhiteLayout next=""> <WhiteLayout next="">
<template v-slot:header> <template v-slot:header>
<img src="@/assets/headers/i-know.svg" style="max-height: 100%; max-width: 90%" alt="TON DNS"/> <img
src="../assets/headers/i-know.svg"
style="max-height: 100%; max-width: 90%"
alt="TON DNS"
/>
</template> </template>
<template v-slot:content> <template v-slot:content>
<div class="cont2"> <div class="cont2">
<div class="columns-3" style="display: flex; columns: 3; justify-content: center; align-items: center"> <div
<div> class="columns-3"
</div> style="
display: flex;
columns: 3;
justify-content: center;
align-items: center;
"
>
<div></div>
<div id="great"> <div id="great">
<p>That's great!<br/>Maybe, you even have a domain already?</p> <p>That's great!<br />Maybe, you even have a domain already?</p>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<template v-slot:buttons> <template v-slot:buttons>
<router-link :to="{name: 'IHave'}"> <router-link :to="{ name: 'IHave' }">
<button class="b blue wide"> <button class="b blue wide">
<img src="@/assets/icons/ton_top.svg" alt="Next"/> <img src="../assets/icons/ton_top.svg" alt="Next" />
<span>Yes</span> <span>Yes</span>
</button> </button>
</router-link> </router-link>
<router-link :to="{name: 'tondns'}"> <router-link :to="{ name: 'tondns' }">
<button class="b blue wide"> <button class="b blue wide">
<img src="@/assets/icons/ton_bottom.svg" alt="Next"/> <img src="../assets/icons/ton_bottom.svg" alt="Next" />
<span>No</span> <span>No</span>
</button> </button>
</router-link> </router-link>
@ -36,8 +47,8 @@ import WhiteLayout from "../components/WhiteLayout.vue";
export default { export default {
name: "IKnow", name: "IKnow",
components: {WhiteLayout} components: { WhiteLayout },
} };
</script> </script>
<style scoped> <style scoped>
@ -64,4 +75,4 @@ export default {
align-items: center; align-items: center;
height: 100%; height: 100%;
} }
</style> </style>

17
src/views/Landing.vue

@ -1,18 +1,20 @@
<script setup lang="ts"> <script setup lang="ts"></script>
</script>
<template> <template>
<main> <main>
<!-- @/assets/logo_single.png centered horizontally and slightly above center vertically --> <!-- @/assets/logo_single.png centered horizontally and slightly above center vertically -->
<img class="logo" src="@/assets/logo_landing.png" alt="Agorata" /> <img class="logo" src="../assets/logo_landing.png" alt="Agorata" />
<p style="font-size: 1.8rem; padding: 2rem;">Helping you <b style="font-weight: bold">be</b> the new internet</p> <p style="font-size: 1.8rem; padding: 2rem">
Helping you <b style="font-weight: bold">be</b> the new internet
</p>
<div id="do-you-know"> <div id="do-you-know">
<p>Do you know what TON Web is?</p><br/> <p>Do you know what TON Web is?</p>
<br />
<router-link to="/i-know"> <router-link to="/i-know">
<button class="b white wide">Yes</button> <button class="b white wide">Yes</button>
</router-link> </router-link>
<br/> <br />
<router-link to="/tonweb"> <router-link to="/tonweb">
<button class="b white wide">No</button> <button class="b white wide">No</button>
</router-link> </router-link>
@ -31,7 +33,7 @@ main {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
color: white; color: white;
font-family: 'Raleway',serif; font-family: "Raleway", serif;
font-size: 1.5rem; font-size: 1.5rem;
text-align: center; text-align: center;
} }
@ -52,5 +54,4 @@ main {
align-items: center; align-items: center;
padding: 2rem; padding: 2rem;
} }
</style> </style>

114
src/views/MintCollection.vue

@ -0,0 +1,114 @@
<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 class="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";
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>

18
src/views/MyDomains.vue

@ -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>

26
src/views/TonDns.vue

@ -1,27 +1,29 @@
<template> <template>
<WhiteLayout> <WhiteLayout>
<template v-slot:header> <template v-slot:header>
<img src="@/assets/tondns.svg" style="height: 100%" alt="TON DNS"/> <img src="../assets/tondns.svg" style="height: 100%" alt="TON DNS" />
</template> </template>
<template v-slot:content> <template v-slot:content>
<div style="justify-content: center; align-items: center"> <div style="justify-content: center; align-items: center">
<div> <div>
<p>TON domains .ton and .t.me are your names in the TON world.<br/> <p>
They can be used to host a website or to transfer money.<br/> TON domains .ton and .t.me are your names in the TON world.<br />
You can host a TON website for your personal brand.</p> They can be used to host a website or to transfer money.<br />
You can host a TON website for your personal brand.
</p>
</div> </div>
<div class="columns-3 images"> <div class="columns-3 images">
<img class="img" src="@/assets/images/usage.png" alt="Usage"/> <img class="img" src="../assets/images/usage.png" alt="Usage" />
<img class="img" src="@/assets/images/my_name_is.png" alt="lame"/> <img class="img" src="../assets/images/my_name_is.png" alt="lame" />
<img class="img" src="@/assets/images/anton_ton.png" alt="cool"/> <img class="img" src="../assets/images/anton_ton.png" alt="cool" />
</div> </div>
</div> </div>
</template> </template>
<template v-slot:buttons> <template v-slot:buttons>
<router-link :to="{name: 'Find'}"> <router-link :to="{ name: 'Find' }">
<button class="b blue wide"> <button class="b blue wide">
<span>Omg, can I get one?</span> <span>Omg, can I get one?</span>
<img src="@/assets/icons/ton_right.svg" alt="Next"/> <img src="../assets/icons/ton_right.svg" alt="Next" />
</button> </button>
</router-link> </router-link>
</template> </template>
@ -33,8 +35,8 @@ import WhiteLayout from "../components/WhiteLayout.vue";
export default { export default {
name: "TonDns", name: "TonDns",
components: {WhiteLayout} components: { WhiteLayout },
} };
</script> </script>
<style scoped> <style scoped>
@ -48,4 +50,4 @@ export default {
width: 75vw; width: 75vw;
} }
} }
</style> </style>

45
src/views/TonWeb.vue

@ -1,26 +1,43 @@
<template> <template>
<WhiteLayout next="tondns" nexttext="Wow, what else?"> <WhiteLayout next="tondns" nexttext="Wow, what else?">
<template v-slot:header> <template v-slot:header>
<img src="@/assets/tonweb.svg" style="height: 100%" alt="TON Web"/> <img src="../assets/tonweb.svg" style="height: 100%" alt="TON Web" />
</template> </template>
<template v-slot:content> <template v-slot:content>
<div class="columns-2"> <div class="columns-2">
<div> <div>
<img src="@/assets/images/tonweb_duck.png" alt="TON Web" style="width: 20rem"/> <img
src="../assets/images/tonweb_duck.png"
alt="TON Web"
style="width: 20rem"
/>
</div> </div>
<div> <div>
<p>TON Sites are just websites hosted on the TON Network.<br/> <p>
After some configuration, you can visit a website like foundation.ton.</p> TON Sites are just websites hosted on the TON Network.<br />
After some configuration, you can visit a website like
foundation.ton.
</p>
<p>They have a lot of advantages:</p> <p>They have a lot of advantages:</p>
<ul class="wbox_ul"> <ul class="wbox_ul">
<li> The DApps are truly D: they cannot be banned or pressured, the servers cannot be traced, the apps <li>
don't get the user's IP The DApps are truly D: they cannot be banned or pressured, the
servers cannot be traced, the apps don't get the user's IP
</li>
<li>There can be no censorship</li>
<li>
Validity of websites is determined on the blockchain instead of
trusting authorities for SSL
</li>
<li>
Domain ownership has clear rules on TON, there is no central
authority, no registrators
</li>
<li>The TON Web is nicely integrated with the TON blockchain</li>
<li>
There is no need for logins and passwords you just use your TON
account
</li> </li>
<li> There can be no censorship</li>
<li> Validity of websites is determined on the blockchain instead of trusting authorities for SSL</li>
<li> Domain ownership has clear rules on TON, there is no central authority, no registrators</li>
<li> The TON Web is nicely integrated with the TON blockchain</li>
<li> There is no need for logins and passwords you just use your TON account</li>
</ul> </ul>
</div> </div>
</div> </div>
@ -33,8 +50,8 @@ import WhiteLayout from "../components/WhiteLayout.vue";
export default { export default {
name: "TonWeb", name: "TonWeb",
components: {WhiteLayout} components: { WhiteLayout },
} };
</script> </script>
<style scoped> <style scoped>
@ -53,4 +70,4 @@ export default {
img { img {
max-width: 80vw; max-width: 80vw;
} }
</style> </style>

18
vite.config.ts

@ -1,14 +1,14 @@
import { fileURLToPath, URL } from 'node:url' import { fileURLToPath, URL } from "node:url";
import svgLoader from "vite-svg-loader";
import { defineConfig } from 'vite' import { defineConfig } from "vite";
import vue from '@vitejs/plugin-vue' import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [vue()], plugins: [vue(), svgLoader({ svgo: false })],
resolve: { resolve: {
alias: { alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)) "@": fileURLToPath(new URL("./src", import.meta.url)),
} },
} },
}) });

Loading…
Cancel
Save