Browse Source

SiteSettings

vue
Lev 2 years ago
parent
commit
3fb1b1a6d6
  1. 29
      .idea/workspace.xml
  2. 1
      src/api.ts
  3. 192
      src/components/SiteSettings.vue
  4. 20
      src/result.ts
  5. 155
      src/views/Explore.vue

29
.idea/workspace.xml

@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="ddb8afd5-d3ba-47b1-b6d0-227403f1abf7" name="Changes" comment="Checkout">
<change afterPath="$PROJECT_DIR$/src/assets/icons/logout.svg" afterDir="false" />
<list default="true" id="ddb8afd5-d3ba-47b1-b6d0-227403f1abf7" name="Changes" comment="SiteSettings">
<change afterPath="$PROJECT_DIR$/src/components/SiteSettings.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/views/Checkout.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/views/Checkout.vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/api.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/api.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/result.ts" beforeDir="false" afterPath="$PROJECT_DIR$/src/result.ts" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/views/Explore.vue" beforeDir="false" afterPath="$PROJECT_DIR$/src/views/Explore.vue" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
@ -15,8 +16,8 @@
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Vue Single File Component" />
<option value="TypeScript File" />
<option value="Vue Single File Component" />
</list>
</option>
</component>
@ -94,7 +95,12 @@
<workItem from="1673906442760" duration="1896000" />
<workItem from="1674161982371" duration="16180000" />
<workItem from="1674453019641" duration="3282000" />
<workItem from="1674576152071" duration="4406000" />
<workItem from="1674576152071" duration="10420000" />
<workItem from="1674812957519" duration="2794000" />
<workItem from="1675542984242" duration="370000" />
<workItem from="1677945869469" duration="608000" />
<workItem from="1678007103478" duration="1012000" />
<workItem from="1678136230438" duration="19501000" />
</task>
<task id="LOCAL-00001" summary="Wrote the landing">
<created>1670844191163</created>
@ -236,7 +242,14 @@
<option name="project" value="LOCAL" />
<updated>1672913681110</updated>
</task>
<option name="localTasksCounter" value="21" />
<task id="LOCAL-00021" summary="Managing records">
<created>1674596285797</created>
<option name="number" value="00021" />
<option name="presentableId" value="LOCAL-00021" />
<option name="project" value="LOCAL" />
<updated>1674596285797</updated>
</task>
<option name="localTasksCounter" value="22" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@ -274,6 +287,8 @@
<MESSAGE value="TON Connect is working" />
<MESSAGE value="Working on the buying process" />
<MESSAGE value="Checkout" />
<option name="LAST_COMMIT_MESSAGE" value="Checkout" />
<MESSAGE value="Managing records" />
<MESSAGE value="SiteSettings" />
<option name="LAST_COMMIT_MESSAGE" value="SiteSettings" />
</component>
</project>

1
src/api.ts

@ -8,6 +8,7 @@ declare var process : {
export class Api {
public readonly api_url: string;
public agorata_adnl: string = "3a3a4515e9092ef501d8d820a2964b42abfe541b7aff3d85f9fe5375bc62de9e";
constructor() {
if (process.env.NODE_ENV === 'development') {

192
src/components/SiteSettings.vue

@ -0,0 +1,192 @@
<template>
<div class="center">
<div class="constr-switcher">
<div @click="constructor_site = true"
:class="{'inactive': !constructor_site, 'constr-switch': true}">
By template
</div>
<div @click="constructor_site = false"
:class="{'inactive': constructor_site, 'constr-switch': true}">
Host your own
</div>
</div>
<div id="site_input" class="rec-field" v-if="!constructor_site">
<div style="display: flex; width: 100%">
<p style="width: 9rem;">Site:</p>
<contenteditable class="record-inp site-record-field" tag="div" :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-else>
<Socket secondary-color="#a7aab3" color="#282e46" size="50px" style="min-width: 3rem"/>
Confirm in the wallet...
</template>
</div>
</div>
</div>
<div v-else class="constructor-form">
<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 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";
export default {
name: "SiteSettings",
components: {Socket, contenteditable},
props: {
site_rec_init: {
default: null
},
siteChanged: {
type: Boolean,
default: false
},
constructorChanged: {
type: Boolean,
default: false
},
signingSite: {
type: Boolean,
default: false
},
},
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: {title: ''},
saved_constructor_params: {title: ''},
}
},
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) {
this.$emit('change-constructor', newVal);
},
deep: true
},
},
computed: {
site_rec_patched() {
if (this.constructor_site) {
return config.agorata_adnl;
} else {
return this.site_rec;
}
}
},
methods: {
set_site_rec(site_rec) {
this.site_rec = site_rec;
},
}
}
</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: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;
}
</style>

