Skip to content

Commit 0788635

Browse files
committed
feat: add search section to landing page
See: FE-92
1 parent 2dda099 commit 0788635

File tree

19 files changed

+1259
-334
lines changed

19 files changed

+1259
-334
lines changed

frontend/i18n/locales/en.json

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
"beaconchain_homepage": "Beaconchain Homepage",
77
"common": {
88
"close": "Close",
9+
"error_retry": "An error occurred. Please try again.",
910
"log_in": "Log in",
11+
"no_results": "No results found.",
1012
"open_navigation": "Open Navigation",
1113
"side_navigation": "Side Navigation"
1214
},
@@ -1157,7 +1159,23 @@
11571159
}
11581160
},
11591161
"search": {
1160-
"title": "Explore Transactions & Validator Staking on"
1162+
"input_label": "Search by Address / Tx hash / Block / Token / ENS",
1163+
"input_placeholder": "Search anything...",
1164+
"loading_message": "Loading search results...",
1165+
"title": "Explore Transactions & Validator Staking on",
1166+
"types": {
1167+
"addresses": "Addresses",
1168+
"blocks": "Blocks",
1169+
"ens_names": "ENS Names",
1170+
"epochs": "Epochs",
1171+
"slots": "Slots",
1172+
"tokens": "Tokens",
1173+
"transactions": "Tx Hashes",
1174+
"validator_deposit_addresses": "Validator Deposit Addresses",
1175+
"validator_graffiti": "Validator Graffiti",
1176+
"validator_withdrawal_credentials": "Validator Withdrawal Credentials",
1177+
"validators": "Validators"
1178+
}
11611179
},
11621180
"staking_hub": {
11631181
"action": {

frontend/layers/base/app/assets/css/main.css

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,17 @@
1111
@theme {
1212
--*: initial;
1313

14+
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
15+
1416
--breakpoint-sm: 40rem; /* 640px */
1517
--breakpoint-md: 48rem; /* 768px */
1618
--breakpoint-lg: 64rem; /* 1024px */
1719
/* --breakpoint-xl: 80rem; */
1820
/* --breakpoint-2xl: 96rem; */
1921

2022

23+
--color-charcoal-50: #555555;
24+
--color-charcoal-500: #303030;
2125
--color-charcoal-600: #282828;
2226
--color-charcoal-700: #212121;
2327

@@ -34,6 +38,7 @@
3438
--color-gray-200: #BDBDBD;
3539
--color-gray-300: #A8A8A8;
3640
--color-gray-400: #888888;
41+
--color-gray-500: #666666;
3742
--color-gray-700: #3B3B3B;
3843
--color-gray-900: #262626;
3944
--color-gray-950: #1A1919;
@@ -47,8 +52,9 @@
4752
--container-3xs: 16rem; /* 256px */
4853
/* --container-7xl: 80rem; 1280px -> this is in conflict with --spacing-7xl */
4954
--container-8xl: 90rem; /* 1440px */
55+
--container-24xl: 80rem; /* 1280px */
56+
--container-30xl: 120rem; /* 1920px */
5057

51-
--container-24xl: 80rem; /* 144px */
5258

5359
/* --ease-in: cubic-bezier(0.4, 0, 1, 1); */
5460
/* --ease-out: cubic-bezier(0, 0, 0.2, 1); */
@@ -59,7 +65,9 @@
5965
--font-weight-semibold: 600;
6066

6167
--radius-xl: .75rem; /* 12px */
68+
--radius-3xl: 1.25rem; /* 20px */
6269
--radius-4xl: 1.5rem; /* 24px */
70+
--radius-7xl: 1.5rem; /* 24px */
6371
--radius-full: 2rem; /* 32px */
6472

6573
--spacing-unset: unset;
@@ -79,8 +87,8 @@
7987

8088
--text-xs: .75rem; /* 12px */
8189
--text-xs--line-height: 1rem; /* 16px */
82-
/* --text-sm-tight: .875rem; 14px */
83-
/* --text-sm-tight--line-height: 1rem; 16px */
90+
--text-sm-tight: .875rem; /* 14px */
91+
--text-sm-tight--line-height: 1rem; /* 16px */
8492
--text-sm: .875rem; /* 14px */
8593
--text-sm--line-height: 1.25rem; /* 20px */
8694
--text-md: 1rem; /* 16px */
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<script setup lang="ts">
2+
import type { ChainId } from '~/types/network'
3+
import { useNetwork } from '~/layers/base/app/composables/useNetwork'
4+
5+
const { id } = defineProps<{
6+
id: ChainId,
7+
}>()
8+
9+
const { getNetworkName } = useNetwork()
10+
11+
const networkName = computed(() => getNetworkName(id))
12+
</script>
13+
14+
<template>
15+
<LazyNetworkIconCryptoEth
16+
v-if="networkName === 'Ethereum'"
17+
class="w-2xl"
18+
/>
19+
<LazyNetworkIconCryptoHoodi
20+
v-if="networkName === 'Ethereum Hoodi'"
21+
class="w-2xl"
22+
/>
23+
</template>
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
<script setup lang="ts" generic="SearchResultType">
2+
type GroupBy = keyof SearchResultType
3+
4+
const {
5+
groupBy,
6+
hasError,
7+
isLoading,
8+
results,
9+
} = defineProps<{
10+
groupBy?: GroupBy,
11+
hasError?: boolean,
12+
isLoading: boolean,
13+
label: string,
14+
placeholder?: string,
15+
results?: SearchResultType[],
16+
}>()
17+
18+
const emit = defineEmits<{
19+
(e: 'search', input: string): void,
20+
}>()
21+
22+
const { t: $t } = useTranslation()
23+
24+
const hasSearched = ref(false)
25+
const input = defineModel<string>({
26+
required: true,
27+
})
28+
29+
watchDebounced(
30+
input,
31+
async () => {
32+
if (input.value.length) {
33+
emit('search', input.value)
34+
hasSearched.value = true
35+
}
36+
},
37+
{
38+
deep: true,
39+
immediate: false,
40+
},
41+
)
42+
43+
const showDropdown = computed(() => isLoading || hasSearched.value)
44+
const groupedResults = computed(() => {
45+
if (!results?.length) return
46+
if (!groupBy) return
47+
48+
const groupedResults = Object.groupBy(results, result => result[groupBy] as PropertyKey)
49+
50+
return Object.entries(groupedResults) as [SearchResultType[GroupBy], SearchResultType[]][]
51+
})
52+
</script>
53+
54+
<template>
55+
<form
56+
role="search"
57+
class="p-2xl dark:bg-[rgba(16,16,16,0.2)] rounded-3xl"
58+
>
59+
<RkComboboxRoot
60+
v-model:open="showDropdown"
61+
class="relative"
62+
ignore-filter
63+
>
64+
<RkLabel
65+
for="blockchain-search-input"
66+
class="absolute bottom-2xl left-2xl dark:text-gray-400 text-sm-tight"
67+
>
68+
{{ label }}
69+
</RkLabel>
70+
<RkComboboxInput
71+
id="blockchain-search-input"
72+
v-model.trim="input"
73+
type="search"
74+
auto-focus
75+
:aria-busy="isLoading"
76+
:placeholder
77+
class="search-input w-full text-2xl font-semibold rounded-3xl pt-3xl pr-5xl pb-6xl pl-2xl dark:bg-gray-950
78+
dark:focus:bg-black placeholder:dark:text-gray-500 dark:text-white border-1 dark:border-charcoal-500
79+
dark:focus:border-charcoal-50 dark:focus-within:outline-0"
80+
@update:model-value="(value) => { if (!value) hasSearched = false }"
81+
/>
82+
83+
<RkComboboxContent class="absolute dark:bg-gray-950 mt-xl rounded-xl w-full max-h-[400px] overflow-y-auto">
84+
<RkComboboxViewport>
85+
<!-- HISTORY AND FILTERS GO HERE -->
86+
87+
<div class="py-lg">
88+
<slot
89+
v-if="isLoading"
90+
name="loading-content"
91+
>
92+
<BlockchainSearchLoadingSkeleton />
93+
</slot>
94+
95+
<slot
96+
v-else-if="hasError"
97+
name="error-content"
98+
>
99+
<div
100+
role="alert"
101+
class="px-2xl py-md dark:text-gray-400 "
102+
>
103+
{{ $t('base.common.error_retry') }}
104+
</div>
105+
</slot>
106+
107+
<slot v-else-if="!results?.length">
108+
<RkComboboxEmpty>
109+
<div class="dark:text-gray-400 px-2xl py-md font-semibold">
110+
{{ $t('base.common.no_results') }}
111+
</div>
112+
</RkComboboxEmpty>
113+
</slot>
114+
115+
<template v-else-if="results?.length && groupBy">
116+
<RkComboboxGroup
117+
v-for="[groupKey, groupItems] in groupedResults"
118+
:key="groupKey as string"
119+
>
120+
<RkComboboxLabel class="px-2xl py-md dark:text-gray-400">
121+
<slot
122+
name="result-group-label"
123+
:label="groupKey"
124+
/>
125+
</RkComboboxLabel>
126+
127+
<RkComboboxItem
128+
v-for="result in groupItems"
129+
:key="JSON.stringify(result)"
130+
as-child
131+
:value="JSON.stringify(result)"
132+
class="dark:data-[highlighted]:bg-gray-900 px-2xl py-md font-semibold"
133+
@select.prevent
134+
>
135+
<slot
136+
name="result-item"
137+
:result
138+
/>
139+
</RkComboboxItem>
140+
</RkComboboxGroup>
141+
</template>
142+
143+
<template v-else-if="results?.length && !groupBy">
144+
<RkComboboxItem
145+
v-for="result in results"
146+
:key="JSON.stringify(result)"
147+
as-child
148+
:value="JSON.stringify(result)"
149+
class="dark:data-[highlighted]:bg-gray-900 px-2xl py-md font-semibold"
150+
@select.prevent
151+
>
152+
<slot
153+
name="result-item"
154+
:result
155+
/>
156+
</RkComboboxItem>
157+
</template>
158+
</div>
159+
</RkComboboxViewport>
160+
</RkComboboxContent>
161+
</RkComboboxRoot>
162+
</form>
163+
</template>
164+
165+
<style lang="scss" scoped>
166+
.search-input::-webkit-search-cancel-button {
167+
display: none;
168+
}
169+
</style>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<script setup lang="ts">
2+
</script>
3+
4+
<template>
5+
<svg
6+
xmlns="http://www.w3.org/2000/svg"
7+
fill="none"
8+
viewBox="0 0 24 24"
9+
>
10+
<path
11+
fill="currentColor"
12+
d="m12 0-.16.55v15.87l.15.16 7-4.36-7-12.22Z"
13+
/>
14+
<path
15+
fill="currentColor"
16+
d="M12 0 5 12.22l7 4.36V0Zm0 17.97-.1.11v5.65l.1.27 7-10.38-7 4.35Z"
17+
/>
18+
<path
19+
fill="currentColor"
20+
d="M12 24v-6.03l-7-4.35L12 24Zm0-7.42 6.99-4.36-7-3.35v7.7Z"
21+
/>
22+
<path
23+
fill="currentColor"
24+
d="m5 12.22 7 4.36v-7.7l-7 3.34Z"
25+
/>
26+
</svg>
27+
</template>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<template>
2+
<svg
3+
xmlns="http://www.w3.org/2000/svg"
4+
viewBox="0 0 24 24"
5+
fill="none"
6+
>
7+
<path
8+
fill="currentColor"
9+
d="m11.994 0-.153.547v15.87l.153.16 6.995-4.354L11.994 0Z"
10+
/>
11+
<path
12+
fill="currentColor"
13+
d="M11.996 0 5 12.223l6.996 4.354V0ZM11.994 17.971l-.087.11v5.654l.087.265 7-10.38-7 4.351Z"
14+
/>
15+
<path
16+
fill="currentColor"
17+
d="M11.996 24V17.97L5 13.619 11.996 24ZM11.995 16.578l6.995-4.355-6.995-3.348v7.703Z"
18+
/>
19+
<path
20+
fill="currentColor"
21+
d="m5 12.223 6.996 4.354V8.874L5 12.223Z"
22+
/>
23+
<circle
24+
cx="5.667"
25+
cy="17.667"
26+
r="5.333"
27+
fill="#2861C1"
28+
stroke="currentColor"
29+
stroke-width=".667"
30+
/>
31+
<path
32+
fill="currentColor"
33+
d="M6.753 15h.914v5.333h-.914v-2.392H4.58v2.392h-.914V15h.914v2.011h2.172V15Z"
34+
/>
35+
</svg>
36+
</template>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export const useBaseUrls = () => {
2+
const config = useRuntimeConfig()
3+
const {
4+
apiClientHoodi,
5+
apiClientMainnet,
6+
} = config.public
7+
8+
const hoodiUrl = new URL(apiClientHoodi as string)
9+
const mainnetUrl = new URL(apiClientMainnet as string)
10+
11+
return {
12+
hoodi: hoodiUrl.origin,
13+
mainnet: mainnetUrl.origin,
14+
}
15+
}

0 commit comments

Comments
 (0)