Skip to content

Commit

Permalink
Merge branch 'albermonte/searchbar-new-behaviour', remote-tracking br…
Browse files Browse the repository at this point in the history
…anch 'upstream/master'
  • Loading branch information
Albermonte committed Aug 21, 2023
2 parents 776ea1a + 01f8cbe commit de78aaa
Show file tree
Hide file tree
Showing 5 changed files with 318 additions and 104 deletions.
98 changes: 98 additions & 0 deletions src/components/CashlinkButton.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<template>
<button @click="$emit('toggle-unclaimed-cashlink-list')" @mousedown.prevent>
<div class="cashlink-button" :class="showUnclaimedCashlinkList ? 'active' : ''">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="18" viewBox="0 0 12 18" fill="none">
<path
d="M10.5 4.125C10.5 2.375 8.97692 1 7.03846 1H4.96154C3.02308
1 1.5 2.375 1.5 4.125V7.875C1.5 9.625 3.02308 11 4.96154 11H5.65385"
stroke-width="2" stroke-linecap="round" />
<path
d="M1.5 13.875C1.5 15.625 3.02308 17 4.96154 17L7.03846
17C8.97692 17 10.5 15.625 10.5 13.875L10.5 10.125C10.5 8.375 8.97692 7 7.03846 7L6.34615 7"
stroke-width="2" stroke-linecap="round" />
</svg>
</div>
<div class="notification-dot">
<span class="text">{{ unclaimedCashlinkCount }}</span>
</div>
</button>
</template>

<script lang="ts">
import { defineComponent } from '@vue/composition-api';
export default defineComponent({
setup() {
return {
};
},
props: {
unclaimedCashlinkCount: {
type: Number,
},
showUnclaimedCashlinkList: {
type: Boolean,
default: false,
},
},
components: {
},
});
</script>

