mirror of
https://github.com/believethehype/nostrdvm.git
synced 2025-07-01 06:20:41 +02:00
add vuejs test ui for search with dvms (very basic for now)
This commit is contained in:
29
tests/gui/vuejs/noogle/README.md
Normal file
29
tests/gui/vuejs/noogle/README.md
Normal 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
|
||||
```
|
13
tests/gui/vuejs/noogle/index.html
Normal file
13
tests/gui/vuejs/noogle/index.html
Normal 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>
|
8
tests/gui/vuejs/noogle/jsconfig.json
Normal file
8
tests/gui/vuejs/noogle/jsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
26
tests/gui/vuejs/noogle/package.json
Normal file
26
tests/gui/vuejs/noogle/package.json
Normal 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"
|
||||
}
|
||||
}
|
BIN
tests/gui/vuejs/noogle/public/favicon.ico
Normal file
BIN
tests/gui/vuejs/noogle/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
49
tests/gui/vuejs/noogle/src/App.vue
Normal file
49
tests/gui/vuejs/noogle/src/App.vue
Normal 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>
|
86
tests/gui/vuejs/noogle/src/assets/base.css
Normal file
86
tests/gui/vuejs/noogle/src/assets/base.css
Normal 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;
|
||||
}
|
BIN
tests/gui/vuejs/noogle/src/assets/delete.png
Normal file
BIN
tests/gui/vuejs/noogle/src/assets/delete.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 211 B |
BIN
tests/gui/vuejs/noogle/src/assets/edit.png
Normal file
BIN
tests/gui/vuejs/noogle/src/assets/edit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 545 B |
BIN
tests/gui/vuejs/noogle/src/assets/load.gif
Normal file
BIN
tests/gui/vuejs/noogle/src/assets/load.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 819 KiB |
35
tests/gui/vuejs/noogle/src/assets/main.css
Normal file
35
tests/gui/vuejs/noogle/src/assets/main.css
Normal 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;
|
||||
}
|
||||
}
|
10
tests/gui/vuejs/noogle/src/assets/nostr-purple.svg
Normal file
10
tests/gui/vuejs/noogle/src/assets/nostr-purple.svg
Normal 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 |
174
tests/gui/vuejs/noogle/src/components/Nip07.vue
Normal file
174
tests/gui/vuejs/noogle/src/components/Nip07.vue
Normal 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>
|
142
tests/gui/vuejs/noogle/src/components/NoteRender.vue
Normal file
142
tests/gui/vuejs/noogle/src/components/NoteRender.vue
Normal 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>
|
70
tests/gui/vuejs/noogle/src/components/ResultTable.vue
Normal file
70
tests/gui/vuejs/noogle/src/components/ResultTable.vue
Normal 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>
|
203
tests/gui/vuejs/noogle/src/components/Search.vue
Normal file
203
tests/gui/vuejs/noogle/src/components/Search.vue
Normal 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>
|
@ -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>
|
@ -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>
|
@ -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>
|
@ -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>
|
19
tests/gui/vuejs/noogle/src/components/icons/IconTooling.vue
Normal file
19
tests/gui/vuejs/noogle/src/components/icons/IconTooling.vue
Normal 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>
|
30
tests/gui/vuejs/noogle/src/main.js
Normal file
30
tests/gui/vuejs/noogle/src/main.js
Normal 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')
|
28
tests/gui/vuejs/noogle/src/store.js
Normal file
28
tests/gui/vuejs/noogle/src/store.js
Normal 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;
|
16
tests/gui/vuejs/noogle/vite.config.js
Normal file
16
tests/gui/vuejs/noogle/vite.config.js
Normal 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))
|
||||
}
|
||||
}
|
||||
})
|
Reference in New Issue
Block a user