add vuejs test ui for search with dvms (very basic for now)

This commit is contained in:
Believethehype
2024-01-15 20:41:23 +01:00
parent 0fec71373a
commit 072ee01460
24 changed files with 966 additions and 0 deletions

View File

@ -0,0 +1,29 @@
# vue
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Compile and Minify for Production
```sh
npm run build
```

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

View File

@ -0,0 +1,8 @@
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
},
"exclude": ["node_modules", "dist"]
}

View File

@ -0,0 +1,26 @@
{
"name": "vue",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@rust-nostr/nostr-sdk": "^0.7.0",
"mini-toastr": "^0.8.1",
"vue": "^3.3.11",
"vue-notifications": "^1.0.2",
"vue3-easy-data-table": "^1.5.47",
"vuex": "^4.1.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.5.2",
"vite": "^5.0.10"
},
"optionalDependencies": {
"@rollup/rollup-linux-x64-gnu": "4.6.1"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,49 @@
<script setup>
import Search from './components/Search.vue'
import Nip07 from './components/Nip07.vue'
import ResultsTable from "@/components/ResultTable.vue";
</script>
<template>
<main>
<img alt="Nostr logo" class="logo" src="./assets/nostr-purple.svg" width="125" height="125" />
<Search/>
<br>
<ResultsTable></ResultsTable>
<Nip07>
</Nip07>
</main>
</template>
<style>
header {
line-height: 1.5;
}
.logo {
display: block;
margin: 0 auto 2rem;
}
@media (min-width: 1024px) {
header {
display: flex;
place-items: center;
padding-right: calc(var(--section-gap) / 2);
}
.logo {
margin: 0 2rem 0 0;
}
header .wrapper {
display: flex;
place-items: flex-start;
flex-wrap: wrap;
}
}
</style>

View File

@ -0,0 +1,86 @@
/* color palette from <https://github.com/vuejs/theme> */
:root {
--vt-c-white: #ffffff;
--vt-c-white-soft: #f8f8f8;
--vt-c-white-mute: #f2f2f2;
--vt-c-black: #181818;
--vt-c-black-soft: #222222;
--vt-c-black-mute: #282828;
--vt-c-indigo: #2c3e50;
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
--vt-c-text-light-1: var(--vt-c-indigo);
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
--vt-c-text-dark-1: var(--vt-c-white);
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
}
/* semantic color variables for this project */
:root {
--color-background: var(--vt-c-white);
--color-background-soft: var(--vt-c-white-soft);
--color-background-mute: var(--vt-c-white-mute);
--color-border: var(--vt-c-divider-light-2);
--color-border-hover: var(--vt-c-divider-light-1);
--color-heading: var(--vt-c-text-light-1);
--color-text: var(--vt-c-text-light-1);
--section-gap: 160px;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: var(--vt-c-black);
--color-background-soft: var(--vt-c-black-soft);
--color-background-mute: var(--vt-c-black-mute);
--color-border: var(--vt-c-divider-dark-2);
--color-border-hover: var(--vt-c-divider-dark-1);
--color-heading: var(--vt-c-text-dark-1);
--color-text: var(--vt-c-text-dark-2);
}
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
font-weight: normal;
}
body {
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
transition:
color 0.5s,
background-color 0.5s;
line-height: 1.6;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Fira Sans',
'Droid Sans',
'Helvetica Neue',
sans-serif;
font-size: 15px;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 KiB

View File

@ -0,0 +1,35 @@
@import './base.css';
#app {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
font-weight: normal;
}
a,
.green {
text-decoration: none;
color: hsla(160, 100%, 37%, 1);
transition: 0.4s;
padding: 3px;
}
@media (hover: hover) {
a:hover {
background-color: hsla(160, 100%, 37%, 0.2);
}
}
@media (min-width: 1024px) {
body {
display: flex;
place-items: center;
}
#app {
display: grid;
grid-template-columns: 1fr 1fr;
padding: 0 2rem;
}
}

View File

