-
- Description
-
-
+
+
+ Description
+
+
+
The total amount sent (in Nano) and total amount of voting weight
changed per day.
-
- {!isLoading && (
-
-
- Download CSV
-
-
- Download JSON
-
-
- )}
+
+ {!isLoading && (
+
+
+ Download CSV
+
+
+ Download JSON
+
+
+ )}
+
+
- {value === index && children}
-
- )
-}
-
-TabPanel.propTypes = {
- children: PropTypes.element,
- value: PropTypes.number,
- index: PropTypes.number
-}
-
export default function LedgerPage({ load, data, isLoading }) {
- const [value, setValue] = useState(0)
+ const previous_filter_text = useRef('')
+ const [cached_open_categories, set_cached_open_categories] = useState({
+ Addresses: true
+ })
+ const [selected_chart, set_selected_chart] = useState([
+ 'Addresses',
+ 'Address Counts'
+ ])
+ const [filter_text, set_filter_text] = useState('')
+ const [open_categories, set_open_categories] = useState({ Addresses: true })
+ const [filtered_categories, set_filtered_categories] = useState({})
+ const [menu_open, set_menu_open] = useState(false)
+ const filter_input_ref = useRef(null)
useEffect(() => {
load()
}, [])
- const handleChange = (event, value) => {
- setValue(value)
+ useEffect(() => {
+ if (filter_text.length > 0) {
+ const result = {}
+
+ for (const key of Object.keys(categories)) {
+ const item = categories[key]
+
+ if (React.isValidElement(item) && fuzzySearch(filter_text, key)) {
+ result[key] = item
+ } else {
+ const charts = {}
+ for (const chart_key of Object.keys(item)) {
+ if (fuzzySearch(filter_text, chart_key)) {
+ charts[chart_key] = item[chart_key]
+ }
+ }
+ if (Object.keys(charts).length > 0) {
+ result[key] = charts
+ }
+ }
+ }
+
+ set_filtered_categories(result)
+ }
+
+ if (filter_text.length && !previous_filter_text.current.length) {
+ set_cached_open_categories({ ...open_categories })
+ }
+
+ if (filter_text.length === 0 && previous_filter_text.current.length) {
+ set_open_categories(cached_open_categories)
+ }
+
+ previous_filter_text.current = filter_text
+ }, [filter_text])
+
+ useEffect(() => {
+ if (filter_text.length > 0) {
+ // Uncollapse all categories when filtering
+ set_open_categories(
+ Object.keys(filtered_categories).reduce(
+ (acc, key) => ({ ...acc, [key]: true }),
+ {}
+ )
+ )
+ }
+ }, [filtered_categories])
+
+ useEffect(() => {
+ if (menu_open) {
+ setTimeout(() => {
+ filter_input_ref.current.focus()
+ }, 300) // Delay to allow for transition effects
+ } else {
+ filter_input_ref.current.blur()
+ set_filter_text('')
+ }
+ }, [menu_open])
+
+ useEffect(() => {
+ const updateMenuHeight = () => {
+ const menuElement = document.querySelector('.ledger__menu-button')
+ const toggleButtonElement = document.querySelector(
+ '.ledger__toggle-button'
+ )
+ if (menuElement && toggleButtonElement) {
+ if (menu_open) {
+ menuElement.style.height = ''
+ } else {
+ menuElement.style.height = `${toggleButtonElement.scrollHeight}px`
+ }
+ }
+ }
+
+ window.addEventListener('resize', updateMenuHeight)
+ updateMenuHeight()
+
+ return () => {
+ window.removeEventListener('resize', updateMenuHeight)
+ }
+ }, [menu_open, selected_chart])
+
+ const handle_menu_toggle = () => {
+ set_menu_open(!menu_open)
+ }
+
+ const handle_click_away = () => {
+ set_menu_open(false)
+ set_filter_text('')
+ }
+
+ const toggle_category = (category) => {
+ set_open_categories((prev) => ({ ...prev, [category]: !prev[category] }))
+ }
+
+ const categories = {
+ Addresses: {
+ 'Address Counts': (
+
+ )
+ },
+ Blocks: {
+ 'Block Counts':
+ },
+ Transactions: {
+ 'Value Transferred': (
+
+ ),
+ 'Transfer Volume': (
+
+ ),
+ 'Transfer Amounts': (
+
+ )
+ },
+ Distribution: {
+ 'Address Supply Distribution': (
+
+ )
+ }
+ }
+
+ const render_category = (category, charts, depth) => {
+ const is_open = open_categories[category] || false
+ return (
+ <>
+
toggle_category(category)}
+ className={`ledger__category ledger__category-depth-${depth}`}>
+
+
+
+
+
+
+ {Object.entries(charts).map(([key, value]) => {
+ const is_selected =
+ selected_chart[0] === category && selected_chart[1] === key
+ const item_class = is_selected ? 'ledger__chart--selected' : ''
+ if (React.isValidElement(value)) {
+ return (
+ set_selected_chart([category, key])}
+ className={`ledger__chart ledger__category-depth-${
+ depth + 1
+ } ${item_class}`}>
+
+
+ )
+ } else {
+ return render_category(key, value, depth + 1)
+ }
+ })}
+
+
+ >
+ )
}
return (
@@ -62,38 +223,49 @@ export default function LedgerPage({ load, data, isLoading }) {
'transactions'
]}
/>
+
+
+
+
+ {selected_chart.join(' > ')}
+
+
+ set_filter_text(e.target.value)}
+ inputRef={filter_input_ref}
+ />
+
+
+
+ {Object.entries(
+ filter_text.length > 0 ? filtered_categories : categories
+ ).map(([category, charts]) =>
+ render_category(category, charts, 0)
+ )}
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ {selected_chart.reduce((acc, key) => acc[key], categories)}
+
diff --git a/src/views/pages/ledger/ledger.styl b/src/views/pages/ledger/ledger.styl
index ecbea07e..d87a296c 100644
--- a/src/views/pages/ledger/ledger.styl
+++ b/src/views/pages/ledger/ledger.styl
@@ -1,17 +1,62 @@
.ledger__body
display flex
- flex-direction column
+ flex-direction row
padding 24px 32px
- max-width 1300px
- width 100%
- margin 0 auto
+ align-items flex-start
.ledger__metric
+ display flex
+ flex-direction column
+ flex 1
width 100%
-.ledger__body-menu
- background white
- border-radius 4px
+.ledger__category
+ padding-top 4px
+ padding-bottom 4px
+ border-radius 6px
+ .MuiTypography-root
+ font-size 0.875rem
+ line-height 1.5
+ color #1C2025
+ font-weight 600
+
+.ledger__chart
+ padding-top 4px
+ padding-bottom 4px
+ border-radius 6px
+ .MuiTypography-root
+ font-size 0.875rem
+ line-height 1.5
+ color #1C2025
+ font-weight 500
+ &.ledger__chart--selected
+ background-color hsl(210, 100%, 96%)
+ color hsl(210, 100%, 42%)
+
+.ledger__category-depth-0
+ padding-left 2px
+
+.ledger__category-depth-1
+ padding-left 36px
+ &:before
+ content: "";
+ display: block;
+ position: absolute;
+ z-index: 1;
+ left: 9.5px;
+ height: 100%;
+ width: 1px;
+ opacity: 1;
+ background: #E5EAF2
+
+ &.ledger__chart--selected:before
+ background hsl(210, 100%, 60%)
+
+.ledger__category-depth-2
+ padding-left 49px
+
+.ledger__category-depth-3
+ padding-left 62px
.ledger__footer
margin 32px auto
@@ -21,11 +66,12 @@
.ledger__chart-sections
display flex
flex-wrap wrap
+ justify-content center
.ledger__chart-section
- max-width 500px
+ max-width 300px
margin 16px
- flex 1 0 300px
+ flex 1 0 250px
.ledger__chart-section-body
padding 0 12px
@@ -46,6 +92,78 @@
p
margin-bottom 16px
+.ledger__chart-description
+ background white
+ padding 16px
+ border-radius 4px
+ max-width 800px
+ margin 16px auto 0
+ width 100%
+
+ .section__heading span
+ background white
+
+.ledger__menu-button
+ opacity 1
+ pointer-events all
+ position fixed
+ top 10px
+ left 50%
+ transform translateX(-50%) scale(1)
+ z-index 101
+ background-color white
+ border-radius 8px
+ width 30%
+ display flex
+ flex-direction column
+ align-items stretch
+ cursor pointer
+ height 40px
+ transition transform 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, width 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, height 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms
+ overflow hidden
+ border 1px solid rgba(0, 0, 0, 0.23)
+ &:hover
+ border 1px solid rgba(0, 0, 0, 0.23)
+ box-shadow #D0D0D0 4px 4px 0px 0px
+
+ &.ledger__menu--open
+ border 1px solid rgba(0, 0, 0, 0.23)
+ box-shadow #D0D0D0 4px 4px 0px 0px
+ width 60%
+ height 80vh // Adjust height as needed for full visibility
+
+.ledger__toggle-button
+ padding 8px 16px
+ border none
+ border-radius 4px
+ cursor pointer
+ display flex
+ align-items center
+ justify-content flex-start
+ &:hover
+ color #4A90E2
+ font-weight 600
+
+.ledger__filter-container
+ padding 0 16px
+ border-top 1px solid rgba(0, 0, 0, 0.23)
+
+.ledger__category-container
+ padding 0 8px
+ display flex
+ flex-direction column
+ overflow-y auto
+ border-top 1px solid rgba(0, 0, 0, 0.23)
+
+@media (max-width 750px)
+ .ledger__body
+ flex-direction column
+ .ledger__menu-button
+ width 60%
+
@media (min-width 750px)
- .ledger__body-menu
- margin 0 64px
+ .ledger__menu-button
+ width 30%
+ max-width 500px
+ &.ledger__menu--open
+ max-width 500px
\ No newline at end of file