mirror of
https://github.com/styppo/hamstr.git
synced 2024-10-18 13:33:22 +00:00
Some search box styling, mock trends
This commit is contained in:
parent
028e870f5f
commit
bcde6aa0b3
@ -54,10 +54,6 @@ export default defineComponent({
|
||||
display: flex;
|
||||
align-items: center;
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
line-height: unset;
|
||||
letter-spacing: unset;
|
||||
margin: .5rem 0;
|
||||
}
|
||||
.back-button {
|
||||
|
@ -159,6 +159,7 @@ export default {
|
||||
&-content {
|
||||
margin-left: 12px;
|
||||
flex-grow: 1;
|
||||
max-width: 570px;
|
||||
&-header {
|
||||
.in-reply-to {
|
||||
color: $color-dark-gray;
|
||||
|
@ -8,34 +8,149 @@
|
||||
<BaseIcon icon="search" />
|
||||
</div>
|
||||
<div class="searchbox-input">
|
||||
<form @submit="searchProfile">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search Profiles"
|
||||
placeholder="Search Hamstr"
|
||||
v-model="query"
|
||||
@focus="toggleFocus"
|
||||
@blur="toggleFocus"
|
||||
>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="domainMode">
|
||||
<div class="flex row justify-between no-wrap">
|
||||
<h2 class="text-h6 text-bold q-my-none"> {{ domain }} {{ $t('users') }}</h2>
|
||||
<q-btn icon="close" @click.stop="domainMode = false" />
|
||||
</div>
|
||||
<div v-if="domainDefaultPubkey">
|
||||
<h2 class="text-caption text-bold q-my-none"> {{ $t('nip05Maintainer') }} </h2>
|
||||
<BaseUserCard :pubkey="domainDefaultPubkey"/>
|
||||
</div>
|
||||
<q-list class="q-pt-xs q-pl-sm" style="overflow-y: auto; max-height: 40vh;">
|
||||
<div v-for="user in domainUsers" :key="user.pubkey">
|
||||
<BaseUserCard :pubkey="user.pubkey" />
|
||||
</div>
|
||||
</q-list>
|
||||
<q-separator color='accent' />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BaseIcon from 'components/BaseIcon'
|
||||
import {Notify} from 'quasar'
|
||||
import {searchDomain, queryName} from 'nostr-tools/nip05'
|
||||
import helpersMixin from 'src/utils/mixin'
|
||||
|
||||
export default {
|
||||
name: 'SearchBar',
|
||||
name: 'SearchBox',
|
||||
components: {
|
||||
BaseIcon,
|
||||
},
|
||||
mixins: [helpersMixin],
|
||||
data() {
|
||||
return {
|
||||
isFocused: false
|
||||
isFocused: false,
|
||||
query: '',
|
||||
searching: false,
|
||||
domainMode: false,
|
||||
domainNames: {},
|
||||
profilesUsed: new Set(),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
validSearch() {
|
||||
if (this.query === '') return true
|
||||
if (this.query.match(/^[a-f0-9A-F]{64}$/)) return true
|
||||
if (this.isBech32Key(this.query) && this.bech32ToHex(this.query).match(/^[a-f0-9A-F]{64}$/)) return true
|
||||
if (this.query.match(/^([a-z0-9A-Z-_.\u00C0-\u1FFF\u2800-\uFFFD]*@)?[a-z0-9A-Z-_]+[.]{1}[a-z0-9A-Z-_.]+$/)) return true
|
||||
return false
|
||||
},
|
||||
domainDefaultPubkey() {
|
||||
return this.domainNames._
|
||||
},
|
||||
domainUsers() {
|
||||
let users = Object.keys(this.domainNames).filter((name) => name !== '_').map((name) => { return { 'name': name, 'pubkey': this.domainNames[name] } })
|
||||
return users
|
||||
},
|
||||
domain() {
|
||||
let [name, domain] = this.query.split('@')
|
||||
return domain || name
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleFocus() {
|
||||
this.isFocused = !this.isFocused
|
||||
},
|
||||
async searchProfile(e) {
|
||||
e.preventDefault()
|
||||
|
||||
if (!this.validSearch) {
|
||||
Notify.create({
|
||||
message: 'Invalid format! Please enter full public key or NIP05 identifier',
|
||||
color: 'negative'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.searching = true
|
||||
this.query = this.query.trim().toLowerCase()
|
||||
|
||||
if (this.query.match(/^[a-f0-9]{64}$/)) {
|
||||
this.toProfile(this.query)
|
||||
this.query = ''
|
||||
this.searching = false
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isBech32Key(this.query) && this.bech32ToHex(this.query).match(/^[a-f0-9A-F]{64}$/)) {
|
||||
this.toProfile(this.bech32ToHex(this.query))
|
||||
this.query = ''
|
||||
this.searching = false
|
||||
return
|
||||
}
|
||||
|
||||
if (this.query.match(/^([a-z0-9-_.\u00C0-\u1FFF\u2800-\uFFFD]*@)?[a-z0-9-_.]+[.]{1}[a-z0-9-_.]+$/)) {
|
||||
// if (!this.query.match(/^[a-z0-9-_.\u00C0-\u1FFF\u2800-\uFFFD]?@/)) {
|
||||
if (this.query.match(/^@/) || !this.query.match(/@/)) {
|
||||
// this.query = '_' + this.query
|
||||
// else if (!this.query.match(/@/)) this.query = '_@' + this.query
|
||||
this.domainNames = await searchDomain(this.domain)
|
||||
// this.domainUsers
|
||||
if (this.domainUsers.length || this.domainDefaultPubkey) {
|
||||
if (this.domainDefaultPubkey) this.useProfile(this.domainDefaultPubkey)
|
||||
if (this.domainUsers.length) this.domainUsers.forEach((user) => this.useProfile(user.pubkey))
|
||||
this.searching = false
|
||||
this.domainMode = true
|
||||
return
|
||||
}
|
||||
}
|
||||
// }
|
||||
console.log('this.domainUsers', this.domainUsers)
|
||||
let pubkey = await queryName(this.query)
|
||||
console.log('queryName returned: ', pubkey)
|
||||
if (pubkey) {
|
||||
this.toProfile(pubkey)
|
||||
this.query = ''
|
||||
this.searching = false
|
||||
return
|
||||
}
|
||||
}
|
||||
this.searching = false
|
||||
Notify.create({
|
||||
message: 'No user found! Please enter full public key or NIP05 identifier and double check search string',
|
||||
color: 'negative'
|
||||
})
|
||||
},
|
||||
useProfile(pubkey) {
|
||||
if (this.profilesUsed.has(pubkey)) return
|
||||
|
||||
this.profilesUsed.add(pubkey)
|
||||
this.$store.dispatch('useProfile', {pubkey})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
@ -97,7 +97,7 @@
|
||||
</template>
|
||||
</q-input>
|
||||
</q-card-section>
|
||||
<!-- <div v-if='isBeck32Key(key)'>
|
||||
<!-- <div v-if='isBech32Key(key)'>
|
||||
{{ hexKey }}
|
||||
</div> -->
|
||||
</q-form>
|
||||
@ -234,14 +234,14 @@ export default defineComponent({
|
||||
// npub1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzsevkk5s
|
||||
// nsec1xtscya34g58tk0z605fvr788k263gsu6cy9x0mhnm87echrgufzs46ahj9
|
||||
// 32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245
|
||||
if (this.isBeck32Key(this.key)) {
|
||||
return this.beck32ToHex(this.key)
|
||||
if (this.isBech32Key(this.key)) {
|
||||
return this.bech32ToHex(this.key)
|
||||
}
|
||||
return this.key?.toLowerCase()
|
||||
},
|
||||
|
||||
isBech32Pub() {
|
||||
if (this.isBeck32Key(this.key)) {
|
||||
if (this.isBech32Key(this.key)) {
|
||||
let { prefix } = decode(this.key.toLowerCase())
|
||||
return prefix === 'npub'
|
||||
}
|
||||
@ -249,7 +249,7 @@ export default defineComponent({
|
||||
},
|
||||
|
||||
isBech32Sec() {
|
||||
if (this.isBeck32Key(this.key)) {
|
||||
if (this.isBech32Key(this.key)) {
|
||||
let { prefix } = decode(this.key.toLowerCase())
|
||||
return prefix === 'nsec'
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ export default defineComponent({
|
||||
validSearch() {
|
||||
if (this.searchingProfile === '') return true
|
||||
if (this.searchingProfile.match(/^[a-f0-9A-F]{64}$/)) return true
|
||||
if (this.isBeck32Key(this.searchingProfile) && this.beck32ToHex(this.searchingProfile).match(/^[a-f0-9A-F]{64}$/)) return true
|
||||
if (this.isBech32Key(this.searchingProfile) && this.bech32ToHex(this.searchingProfile).match(/^[a-f0-9A-F]{64}$/)) return true
|
||||
if (this.searchingProfile.match(/^([a-z0-9A-Z-_.\u00C0-\u1FFF\u2800-\uFFFD]*@)?[a-z0-9A-Z-_]+[.]{1}[a-z0-9A-Z-_.]+$/)) return true
|
||||
return false
|
||||
},
|
||||
@ -174,8 +174,8 @@ export default defineComponent({
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isBeck32Key(this.searchingProfile) && this.beck32ToHex(this.searchingProfile).match(/^[a-f0-9A-F]{64}$/)) {
|
||||
this.toProfile(this.beck32ToHex(this.searchingProfile))
|
||||
if (this.isBech32Key(this.searchingProfile) && this.bech32ToHex(this.searchingProfile).match(/^[a-f0-9A-F]{64}$/)) {
|
||||
this.toProfile(this.bech32ToHex(this.searchingProfile))
|
||||
this.searchingProfile = ''
|
||||
this.searching = false
|
||||
return
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="trends-item">
|
||||
<h3>{{ data.name }}</h3>
|
||||
<span>{{ normalizedTweetCount }} Tweets</span>
|
||||
<span>{{ nicePostCount }} posts</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -15,10 +15,10 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
normalizedTweetCount(){
|
||||
const stringNumber = this.data.tweetsCount.toString();
|
||||
nicePostCount() {
|
||||
const stringNumber = this.data.postCount.toString()
|
||||
if (stringNumber.length > 4) {
|
||||
return stringNumber.substring(0, stringNumber.length - 3) + "K"
|
||||
return stringNumber.substring(0, stringNumber.length - 3) + 'K'
|
||||
}
|
||||
return stringNumber
|
||||
}
|
||||
@ -27,7 +27,8 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/assets/theme/colors.scss';
|
||||
@import 'assets/theme/colors.scss';
|
||||
|
||||
.trends-item {
|
||||
padding: 1rem;
|
||||
border-top: $border-dark;
|
||||
|
@ -19,8 +19,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TrendsItem from '@/components/Trends/Item'
|
||||
import { getTrends } from '@/services/api'
|
||||
import TrendsItem from 'components/Trends/Item'
|
||||
|
||||
export default {
|
||||
name: 'Trends',
|
||||
@ -29,33 +28,27 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
trends: []
|
||||
trends: [
|
||||
{
|
||||
name: '#nostr',
|
||||
postCount: 58
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
sortedTrends() {
|
||||
const trendsArray = this.trends;
|
||||
trendsArray.sort((a,b) => a.tweetsCount > b.tweetsCount ? -1 : 1, 0)
|
||||
const trendsArray = this.trends
|
||||
trendsArray.sort((a, b) => a.postCount > b.postCount ? -1 : 1)
|
||||
return trendsArray
|
||||
}
|
||||
},
|
||||
async mounted(){
|
||||
try{
|
||||
const response = await getTrends();
|
||||
const trends = response.data.trends;
|
||||
this.trends = trends;
|
||||
} catch(err){
|
||||
this.$notification({
|
||||
type: 'error',
|
||||
message: 'Error when fetching trends'
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@/assets/theme/colors.scss';
|
||||
@import 'assets/theme/colors.scss';
|
||||
|
||||
.trends {
|
||||
background-color: rgba($color: $color-dark-gray, $alpha: 0.1);
|
||||
border-radius: 1rem;
|
||||
@ -70,7 +63,6 @@ export default {
|
||||
}
|
||||
}
|
||||
&-body {
|
||||
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1 +1,13 @@
|
||||
// app global css in SCSS form
|
||||
h2 {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
line-height: unset;
|
||||
letter-spacing: unset;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
line-height: unset;
|
||||
letter-spacing: unset;
|
||||
}
|
||||
|
@ -42,7 +42,8 @@
|
||||
|
||||
<div class="layout-sidebar">
|
||||
<div class="layout-sidebar-fixed">
|
||||
<TheSearchMenu/>
|
||||
<search-box />
|
||||
<trends />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -90,16 +91,18 @@ const { getVerticalScrollPosition, setVerticalScrollPosition} = scroll
|
||||
import { activateSub, deactivateSub, destroyStreams } from '../query'
|
||||
import MainMenu from 'components/MainMenu/index.vue'
|
||||
import TheUserMenu from 'components/TheUserMenu.vue'
|
||||
import TheSearchMenu from 'components/TheSearchMenu.vue'
|
||||
import TheKeyInitializationDialog from 'components/TheKeyInitializationDialog.vue'
|
||||
import SearchBox from 'components/SearchBox/index.vue'
|
||||
import Trends from 'components/Trends/index.vue'
|
||||
import { setCssVar, getCssVar } from 'quasar'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MainLayout',
|
||||
components: {
|
||||
MainMenu,
|
||||
SearchBox,
|
||||
Trends,
|
||||
TheUserMenu,
|
||||
TheSearchMenu,
|
||||
TheKeyInitializationDialog,
|
||||
},
|
||||
|
||||
@ -338,7 +341,7 @@ export default defineComponent({
|
||||
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
<style lang="scss">
|
||||
@import 'assets/theme/colors.scss';
|
||||
@import 'assets/variables.scss';
|
||||
|
||||
|
@ -287,21 +287,21 @@ export default {
|
||||
return false
|
||||
},
|
||||
|
||||
isBeck32Key(key) {
|
||||
isBech32Key(key) {
|
||||
if (typeof key !== 'string') return false
|
||||
try {
|
||||
let { prefix } = decode(key.toLowerCase())
|
||||
if (!['npub', 'nsec'].includes(prefix)) return false
|
||||
if (prefix === 'npub') this.watchOnly = true
|
||||
if (prefix === 'nsec') this.watchOnly = false
|
||||
if (!this.isKey(this.beck32ToHex(key))) return false
|
||||
if (!this.isKey(this.bech32ToHex(key))) return false
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
},
|
||||
|
||||
beck32ToHex(key) {
|
||||
bech32ToHex(key) {
|
||||
let { data } = decode(key.toLowerCase())
|
||||
return data.reduce((s, byte) => {
|
||||
let hex = byte.toString(16)
|
||||
|
Loading…
Reference in New Issue
Block a user