20
src/result.ts

@ -1,11 +1,10 @@
// import {call_api} from "@/api";
import {Zone} from "@/zone";
import {Collection} from "@/collection";
import type {Message} from "@/utils";
import {call_api} from "@/api";
let ex_collection = () => new Collection("example.ton", "Example collection");
// let ex_collection = () => new Collection("example.ton", "Example collection");
export class Result {
domain: string;
@ -65,9 +64,9 @@ export class Result {
}
}
const sleep = (milliseconds: number) => {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}
// const sleep = (milliseconds: number) => {
// return new Promise(resolve => setTimeout(resolve, milliseconds))
// }
export async function get_search_results(query: string) {
return Result.fromBackend(await call_api('find/' + query));
@ -80,7 +79,7 @@ export async function get_search_results(query: string) {
];*/
}
export async function get_domain_result(domain: string, address?: string) {
export async function get_domain_result(domain: string, _address?: string) {
return Result.fromBackend(await call_api('get/' + domain));
/*await sleep(100);
if (domain === 'test.ton') {
@ -143,3 +142,12 @@ export class TonLink {
export function get_ton_link(res: Result) {
return new TonLink(res.zone(), 'b/' + res.domain, res.buy_price!);
}
export class SiteConstructorParams {
domain: string;
title: string;
constructor(domain: string, title: string = '') {
this.domain = domain;
this.title = title;
}
}

155
src/views/Explore.vue

@ -8,52 +8,52 @@
</button>
</router-link>
</template>
<DomainBar :value="core_domain" :zone="'.' + zone" :has_button="false" :editable="false"/>
<div v-if="loading" class="center">
<RotateSquare2 style="width: 5rem; height: 5rem; margin-top: 3rem;"/>
</div>
<div v-else>
<div class="owned" v-if="result.owner && !isMine">
<p class="domain">{{ domain }}</p>
<div>is owned by
<div class="owner-address">{{ ownerAddr }}</div>
</div>
<a :href="result.nft_info.explorer_link">View nft</a>
<div style="min-width: 50%">
<DomainBar :value="core_domain" :zone="'.' + zone" :has_button="false" :editable="false"/>
<div v-if="loading" class="center">
<RotateSquare2 style="width: 5rem; height: 5rem; margin-top: 3rem;"/>
</div>
<div v-else-if="isMine" class="owned">
<p class="domain">{{ domain }}</p>
<div>is owned by
<div class="owner-address">you</div>
</div>
<a :href="result.nft_info.explorer_link">View nft</a>
<br/>
<div id="wallet_input" class="rec-field">
<div style="display: flex; width: 100%">
<p style="width: 9rem">Wallet:</p>
<contenteditable class="record-inp" 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}" @click="saveWallet()">
Save
</div>
<div v-else>
<div class="owned" v-if="result.owner && !isMine">
<p class="domain">{{ domain }}</p>
<div>is owned by
<div class="owner-address">{{ ownerAddr }}</div>
</div>
<a :href="result.nft_info.explorer_link">View nft</a>
</div>
<div id="site_input" class="rec-field">
<div style="display: flex; width: 100%">
<p style="width: 9rem;">Site:</p>
<contenteditable class="record-inp" tag="div" :no-hl="true" :no-html="true" spellcheck="false"
v-model="site_rec"></contenteditable>
<div :class="{'record-submit': true, 'get_b': true, 'inactive': !siteChanged}" @click="saveSite()">Save
<div v-else-if="isMine" class="owned">
<p class="domain">{{ domain }}</p>
<div>is owned by
<div class="owner-address">you</div>
</div>
<a :href="result.nft_info.explorer_link">View nft</a>
<br/>
<div id="wallet_input" class="rec-field">
<div style="display: flex; width: 100%">
<p style="width: 9rem">Wallet:</p>
<contenteditable class="record-inp wallet-record-field" 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-else>
<Socket secondary-color="#a7aab3" color="#282e46" size="50px" style="min-width: 3rem"/>
Confirm in the wallet...
</template>
</div>
</div>
</div>
<SiteSettings ref="site_settings"
@save="saveSite()" @change="site_rec = $event" @change-constructor="constructor_params = $event"
:site-changed="siteChanged" :signing-site="signingSite"/>
</div>
<div v-else>
This domain is not owned.
<router-link :to="{name: 'Get', params: {domain_init: core_domain, zone: zone}}">
<button class="b darkish back">
Get it
</button>
</router-link>
</div>
</div>
<div v-else>
This domain is not owned.
<router-link :to="{name: 'Get', params: {domain_init: core_domain, zone: zone}}">
<button class="b darkish back">
Get it
</button>
</router-link>
</div>
</div>
</DarkLayout>
@ -63,38 +63,45 @@
import DarkLayout from "../components/DarkLayout.vue";
import DomainBar from "../components/DomainBar.vue";
import RotateSquare2 from "../components/RotateSquare2.vue";
import {get_domain_result, get_records} from "../result";
import {get_domain_result, get_records, SiteConstructorParams} from "../result";
import {convertAddress} from "../utils";
import contenteditable from 'vue-contenteditable';
import {call_api} from "../api";
import Socket from "../components/Socket.vue";
import SiteSettings from "../components/SiteSettings.vue";
export default {
name: "Explore",
components: {DomainBar, DarkLayout, RotateSquare2, contenteditable},
components: {SiteSettings, Socket, DomainBar, DarkLayout, RotateSquare2, contenteditable},
props: {
domain: {
type: String,
}
},
data() {
let saved_constructor_params = new SiteConstructorParams(this.domain, this.domain);
return {
result: null,
records: null,
records: {wallet: null, storage: null, uri: null, next_resolver: null, site: null},
wallet_rec: null,
site_rec: null,
signingSite: false,
signingWallet: false
signingWallet: false,
constructor_params: saved_constructor_params,
saved_constructor_params,
timer: ''
}
},
mounted() {
get_domain_result(this.domain, this.$store.getters.address).then(r => {
this.result = r;
setInterval(() => get_domain_result(this.domain, this.$store.getters.address).then(r => {
this.result = Object.assign({}, r);
if (this.isMine) {
get_records(r.nft_info.address).then(r => {
this.records = r;
// this.timer = setTimeout(this.updRecords, 10000);
})
}
})
}), 7000);
},
computed: {
core_domain() {
@ -122,6 +129,9 @@ export default {
},
siteChanged() {
return this.records && this.site_rec !== this.records.site;
},
settingsCompLoaded() {
return this.$refs.site_settings !== undefined;
}
},
methods: {
@ -148,12 +158,10 @@ export default {
console.log("Sending transaction", transaction);
const result = await this.$store.state.connector.sendTransaction(transaction);
this.signingWallet = false;
if(!result.boc) {
if (!result.boc) {
// todo
}
get_records(this.result.nft_info.address).then(r => {
this.records = r;
})
this.records.wallet = this.wallet_rec;
},
async saveSite() {
if (!this.siteChanged) {
@ -177,13 +185,22 @@ export default {
this.signingSite = true;
const result = await this.$store.state.connector.sendTransaction(transaction);
this.signingSite = false;
if(!result.boc) {
if (!result.boc) {
// todo
}
this.records.site = this.site_rec;
},
updRecords() {
get_records(this.result.nft_info.address).then(r => {
this.records = r;
if (this.records.wallet !== r.wallet || this.records.site !== r.site) {
this.records = r;
}
})
},
updSettingsComponent() {
this.$refs.site_settings.set_site_rec(this.site_rec);
this.$refs.site_settings.saved_constructor_params = this.saved_constructor_params;
}
},
watch: {
records: function (val) {
@ -191,6 +208,17 @@ export default {
this.wallet_rec = val.wallet;
this.site_rec = val.site;
}
},
site_rec () {
this.$refs.site_settings.set_site_rec(this.site_rec);
},
saved_constructor_params () {
this.$refs.site_settings.saved_constructor_params = this.saved_constructor_params;
},
settingsCompLoaded () {
if (!this.loading && this.settingsCompLoaded) {
this.updSettingsComponent();
}
}
}
}
@ -231,11 +259,30 @@ export default {
border-radius: 0.3rem;
background-color: #4e5a88;
color: white;
min-width: 50%;
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;
}
.wallet-record-field {
font-family: 'Inconsolata', monospace;
}
</style>
Loading…
Cancel
Save