@ -0,0 +1,10 @@
<svg width="225" height="224" viewBox="0 0 225 224" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="224.047" height="224" rx="64" fill="url(#paint0_radial_855_5166)"/>
<path d="M162.441 135.941V88.0593C170.359 85.1674 176 77.5348 176 68.6696C176 57.2919 166.708 48 155.33 48C143.953 48 134.661 57.2444 134.661 68.6696C134.661 77.5822 140.302 85.1674 148.219 88.0593V135.941C147.698 136.13 147.176 136.367 146.655 136.604L87.3956 77.3452C88.6282 74.6904 89.2919 71.7511 89.2919 68.6696C89.2919 57.2444 80.0474 48 68.6696 48C57.2919 48 48 57.2444 48 68.6696C48 77.5822 53.6415 85.1674 61.5585 88.0593V135.941C53.6415 138.833 48 146.465 48 155.33C48 166.708 57.2444 176 68.6696 176C80.0948 176 89.3393 166.708 89.3393 155.33C89.3393 146.418 83.6978 138.833 75.7807 135.941V88.0593C76.3022 87.8696 76.8237 87.6326 77.3452 87.3956L136.604 146.655C135.372 149.31 134.708 152.249 134.708 155.33C134.708 166.708 143.953 176 155.378 176C166.803 176 176.047 166.708 176.047 155.33C176.047 146.418 170.406 138.833 162.489 135.941H162.441Z" fill="white"/>
<defs>
<radialGradient id="paint0_radial_855_5166" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(224.047 224) rotate(-135.006) scale(316.817 473.813)">
<stop stop-color="#6951FA"/>
<stop offset="1" stop-color="#9151FA"/>
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,174 @@
<template>
<div>
<div class="playeauthor-wrapper" v-if="current_user">
<img class="avatar" :src="this.avatar" alt="" />
<p>Current User is: {{ this.current_user }}</p>
</div>
<template v-if="current_user">
<button class="b-Button" @click="sign_out()">Sign out</button>
</template>
<template v-if="!current_user">
<button class="c-Button" @click="sign_in()">Sign in</button>
</template>
</div>
</template>
<script>
import {
loadWasmAsync,
Client,
ClientSigner,
Nip07Signer,
Filter,
initLogger,
LogLevel,
Timestamp
} from "@rust-nostr/nostr-sdk";
import VueNotifications from "vue-notifications";
import store from '../store';
export default {
data() {
return {
current_user: "",
avatar: "",
signer: "",
};
},
async mounted() {
await this.sign_in();
},
notifications: {
showSuccessMsg: {
type: VueNotifications.types.success,
title: 'Login',
message: 'That\'s the success!'
},
showInfoMsg: {
type: VueNotifications.types.info,
title: 'Hey you',
message: 'Here is some info for you'
},
showWarnMsg: {
type: VueNotifications.types.warn,
title: 'Wow, man',
message: 'That\'s the kind of warning'
},
showErrorMsg: {
type: VueNotifications.types.error,
title: 'Wow-wow',
message: 'That\'s the error'
}
},
methods: {
async sign_in() {
try {
await loadWasmAsync();
try {
initLogger(LogLevel.debug());
} catch (error) {
console.log(error);
}
let nip07_signer = new Nip07Signer();
this.signer = ClientSigner.nip07(nip07_signer);
let client = new Client(this.signer);
//await client.addRelay("wss://relay.damus.io");
//await client.addRelay("wss://nos.lol");
await client.addRelay("wss://relay.nostr.band");
await client.addRelay("wss://nostr-pub.wellorder.net")
const pubkey = await nip07_signer.getPublicKey()
await client.connect();
store.commit('set_client', client)
console.log("Client connected")
await this.get_user_info(pubkey)
//this.current_user = (await nip07_signer.getPublicKey()).toBech32()
//console.log( this.current_user)
this.showSuccessMsg()
} catch (error) {
console.log(error);
}
},
async get_user_info(pubkey){
let client = store.state.client
const profile_filter = new Filter().kind(0).author(pubkey).limit(1)
let evts = await client.getEventsOf([profile_filter], 10)
console.log("PROFILES:" + evts.length)
if (evts.length > 0){
let latest_entry = evts[0]
let latest_time = 0
for (const entry of evts){
if (entry.createdAt.asSecs() > latest_time){
latest_time = entry.createdAt.asSecs();
latest_entry = entry
}
}
let profile = JSON.parse(latest_entry.content);
this.current_user = profile["name"]
this.avatar = profile["picture"]
}
},
async sign_out(){
this.current_user = ""
}
},
};
</script>
<style scoped>
.operation-wrapper .operation-icon {
width: 20px;
cursor: pointer;
}
.playeauthor-wrapper {
padding: 5px;
display: flex;
align-items: center;
justify-items: center;
}
.avatar {
margin-right: 10px;
display: inline-block;
width: 30px;
height: 30px;
border-radius: 50%;
object-fit: cover;
box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 10%);
}
.b-Button {
height: 30px;
color: white;
background: purple;
}
.c-Button {
height: 30px;
color: white;
background: #8e30eb;
}
</style>

