mirror of
https://github.com/styppo/hamstr.git
synced 2024-10-18 21:43:25 +00:00
move LeftMenu to its own component, remove the notifications thing from before as it wasn't good enough, pre-step before saving events to ensure we don't save old metadata from people.
This commit is contained in:
parent
02e2fb8217
commit
c79859437e
@ -1,9 +1,11 @@
|
|||||||
|
import LeftMenu from '../components/LeftMenu.vue'
|
||||||
import Publish from '../components/Publish.vue'
|
import Publish from '../components/Publish.vue'
|
||||||
import Balloon from '../components/Balloon.vue'
|
import Balloon from '../components/Balloon.vue'
|
||||||
import Reply from '../components/Reply.vue'
|
import Reply from '../components/Reply.vue'
|
||||||
import Post from '../components/Post.vue'
|
import Post from '../components/Post.vue'
|
||||||
|
|
||||||
export default ({app}) => {
|
export default ({app}) => {
|
||||||
|
app.component('LeftMenu', LeftMenu)
|
||||||
app.component('Publish', Publish)
|
app.component('Publish', Publish)
|
||||||
app.component('Balloon', Balloon)
|
app.component('Balloon', Balloon)
|
||||||
app.component('Reply', Reply)
|
app.component('Reply', Reply)
|
||||||
|
118
src/components/LeftMenu.vue
Normal file
118
src/components/LeftMenu.vue
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<q-dialog v-model="dialogPublish">
|
||||||
|
<Publish />
|
||||||
|
</q-dialog>
|
||||||
|
|
||||||
|
<div class="hidden sm:flex w-1/4 justify-center px-8">
|
||||||
|
<q-card flat no-box-shadow class="text-xl">
|
||||||
|
<q-card-section class="flex justify-center">
|
||||||
|
<q-img src="/bird.png" fit="scale-down" width="80px" />
|
||||||
|
</q-card-section>
|
||||||
|
<q-list class="text-slate-700">
|
||||||
|
<q-item v-ripple clickable :to="'/'" active-class="">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-icon name="home" color="secondary" />
|
||||||
|
</q-item-section>
|
||||||
|
|
||||||
|
<q-item-section
|
||||||
|
:class="{
|
||||||
|
'text-primary': $route.name === 'home'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
Home
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-item v-ripple clickable :to="'/notifications'" active-class="">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-icon name="notifications" color="secondary" />
|
||||||
|
</q-item-section>
|
||||||
|
|
||||||
|
<q-item-section
|
||||||
|
:class="{'text-primary': $route.name === 'notifications'}"
|
||||||
|
>
|
||||||
|
Notifications
|
||||||
|
|
||||||
|
<q-badge
|
||||||
|
v-if="notifications.length"
|
||||||
|
color="primary"
|
||||||
|
floating
|
||||||
|
transparent
|
||||||
|
>
|
||||||
|
{{ notifications.length }}
|
||||||
|
</q-badge>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-item v-ripple clickable :to="'/messages'" active-class="">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-icon name="email" color="secondary" />
|
||||||
|
</q-item-section>
|
||||||
|
|
||||||
|
<q-item-section :class="{'text-primary': $route.name === 'messages'}">
|
||||||
|
Messages
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-item
|
||||||
|
v-ripple
|
||||||
|
clickable
|
||||||
|
:to="'/' + $store.state.keys.pub"
|
||||||
|
active-class=""
|
||||||
|
>
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-icon name="person" color="secondary" />
|
||||||
|
</q-item-section>
|
||||||
|
|
||||||
|
<q-item-section
|
||||||
|
:class="{
|
||||||
|
'text-primary':
|
||||||
|
$route.name === 'profile' &&
|
||||||
|
$route.params.pubkey === $store.state.keys.pub
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
Profile
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
|
<q-item v-ripple clickable :to="'/settings'" active-class="">
|
||||||
|
<q-item-section avatar>
|
||||||
|
<q-icon name="settings" color="secondary" />
|
||||||
|
</q-item-section>
|
||||||
|
|
||||||
|
<q-item-section :class="{'text-primary': $route.name === 'settings'}">
|
||||||
|
Settings
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
</q-list>
|
||||||
|
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<q-btn
|
||||||
|
rounded
|
||||||
|
unelevated
|
||||||
|
color="primary"
|
||||||
|
size="md"
|
||||||
|
label="Publish"
|
||||||
|
class="mx-2 my-4 py-2 px-4 w-full"
|
||||||
|
@click="dialogPublish = true"
|
||||||
|
></q-btn>
|
||||||
|
</div>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import helpersMixin from '../utils/mixin'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'LeftMenu',
|
||||||
|
mixins: [helpersMixin],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
notifications: [],
|
||||||
|
dialogPublish: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -35,7 +35,10 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-slate-500 cursor-pointer hover:underline text-xs">
|
<div
|
||||||
|
class="text-slate-500 cursor-pointer hover:underline text-xs"
|
||||||
|
@click="toEvent(event.id)"
|
||||||
|
>
|
||||||
{{ niceDate(event.created_at) }}
|
{{ niceDate(event.created_at) }}
|
||||||
</div>
|
</div>
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<q-input v-model="text" dense label="Say something" maxlength="280">
|
<q-input v-model="text" dense label="Say something" maxlength="280">
|
||||||
<template #before>
|
<template #before>
|
||||||
<q-btn round class="mr-3" @click="toProfile($store.state.keys.pub)">
|
<q-btn round class="mr-3" @click="toProfile($store.state.keys.pub)">
|
||||||
<q-avatar rounded size="42px">
|
<q-avatar round size="42px">
|
||||||
<img :src="$store.getters.avatar($store.state.keys.pub)" />
|
<img :src="$store.getters.avatar($store.state.keys.pub)" />
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
|
40
src/db.js
40
src/db.js
@ -68,6 +68,39 @@ db.upsert('_design/main', current => {
|
|||||||
db.viewCleanup().then(r => console.log('view cleanup done', r))
|
db.viewCleanup().then(r => console.log('view cleanup done', r))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// general function for saving an event, with granular logic for each kind
|
||||||
|
//
|
||||||
|
export async function dbSave(event) {
|
||||||
|
switch (event.kind) {
|
||||||
|
case 0: {
|
||||||
|
// first check if we don't have a newer metadata for this user
|
||||||
|
let current = await dbGetProfile(event.pubkey)
|
||||||
|
if (current.created_at >= event.created_at) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
break
|
||||||
|
case 4:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
event._id = event.id
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db.put(event)
|
||||||
|
} catch (err) {
|
||||||
|
if (err.name !== 'conflict') {
|
||||||
|
console.error('unexpected error saving event', event, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// db queries
|
// db queries
|
||||||
// ~
|
// ~
|
||||||
export async function dbGetHomeFeedNotes(
|
export async function dbGetHomeFeedNotes(
|
||||||
@ -202,12 +235,7 @@ export async function dbGetProfile(pubkey) {
|
|||||||
sorted
|
sorted
|
||||||
.slice(1)
|
.slice(1)
|
||||||
.filter(row => row.doc)
|
.filter(row => row.doc)
|
||||||
.forEach(row =>
|
.forEach(row => db.remove(row.doc))
|
||||||
db
|
|
||||||
.remove(row.doc)
|
|
||||||
.then(x => console.log('deleted', x))
|
|
||||||
.catch(e => console.log('failed to delete', e))
|
|
||||||
)
|
|
||||||
return sorted[0].doc
|
return sorted[0].doc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,110 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-layout>
|
<q-layout>
|
||||||
<q-dialog v-model="dialogPublish">
|
|
||||||
<Publish />
|
|
||||||
</q-dialog>
|
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="hidden sm:flex w-1/4 justify-center px-8">
|
<LeftMenu />
|
||||||
<q-card flat no-box-shadow class="text-xl">
|
|
||||||
<q-card-section class="flex justify-center">
|
|
||||||
<q-img src="/bird.png" fit="scale-down" width="80px" />
|
|
||||||
</q-card-section>
|
|
||||||
<q-list class="text-slate-700">
|
|
||||||
<q-item v-ripple clickable :to="'/'" active-class="">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="home" color="secondary" />
|
|
||||||
</q-item-section>
|
|
||||||
|
|
||||||
<q-item-section
|
|
||||||
:class="{
|
|
||||||
'text-primary': $route.name === 'home'
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
Home
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-item v-ripple clickable :to="'/notifications'" active-class="">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="notifications" color="secondary" />
|
|
||||||
</q-item-section>
|
|
||||||
|
|
||||||
<q-item-section
|
|
||||||
:class="{'text-primary': $route.name === 'notifications'}"
|
|
||||||
>
|
|
||||||
Notifications
|
|
||||||
|
|
||||||
<q-badge
|
|
||||||
v-if="Object.keys($store.state.notifications).length"
|
|
||||||
color="primary"
|
|
||||||
floating
|
|
||||||
transparent
|
|
||||||
>
|
|
||||||
{{ Object.keys($store.state.notifications).length }}
|
|
||||||
</q-badge>
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-item v-ripple clickable :to="'/messages'" active-class="">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="email" color="secondary" />
|
|
||||||
</q-item-section>
|
|
||||||
|
|
||||||
<q-item-section
|
|
||||||
:class="{'text-primary': $route.name === 'messages'}"
|
|
||||||
>
|
|
||||||
Messages
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-item
|
|
||||||
v-ripple
|
|
||||||
clickable
|
|
||||||
:to="'/' + $store.state.keys.pub"
|
|
||||||
active-class=""
|
|
||||||
>
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="person" color="secondary" />
|
|
||||||
</q-item-section>
|
|
||||||
|
|
||||||
<q-item-section
|
|
||||||
:class="{
|
|
||||||
'text-primary':
|
|
||||||
$route.name === 'profile' &&
|
|
||||||
$route.params.pubkey === $store.state.keys.pub
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
Profile
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-item v-ripple clickable :to="'/settings'" active-class="">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="settings" color="secondary" />
|
|
||||||
</q-item-section>
|
|
||||||
|
|
||||||
<q-item-section
|
|
||||||
:class="{'text-primary': $route.name === 'settings'}"
|
|
||||||
>
|
|
||||||
Settings
|
|
||||||
</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
|
|
||||||
<div class="flex justify-center">
|
|
||||||
<q-btn
|
|
||||||
rounded
|
|
||||||
unelevated
|
|
||||||
color="primary"
|
|
||||||
size="md"
|
|
||||||
label="Publish"
|
|
||||||
class="mx-2 my-4 py-2 px-4 w-full"
|
|
||||||
@click="dialogPublish = true"
|
|
||||||
></q-btn>
|
|
||||||
</div>
|
|
||||||
</q-card>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-full sm:w-3/4 lg:w-2/4 pl-4">
|
<div class="w-full sm:w-3/4 lg:w-2/4 pl-4">
|
||||||
<q-page-container>
|
<q-page-container>
|
||||||
@ -173,8 +70,6 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dialogGenerate: false,
|
|
||||||
dialogPublish: false,
|
|
||||||
searchingProfile: ''
|
searchingProfile: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-left items-center mt-4">
|
<div class="flex justify-left items-center mt-4">
|
||||||
<q-avatar rounded>
|
<q-avatar round>
|
||||||
<img :src="$store.getters.avatar($route.params.pubkey)" />
|
<img :src="$store.getters.avatar($route.params.pubkey)" />
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
<div class="ml-4">
|
<div class="ml-4">
|
||||||
|
@ -2,7 +2,7 @@ import {encrypt, decrypt} from 'nostr-tools/nip04'
|
|||||||
import {Notify} from 'quasar'
|
import {Notify} from 'quasar'
|
||||||
|
|
||||||
import {pool} from '../pool'
|
import {pool} from '../pool'
|
||||||
import {db, dbGetProfile} from '../db'
|
import {dbSave, dbGetProfile} from '../db'
|
||||||
|
|
||||||
export function launch(store) {
|
export function launch(store) {
|
||||||
if (!store.state.keys.pub) {
|
if (!store.state.keys.pub) {
|
||||||
@ -177,24 +177,15 @@ export async function sendChatMessage(store, {pubkey, text, replyTo}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function addEvent(store, event) {
|
export async function addEvent(store, event) {
|
||||||
event._id = event.id
|
await dbSave(event)
|
||||||
|
|
||||||
db.put(event).catch(err => {
|
|
||||||
if (err.name === 'conflict') return
|
|
||||||
console.error(err)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
// do things after the event is saved
|
||||||
switch (event.kind) {
|
switch (event.kind) {
|
||||||
case 0:
|
case 0:
|
||||||
// this will reset the profile cache for this URL
|
// this will reset the profile cache for this URL
|
||||||
store.dispatch('useProfile', event.pubkey)
|
store.dispatch('useProfile', event.pubkey)
|
||||||
break
|
break
|
||||||
case 1:
|
case 1:
|
||||||
if (
|
|
||||||
event.tags.find(([t, v]) => t === 'p' && v === store.state.keys.pub)
|
|
||||||
) {
|
|
||||||
store.dispatch('addNotification', event)
|
|
||||||
}
|
|
||||||
break
|
break
|
||||||
case 2:
|
case 2:
|
||||||
break
|
break
|
||||||
|
@ -92,7 +92,3 @@ export function addProfileToCache(state, event) {
|
|||||||
state.me = JSON.parse(event.content)
|
state.me = JSON.parse(event.content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addNotification(state, event) {
|
|
||||||
state.notifications[event.id] = true
|
|
||||||
}
|
|
||||||
|
@ -8,8 +8,6 @@ export default function () {
|
|||||||
following: LocalStorage.getItem('following') || [], // [ pubkeys... ]
|
following: LocalStorage.getItem('following') || [], // [ pubkeys... ]
|
||||||
|
|
||||||
profilesCache: {}, // { [pubkey]: {name, about, picture, ...} }
|
profilesCache: {}, // { [pubkey]: {name, about, picture, ...} }
|
||||||
profilesCacheLRU: [], // [ pubkeys... ]
|
profilesCacheLRU: [] // [ pubkeys... ]
|
||||||
|
|
||||||
notifications: {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user