<style lang="scss" scoped>
button {
position: relative;
background: transparent;
border-width: 0;
cursor: pointer;
}
.cashlink-button {
width: 4rem;
height: 4rem;
display: flex;
align-items: center;
justify-content: center;
border-radius: 2rem;
background: var(--nimiq-blue-bg);
transition: background var(--attr-duration) var(--nimiq-ease);
svg {
stroke: white;
}
}
.active {
background: transparent;
border: 1.5px solid rgba(31, 35, 72, 0.16);
svg {
stroke: var(--nimiq-blue);
}
}
.notification-dot {
position: absolute;
bottom: -1rem;
right: 0;
padding: 2.5px 5px;
font-size: 11px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
border-radius: 2rem;
border: 0.375rem solid var(--bg-primary);
transition: border-color 400ms var(--nimiq-ease);
color: white;
font-family: Muli;
background: var(--light-blue-gradient, radial-gradient(100% 100% at 100% 100.00%, #265DD7 0%, #0582CA 100%));
.text {
font-size: 11px;
font-weight: 600;
line-height: 100%;
}
}</style>
136 changes: 118 additions & 18 deletions src/components/SearchBar.vue
Original file line number Diff line number Diff line change
@@ -1,27 +1,37 @@
<template>
<div class="search-bar" @click="$refs.searchBarInput.focus()">
<div
class="search-bar cover-all"
@click="$refs.searchBarInput.focus()"
@pointerdown.prevent
:style="{ 'max-width': `${maxWidth}` }"
>
<svg fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="6" cy="6" r="5" stroke="currentColor" stroke-width="2"/>
<circle cx="6" cy="6" r="5" stroke="currentColor" stroke-width="2" />
<path d="M13.31 14.73a1 1 0 001.42-1.42l-1.42 1.42zM8.3 9.7l5.02 5.02 1.42-1.42L9.7 8.3 8.29 9.71z"
fill="currentColor"/>
fill="currentColor" />
</svg>
<input
ref="searchBarInput"
type="text"
:value="value"
:placeholder="width < 50
? ''
: width > 340
? $t('Search transactions by contact, address, etc.')
: width > 150
? $t('Search transactions')
: $t('Search')"
@input="$emit('input', $event.target.value)" />
type="text" :value="value"
:placeholder="placeholderText"
@input="$emit('input', $event.target.value)"
@focus="handleFocus"
@blur="handleBlur"
/>
<transition name="fade">
<CrossCloseButton
class="cross-close-button"
v-if="isInputActive"
@click="handleClose"
/>
</transition>
</div>
</template>

<script lang="ts">
import { defineComponent, ref, onMounted, onUnmounted } from '@vue/composition-api';
import { defineComponent, ref, onMounted, onUnmounted, computed } from '@vue/composition-api';
import CrossCloseButton from './CrossCloseButton.vue';
export default defineComponent({
name: 'search-bar',
Expand All @@ -31,12 +41,57 @@ export default defineComponent({
default: '',
},
},
setup() {
setup(props, context) {
const searchBarInput = ref<HTMLInputElement | null>(null);
const width = ref(1000);
const placeholderText = ref('');
const isInputFocused = ref(false);
let observer: ResizeObserver;
const getFontSize = (element: HTMLElement) => {
const style = getComputedStyle(element);
const fontSize = style.getPropertyValue('--body-size');
return fontSize;
};
const getTextWidth = (text: string, size: string) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) return 0;
ctx.font = size;
return ctx.measureText(text).width;
};
const maxWidth = computed(() => {
if (!searchBarInput.value) return '100%';
const fontSize = getFontSize(searchBarInput.value);
const textSize = getTextWidth(placeholderText.value, fontSize);
return isInputActive.value ? '100%' : `${textSize + 120}px`;
});
const handleFocus = () => {
isInputFocused.value = true;
};
const handleBlur = () => {
isInputFocused.value = false;
};
const inputValue = computed(() => props.value);
const isInputActive = computed(() => {
// Only collapse if not focused and no text
if (!isInputFocused.value && inputValue.value === '') return false;
return true;
});
const handleClose = (e: Event) => {
context.emit('input', '');
// Prevent the search bar from losing or gaining focus when not intended
e.stopImmediatePropagation();
};
onMounted(() => {
if ('ResizeObserver' in window && searchBarInput.value) {
observer = new ResizeObserver((entries: ResizeObserverEntry[]) => {
Expand All @@ -46,6 +101,14 @@ export default defineComponent({
? entry.contentBoxSize[0].inlineSize
: (entry.contentBoxSize as any).inlineSize)
: entry.contentRect.width;
placeholderText.value = (width.value < 50
? ''
: width.value > 340
? context.root.$t('Search transactions by contact, address, etc.')
: width.value > 130
? context.root.$t('Search transactions')
: context.root.$t('Search')) as string;
});
observer.observe(searchBarInput.value);
}
Expand All @@ -60,8 +123,17 @@ export default defineComponent({
return {
searchBarInput,
width,
maxWidth,
placeholderText,
isInputActive,
handleFocus,
handleBlur,
handleClose,
};
},
components: {
CrossCloseButton,
},
});
</script>

Expand All @@ -76,9 +148,10 @@ export default defineComponent({
width: 100%;
cursor: text;
padding: 0.75rem 0;
min-width: 0;
margin-right: 1rem;
min-width: 5.5rem;
transition: color var(--attr-duration) var(--nimiq-ease);
transition: color var(--attr-duration) var(--nimiq-ease), max-width var(--attr-duration) var(--nimiq-ease);
&::after {
content: '';
Expand Down Expand Up @@ -149,11 +222,38 @@ input {
}
}
@media (max-width: 700px) { // Full mobile breakpoint
@media (max-width: 700px) {
// Full mobile breakpoint
input {
&::placeholder {
font-weight: 600;
}
}
}
.cross-close-button {
position: absolute;
z-index: 1;
right: 1.75rem;
cursor: pointer;
}
.fade-enter-active, .fade-leave-active {
transition-duration: var(--attr-duration);
}
@media (min-width: 700px) and (max-width: 900px) {
.cover-all {
&:focus-within {
position: absolute;
z-index: 10;
background: var(--bg-primary);
box-shadow: 0 0 0 1rem var(--bg-primary);
border-radius: 6rem;
width: calc(100% - 5rem);
}
}
}
</style>
17 changes: 14 additions & 3 deletions src/components/TransactionList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
>
<template v-if="showUnclaimedCashlinkList" v-slot:before>
<div class="unclaimed-cashlink-list">
<CrossCloseButton class="top-right nq-orange" @click="$emit('close-unclaimed-cashlink-list')"/>
<div class="month-label nq-orange"><label>{{ $t('Pending Cashlinks') }}</label></div>
<div class="month-label nq-blue opacity-40"><label>{{ $t('Pending Cashlinks') }}</label></div>
<CrossCloseButton
class="top-right nq-blue opacity-50"
@click="$emit('close-unclaimed-cashlink-list')"
/>
<TransactionListItem
v-for="tx in unclaimedCashlinkTxs"
:transaction="tx"
Expand Down Expand Up @@ -472,7 +475,7 @@ export default defineComponent({
padding: 2rem;
position: relative;
margin: 4rem -2rem 0;
box-shadow: inset 0 0 0 0.1875rem rgba(252, 135, 2, 0.4);
box-shadow: inset 0 0 0 0.1875rem rgba(31, 35, 72, 0.16);
.cross-close-button {
top: 1.5rem;
Expand Down Expand Up @@ -690,4 +693,12 @@ export default defineComponent({
}
}
}
.opacity-50 {
opacity: 0.5;
}
.opacity-40 {
opacity: 0.4;
}
</style>
Loading

0 comments on commit de78aaa

Please sign in to comment.