View File

@ -0,0 +1,142 @@
<script setup>
import {EventId, Filter, PublicKey} from "@rust-nostr/nostr-sdk";
import store from '../store';
import {computed, onMounted, ref, watch} from "vue";
const props = defineProps({
content: {
type: String,
required: true
},
author: {
type: String,
required: true
},
avatar: {
type: String,
required: true
},
authorurl: {
type: String,
required: true
},
})
async function getEvent(eventid){
const event_filter = new Filter().id(EventId.fromHex(eventid)).limit(1)
let client = store.state.client
let evts = await client.getEventsOf([event_filter], 5)
return evts[0]
}
async function parseContent(pubkey) {
let name = PublicKey.fromHex(pubkey).toBech32()
let nip05 = ""
let lud16 = ""
let picture = ""
const profile_filter = new Filter().kind(0).author(PublicKey.fromHex(pubkey)).limit(1)
let client = store.state.client
let evts = await client.getEventsOf([profile_filter], 5)
console.log("PROFILES:" + evts.length)
if (evts.length > 0) {
let latest_entry = evts[0]
let latest_time = 0
for (const entry of evts) {
if (entry.createdAt.asSecs() > latest_time) {
latest_time = entry.createdAt.asSecs();
latest_entry = entry
}
}
let profile = JSON.parse(latest_entry.content);
name = profile["name"]
picture = profile["picture"]
console.log(picture)
return name
}
}
async function get_user_info(pubkey){
let client = store.state.client
const profile_filter = new Filter().kind(0).author(PublicKey.fromHex(pubkey)).limit(1)
let evts = await client.getEventsOf([profile_filter], 10)
console.log("PROFILES:" + evts.length)
if (evts.length > 0){
let latest_entry = evts[0]
let latest_time = 0
for (const entry of evts){
if (entry.createdAt.asSecs() > latest_time){
latest_time = entry.createdAt.asSecs();
latest_entry = entry
}
}
return JSON.parse(latest_entry.content);
}
}
const content_placeholder = ref()
const author_placeholder = ref()
const author_image_placeholder = ref()
onMounted(async () => {
content_placeholder.value = "Event not found"
author_placeholder.value = ""
author_image_placeholder.value = ""
content_placeholder.value = props.content //TODO furher parse content
console.log(props.author)
const profile = await get_user_info(props.author)
console.log(profile)
author_placeholder.value = profile["name"]
author_image_placeholder.value = profile["picture"]
})
</script>
<template><div class="playeauthor-wrapper">
<img class="avatar" :src="author_image_placeholder" alt="" />
<a :href="author_placeholder">{{ author_placeholder}}</a> </div>
<p>{{ content_placeholder }}</p>
</template>
<style scoped>
.operation-wrapper .operation-icon {
width: 20px;
cursor: pointer;
}
.playeauthor-wrapper {
padding: 5px;
display: flex;
align-items: center;
justify-items: center;
}
.avatar {
margin-right: 10px;
display: inline-block;
width: 30px;
height: 30px;
border-radius: 50%;
object-fit: cover;
box-shadow: inset 0 2px 4px 0 rgb(0 0 0 / 10%);
}
</style>

