Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Collection Activity Tab #5345

Merged
merged 68 commits into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
829f7b5
feat: collection activity chart
daiagi Mar 22, 2023
b030b79
remove controls on activity tab
daiagi Mar 22, 2023
66b19b8
feat: holders tab
daiagi Mar 23, 2023
9c9c32b
Merge branch 'main' of https://github.com/kodadot/nft-gallery into co…
daiagi Mar 23, 2023
ef606dd
feat: flippers tab
daiagi Mar 23, 2023
a0f5b6f
control chart height
daiagi Mar 23, 2023
71dd950
finish owners insights
daiagi Mar 24, 2023
6693f98
reponsivity
daiagi Mar 24, 2023
7b6de3b
feat: events table
daiagi Mar 24, 2023
76b7fa0
touch up events table
daiagi Mar 24, 2023
01eb816
Merge branch 'main' of https://github.com/kodadot/nft-gallery into co…
daiagi Mar 24, 2023
3557ecd
feat: add offers to event table
daiagi Mar 25, 2023
78e7c13
Merge branch 'main' of https://github.com/kodadot/nft-gallery into co…
daiagi Mar 25, 2023
dfd86b1
implement design review
daiagi Mar 25, 2023
d350989
responsivity
daiagi Mar 25, 2023
e1381e7
clear deepScan deepSource issues
daiagi Mar 25, 2023
733cd16
link on nft avatar in mobile
daiagi Mar 25, 2023
c9b0661
feat: filters
daiagi Mar 25, 2023
3cfec0f
cleanups, touchups
daiagi Mar 26, 2023
27b6e3b
attempt1 to fix chart responsivity
daiagi Mar 26, 2023
8caac91
visual touchups
daiagi Mar 26, 2023
6300597
attempt to fix / improve chart resize issue
daiagi Mar 26, 2023
6f579f2
fix deepSource issues
daiagi Mar 26, 2023
bd27a34
fix wrong to addres for send interaction
daiagi Mar 26, 2023
ba37fd5
fix
daiagi Mar 26, 2023
4e28e88
Update components/collection/utils/useCollectionActivity.ts
daiagi Mar 26, 2023
5d6eee6
use one ref for toggling vue
daiagi Mar 26, 2023
d07cd73
Merge branch 'collection-activity-tab' of https://github.com/daiagi/n…
daiagi Mar 26, 2023
be33938
fix visual issues
daiagi Mar 26, 2023
ee0bf80
remove price filter on collection activity
daiagi Mar 26, 2023
c1dcf38
fixed breadcrumbs margin
daiagi Mar 26, 2023
6c9e08c
code styling issue
daiagi Mar 26, 2023
293b09b
toggle event row with resizeObserver
daiagi Mar 26, 2023
991e12a
remove a console log
daiagi Mar 26, 2023
8bcb8c3
clip flip profit to 4 digits
daiagi Mar 26, 2023
d2a9b12
sensible chart (rolling avg of a day)
daiagi Mar 27, 2023
a96e365
deepSource fix
daiagi Mar 27, 2023
90dd650
trim price digits in chart
daiagi Mar 27, 2023
afdbcf0
rmrk2 fix
daiagi Mar 27, 2023
5a9091b
Merge branch 'main' into collection-activity-tab
daiagi Mar 27, 2023
e6be07b
touch up flippers profit display
daiagi Mar 27, 2023
8146906
Merge branch 'collection-activity-tab' of https://github.com/daiagi/n…
daiagi Mar 27, 2023
433df89
simplify timeAgo function using date-fns
daiagi Mar 28, 2023
5e97419
remove 'set'
daiagi Mar 28, 2023
a424df1
fix timeAgo
daiagi Mar 28, 2023
40bceba
use 'has-text-grey'
daiagi Mar 28, 2023
b6a53de
move useREplaceUrl to composables
daiagi Mar 28, 2023
5489b24
remove duplicate css, renaming
daiagi Mar 28, 2023
e87fc36
move function to utils, rename Chart to ActivityChart
daiagi Mar 28, 2023
3216601
extract some function out of getOwners, getFlippers
daiagi Mar 28, 2023
7e22d7f
remove few lines from getFlippers
daiagi Mar 28, 2023
ccd9b10
remove some more lines from getOwners
daiagi Mar 28, 2023
d338ea0
Merge branch 'main' of https://github.com/kodadot/nft-gallery into co…
daiagi Mar 28, 2023
5ad06c4
@vikiival update pnpm veriosn to 8 in package.json
daiagi Mar 28, 2023
09ca4b5
undo update pnpm veriosn to 8 in package.json
daiagi Mar 28, 2023
fe7eb4f
Merge branch 'collection-activity-tab' of https://github.com/daiagi/n…
daiagi Mar 28, 2023
b6603c8
undo pnpm version update
daiagi Mar 28, 2023
f6133cb
better organize useCollectionActivityCode
daiagi Mar 28, 2023
5c18cd3
Merge branch 'main' into collection-activity-tab
daiagi Mar 28, 2023
0d04e7a
clear deepSource
daiagi Mar 28, 2023
a415e3d
Merge branch 'collection-activity-tab' of https://github.com/daiagi/n…
daiagi Mar 28, 2023
a4cfdaf
Merge branch 'main' into collection-activity-tab
daiagi Mar 28, 2023
8078664
move useCollectionActivity to composables
daiagi Mar 28, 2023
b2a744f
Merge branch 'main' of https://github.com/kodadot/nft-gallery into co…
daiagi Mar 28, 2023
158db8a
resolve some code review
daiagi Mar 28, 2023
d3b5cab
Merge branch 'collection-activity-tab' of https://github.com/daiagi/n…
daiagi Mar 28, 2023
2c9caa6
delete format file
daiagi Mar 28, 2023
9f4865d
removed negative margin
daiagi Mar 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions components/chart/PriceChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
>Price ({{ chainSymbol }})
</span>
<NeoDropdown class="py-0">
<NeoButton :label="selectedTimeRange.label" class="time-range-button" />
<NeoButton
:label="selectedTimeRange.label"
class="time-range-button"
no-shadow />