View File

@ -0,0 +1,70 @@
<template>
<EasyDataTable table-class-name="customize-table"
:headers="headers"
:items="store.state.results">
<template #item-content="{ content, author}">
<NoteRender :content="content" :author="author"/>
</template>
</EasyDataTable>
</template>
<script lang="ts" setup>
import type { Header, Item } from "vue3-easy-data-table";
import store from '../store';
import NoteRender from "@/components/NoteRender.vue";
import {EventId, Filter} from "@rust-nostr/nostr-sdk";
const headers: Header[] = [
{ text: "Results:", value: "content", width: 400},
{ text: "Time", value: "indicator.time", sortable: true},
];
</script>
<style>
.customize-table {
--easy-table-border: 1px solid #445269;
--easy-table-row-border: 1px solid #445269;
--easy-table-header-font-size: 14px;
--easy-table-header-height: 50px;
--easy-table-header-font-color: #c1cad4;
--easy-table-header-background-color: #2d3a4f;
--easy-table-header-item-padding: 10px 15px;
--easy-table-body-even-row-font-color: #fff;
--easy-table-body-even-row-background-color: #4c5d7a;
--easy-table-body-row-font-color: #c0c7d2;
--easy-table-body-row-background-color: #2d3a4f;
--easy-table-body-row-height: 50px;
--easy-table-body-row-font-size: 14px;
--easy-table-body-row-hover-font-color: #2d3a4f;
--easy-table-body-row-hover-background-color: #eee;
--easy-table-body-item-padding: 10px 15px;
--easy-table-footer-background-color: #2d3a4f;
--easy-table-footer-font-color: #c0c7d2;
--easy-table-footer-font-size: 14px;
--easy-table-footer-padding: 0px 10px;
--easy-table-footer-height: 50px;
--easy-table-rows-per-page-selector-width: 70px;
--easy-table-rows-per-page-selector-option-padding: 10px;
--easy-table-rows-per-page-selector-z-index: 1;
--easy-table-scrollbar-track-color: #2d3a4f;
--easy-table-scrollbar-color: #2d3a4f;
--easy-table-scrollbar-thumb-color: #4c5d7a;;
--easy-table-scrollbar-corner-color: #2d3a4f;
--easy-table-loading-mask-background-color: #2d3a4f;
}
</style>

View File