<template #items>
<NeoDropdownItem
Expand All @@ -19,7 +22,7 @@
</template>
</NeoDropdown>

<div class="content">
<div :class="{ content: !chartHeight }" :style="heightStyle">
<canvas id="priceChart" />
</div>
</div>
Expand Down Expand Up @@ -66,7 +69,12 @@ const setTimeRange = (value: { value: number; label: string }) => {

const props = defineProps<{
priceChartData?: [Date, number][][]
chartHeight?: string
}>()

const heightStyle = computed(() =>
props.chartHeight ? `height: ${props.chartHeight}` : ''
)
let Chart: ChartJS<'line', any, unknown>

onMounted(() => {
Expand Down Expand Up @@ -124,11 +132,11 @@ const getPriceChartData = () => {
)?.getContext('2d')
if (ctx) {
const commonStyle = {
tension: 0,
tension: 0.2,
pointRadius: 6,
pointHoverRadius: 6,
pointHoverBackgroundColor: isDarkMode.value ? '#181717' : 'white',
borderJoinStyle: 'miter' as const,
borderJoinStyle: 'round' as const,
radius: 0,
pointStyle: 'rect',
borderWidth: 1,
Expand Down Expand Up @@ -157,6 +165,16 @@ const getPriceChartData = () => {
},
options: {
maintainAspectRatio: false,
responsive: true,
responsiveAnimationDuration: 0,
transitions: {
resize: {
animation: {
duration: 0,
},
},
},

plugins: {
customCanvasBackgroundColor: {
color: isDarkMode.value ? '#181717' : 'white',
Expand Down Expand Up @@ -225,7 +243,7 @@ const getPriceChartData = () => {
callback: (value) => {
return `${Number(value).toFixed(2)} `
},
maxTicksLimit: 7,
stepSize: 1,
color: lineColor.value,
},
grid: {
Expand Down
104 changes: 104 additions & 0 deletions components/collection/activity/Activity.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<template>
<div class="is-flex">
<SidebarFilter />
<div ref="wrapper" class="w-full mt-5">
<div v-if="tablet">
<div class="columns">
<div class="column is-two-thirds">
<ActivityChart :events="events" />
</div>
<div class="column">
<OwnerInsights :owners="owners" :flippers="flippers" />
</div>
</div>
<BreadcrumbsFilter />
</div>
<div v-else>
<div class="is-flex is-flex-direction-column gap">
<OwnerInsights :owners="owners" :flippers="flippers" />
<div class="max-width">
<ActivityChart :events="events" />
</div>
</div>
</div>
<hr class="mb-40" :class="{ 'my-40': !isBreadCrumbsShowing }" />
<Events :events="sortedEventsWithOffersDesc" />
</div>
</div>
</template>

<script setup lang="ts">
import ActivityChart from './ActivityChart.vue'
import OwnerInsights from './OwnerInsights.vue'
import Events from './events/Events.vue'
import BreadcrumbsFilter from '@/components/shared/BreadcrumbsFilter.vue'
import { Interaction } from '@kodadot1/minimark'
import { useResizeObserver } from '@vueuse/core'
import SidebarFilter from '@/components/shared/filters/SidebarFilter.vue'
import { isAnyActivityFilterActive } from './utils'
import { mintInteraction } from '@/composables/collectionActivity/helpers'
import { useCollectionActivity } from '@/composables/collectionActivity/useCollectionActivity'
const mobileBreakpoint = 800
const route = useRoute()
const tablet = ref(true)
const wrapper = ref<HTMLDivElement | null>(null)

const isBreadCrumbsShowing = computed(
() => isAnyActivityFilterActive() && tablet.value
)

const collectionId = computed(() => route.params.id)
const { events, flippers, owners, offers } = useCollectionActivity({
collectionId: collectionId.value,
})

const InteractionIncluded = [
Interaction.BUY,
Interaction.LIST,
mintInteraction(),
Interaction.SEND,
]

const filteredEvents = computed(() =>
events.value.filter((event) =>
InteractionIncluded.includes(event.interaction as Interaction)
)
)
const withOffers = computed(() => [...filteredEvents.value, ...offers.value])

// newest events first (bigger timestamp first)
const sortedEventsWithOffersDesc = computed(() =>
withOffers.value.sort((a, b) => b.timestamp - a.timestamp)
)

useResizeObserver(wrapper, (entry) => {
if (entry[0].contentRect.width >= mobileBreakpoint) {
tablet.value = true
} else {
tablet.value = false
}
})
</script>

<style lang="scss" scoped>
.gap {
gap: 2.5rem;
}
.my-40 {
margin: 2.5rem 0;
}
.mb-40 {
margin-bottom: 2.5rem;
}
.is-flex-basis-two-thirds {
flex-basis: 66.6%;
}
.is-flex-basis-auto {
flex-basis: auto;
}

//hack to make the chart responsive
.max-width {
max-width: calc(100% - 1px);
}
</style>
53 changes: 53 additions & 0 deletions components/collection/activity/ActivityChart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<PriceChart
v-if="events.length > 0"
:price-chart-data="chartData"
chart-height="350px" />
</template>

<script setup lang="ts">
import { ActivityInteraction } from '@/components/rmrk/service/scheme'
import { Interaction } from '@kodadot1/minimark'
import PriceChart from '@/components/chart/PriceChart.vue'
import { bin, displayValue, sortAsc, toDataPoint } from './utils'

const props = withDefaults(
defineProps<{
events: ActivityInteraction[]
}>(),
{
events: () => [],
}
)

const buyEvents = computed(() =>
sortAsc(
props.events
.filter((e) => e.interaction === Interaction.BUY)
.map(toDataPoint)
)
)
const listEvents = computed(() =>
sortAsc(
props.events
.filter((e) => e.interaction === Interaction.LIST)
.map(toDataPoint)
)
)

const chartData = computed(() => {
const buyBins = bin(buyEvents.value, { days: 1 })
const listBins = bin(listEvents.value, { days: 1 })

const binnedBuyEvents = buyBins.map(({ timestamp, value }) => [
new Date(timestamp),
displayValue(value),
]) as [Date, number][]
const binnedListEvents = listBins.map(({ timestamp, value }) => [
new Date(timestamp),
displayValue(value),
]) as [Date, number][]

return [binnedBuyEvents, binnedListEvents]
})
</script>
51 changes: 51 additions & 0 deletions components/collection/activity/OwnerInsights.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<template>
<div class="fixed-height border">
<div class="py-4 px-5 is-flex border-bottom" aria-label="controls">
<div
class="mr-4 is-clickable"
:class="{ 'has-text-weight-bold': activeTab === Tabs.holders }"
@click="activeTab = Tabs.holders">
{{ $t('holders') }}
</div>
<div
class="is-clickable"
:class="{ 'has-text-weight-bold': activeTab === Tabs.flippers }"
@click="activeTab = Tabs.flippers">
{{ $t('flippers') }}
</div>
</div>
<div class="py-4 limit-height is-scrollable">
<HoldersTab v-if="activeTab === Tabs.holders" :owners="owners" />
<FlippersTab v-if="activeTab === Tabs.flippers" :flippers="flippers" />
</div>
</div>
</template>

<script setup lang="ts">
import HoldersTab from './ownerInsightsTabs/HolderTab.vue'
import FlippersTab from './ownerInsightsTabs/FlipperTab.vue'
import { Flippers, Owners } from '@/composables/collectionActivity/types'

enum Tabs {
holders,
flippers,
}

defineProps<{
owners?: Owners
flippers?: Flippers
}>()
const activeTab = ref(Tabs.holders)
</script>

<style lang="scss" scoped>
.fixed-height {
height: 350px;
}
.limit-height {
max-height: 290px;
}
.is-scrollable {
overflow-y: auto;
}
</style>
20 changes: 20 additions & 0 deletions components/collection/activity/events/EventRow.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<template>
<div>
<EventRowDesktop v-if="variant === 'Desktop'" :event="event" />
<EventRowTablet v-else :event="event" />
</div>
</template>

<script setup lang="ts">
import {
InteractionWithNFT,
Offer,
} from '@/composables/collectionActivity/types'
import EventRowDesktop from './eventRow/EventRowDesktop.vue'
import EventRowTablet from './eventRow/EventRowTablet.vue'

defineProps<{
event: InteractionWithNFT | Offer
variant: 'Touch' | 'Desktop'
}>()
</script>
Loading