@ -0,0 +1,203 @@
<script setup>
import {Client, Filter, Timestamp, Event, Metadata, PublicKey, EventBuilder, Tag, EventId} from "@rust-nostr/nostr-sdk";
import store from '../store';
let items = []
async function get_some_stuff(message) {
try {
if (message === undefined){
message = "Nostr"
}
//console.log( store.state.test + " " + message)
const filter = new Filter().kind(1).limit(20).search(message);
//console.log('filter', filter.asJson());
let client = store.state.client
let events = await client.getEventsOf([filter], 3);
//console.log(events.length)
let items = []
for (const e of events) {
let name = e.pubkey.toBech32()
let nip05 = ""
let lud16 = ""
let picture = ""
//console.log(e.pubkey.toHex())
const profile_filter = new Filter().kind(0).author(e.pubkey).limit(1)
let evts = await client.getEventsOf([profile_filter], 5)
if (evts.length > 0){
let latest_entry = evts[0]
let latest_time = 0
for (const entry of evts){
if (entry.createdAt.asSecs() > latest_time){
latest_time = entry.createdAt.asSecs();
latest_entry = entry
}
}
let profile = JSON.parse(latest_entry.content);
name = profile["name"]
picture = profile["picture"]
}
items.push({ content: e.content, author: name, authorurl: "https://njump.me/" + e.pubkey.toBech32(), avatar:
picture, indicator: {"time": e.createdAt.toHumanDatetime()}})
//console.log(e.asJson())
}
store.commit('set_search_results', items)
//await client.publishTextNote("Test from Rust Nostr SDK JavaScript bindings with NIP07 signer!", []);
} catch (error) {
console.log(error);
}
}
async function send_search_request(message) {
try {
if (message === undefined){
message = "Nostr"
}
items = []
let client = store.state.client
let tags = []
tags.push(Tag.parse(["i", message, "text"]))
let evt = new EventBuilder(5302, "Search for me", tags)
let res = await client.sendEventBuilder(evt)
console.log(res)
await this.listen()
} catch (error) {
console.log(error);
}
}
async function getEvents(eventids) {
const event_filter = new Filter().ids(eventids)
let client = store.state.client
return await client.getEventsOf([event_filter], 5)
}
async function listen() {
let client = store.state.client
const filter = new Filter().kinds([7000, 6302]).since(Timestamp.now());
await client.subscribe([filter]);
const handle = {
// Handle event
handleEvent: async (relayUrl, event) => {
console.log("Received new event from", relayUrl);
if (event.kind === 7000) {
try {
console.log("7000:", event.content);
//if (content === "stop") {
// return true
//}
} catch (error) {
console.log("Error: ", error);
}
}
else if(event.kind === 6302) {
let entries = []
console.log("6302:", event.content);
let event_etags = JSON.parse(event.content)
for (let etag of event_etags){
const eventid = EventId.fromHex(etag[1])
entries.push(eventid)
}
const events = await getEvents(entries)
for (const evt of events){
items.push({ content: evt.content, author: evt.author.toHex(), indicator: {"time": evt.createdAt.toHumanDatetime()}})
}
store.commit('set_search_results', items)
}
},
// Handle relay message
handleMsg: async (relayUrl, message) => {
//console.log("Received message from", relayUrl, message.asJson());
}
};
client.handleNotifications(handle);
}
defineProps({
msg: {
type: String,
required: false
},
})
</script>
<template>
<div class="greetings">
<h1 class="purple">Noogle</h1>
<h3>
<div>
<button class="c-Button" @click="send_search_request(message)">Search the Nostr
</button> <input class="c-Input" v-model="message" >
</div>
<!--
<a href="https://vitejs.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. -->
</h3>
</div>
</template>
<style scoped>
.c-Button {
height: 50px;
color: white;
background: #8e30eb;
}
.c-Input {
margin: -5px;
width: 400px;
height: 48px;
color: white;
background: black;
}
h1 {
font-weight: 500;
font-size: 2.6rem;
position: relative;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>

View File

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
/>
</svg>
</template>

View File

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
<path
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
/>
</svg>
</template>

View File

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
<path
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
/>
</svg>
</template>

View File

@ -0,0 +1,7 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
/>
</svg>
</template>

View File

@ -0,0 +1,19 @@
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--mdi"
width="24"
height="24"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>
<path
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
fill="currentColor"
></path>
</svg>
</template>

View File

@ -0,0 +1,30 @@
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
import store from './store';
import Vue3EasyDataTable from 'vue3-easy-data-table';
import 'vue3-easy-data-table/dist/style.css';
//This is all for notifications
import VueNotifications from 'vue-notifications'
import miniToastr from 'mini-toastr'
miniToastr.init()
function toast ({title, message, type, timeout, cb}) {
return miniToastr[type](message, title, timeout, cb)
}
const options = {
success: toast,
error: toast,
info: toast,
warn: toast
}
//This is all for notifications end
createApp(App).use(VueNotifications, options).use(store).component('EasyDataTable', Vue3EasyDataTable).mount('#app')

View File

@ -0,0 +1,28 @@
import {createStore} from "vuex";
import {Client} from "@rust-nostr/nostr-sdk";
const store = createStore({
state () {
return {
count: 0,
test: "hello",
client: Client,
results: []
}
},
mutations: {
increment (state) {
state.count++
},
set_client (state, client) {
state.client = client
},
set_search_results(state, results){
state.results = results
console.log(state.results)
}
}
})
export default store;

View File

@ -0,0 +1,16 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})