Skip to content

Commit 939409c

Browse files
committed
Improve modal mobile design
- Enable horizontal scroll for details modal on mobile - Add responsive spacing and positioning to modal
1 parent 9f49efc commit 939409c

8 files changed

Lines changed: 48 additions & 42 deletions

File tree

assets/css/app.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
--color-gray-950: var(--color-zinc-950);
9191

9292
/* Custom gray shades from config (override some zinc values) */
93+
--color-gray-75: rgb(247 247 248);
9394
--color-gray-150: rgb(236 236 238);
9495
--color-gray-750: rgb(50 50 54);
9596
--color-gray-825: rgb(35 35 38);
@@ -295,7 +296,7 @@ blockquote {
295296
}
296297

297298
.table-striped tbody tr:nth-child(odd) td {
298-
background-color: var(--color-gray-100);
299+
background-color: var(--color-gray-75);
299300
}
300301

301302
.dark .table-striped tbody tr:nth-child(odd) td {

assets/css/modal.css

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@
3232
overflow: auto;
3333
}
3434

35-
.modal__content {
36-
margin-bottom: 2rem;
37-
}
38-
3935
@keyframes mm-fade-in {
4036
from {
4137
opacity: 0;

assets/js/dashboard/stats/modals/breakdown-modal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export default function BreakdownModal<TListItem extends { name: string }>({
125125
{
126126
label: reportInfo.dimensionLabel,
127127
key: 'name',
128-
width: 'w-48 md:w-full flex items-center break-all',
128+
width: 'min-w-48 w-full flex items-center break-all',
129129
align: 'left',
130130
renderItem: (item) => (
131131
<NameCell

assets/js/dashboard/stats/modals/breakdown-table.tsx

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import { ColumnConfiguraton, Table } from '../../components/table'
55
import RocketIcon from './rocket-icon'
66
import { QueryStatus } from '@tanstack/react-query'
77

8-
const MIN_HEIGHT_PX = 500
9-
108
export const BreakdownTable = <TListItem extends { name: string }>({
119
title,
1210
isPending,
@@ -39,9 +37,9 @@ export const BreakdownTable = <TListItem extends { name: string }>({
3937

4038
return (
4139
<>
42-
<div className="flex justify-between items-center">
43-
<div className="flex items-center gap-x-2">
44-
<h1 className="text-lg font-bold dark:text-gray-100">{title}</h1>
40+
<div className="flex justify-between items-center gap-4">
41+
<div className="flex items-center gap-x-2 shrink-0">
42+
<h1 className="shrink-0 text-base md:text-lg font-bold dark:text-gray-100">{title}</h1>
4543
{!isPending && isFetching && <SmallLoadingSpinner />}
4644
</div>
4745
{!!onSearch && (
@@ -54,8 +52,8 @@ export const BreakdownTable = <TListItem extends { name: string }>({
5452
/>
5553
)}
5654
</div>
57-
<div className="my-4 border-b border-gray-250 dark:border-gray-700"></div>
58-
<div className="flex-1 overflow-y-auto pr-3 -mr-3" style={{ minHeight: `${MIN_HEIGHT_PX}px` }}>
55+
<div className="my-3 md:my-4 border-b border-gray-250 dark:border-gray-700"></div>
56+
<div className="flex-1 overflow-auto pr-4 -mr-4">
5957
{displayError && status === 'error' && <ErrorMessage error={error} />}
6058
{isPending && <InitialLoadingSpinner />}
6159
{data && <Table<TListItem> data={data} columns={columns} />}
@@ -73,7 +71,6 @@ export const BreakdownTable = <TListItem extends { name: string }>({
7371
const InitialLoadingSpinner = () => (
7472
<div
7573
className="w-full h-full flex flex-col justify-center"
76-
style={{ minHeight: `${MIN_HEIGHT_PX}px` }}
7774
>
7875
<div className="mx-auto loading">
7976
<div />
@@ -90,7 +87,6 @@ const SmallLoadingSpinner = () => (
9087
const ErrorMessage = ({ error }: { error?: unknown }) => (
9188
<div
9289
className="grid grid-rows-2 text-gray-700 dark:text-gray-300"
93-
style={{ height: `${MIN_HEIGHT_PX}px` }}
9490
>
9591
<div className="text-center self-end">
9692
<RocketIcon />

assets/js/dashboard/stats/modals/entry-pages.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function EntryPagesModal() {
7575
return [
7676
metrics.createVisitors({ renderLabel: (_query) => 'Visitors' }),
7777
metrics.createVisits({
78-
renderLabel: (_query) => 'Total Entrances',
78+
renderLabel: (_query) => 'Total entrances',
7979
width: 'w-36'
8080
}),
8181
metrics.createBounceRate(),

assets/js/dashboard/stats/modals/exit-pages.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function ExitPagesModal() {
7575
sortable: true
7676
}),
7777
metrics.createVisits({
78-
renderLabel: (_query) => 'Total Exits',
78+
renderLabel: (_query) => 'Total exits',
7979
sortable: true
8080
}),
8181
metrics.createExitRate()

assets/js/dashboard/stats/modals/filter-modal.js

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react'
2+
import { XMarkIcon } from '@heroicons/react/20/solid'
23
import { useParams } from 'react-router-dom'
34

45
import Modal from './modal'
@@ -68,6 +69,7 @@ class FilterModal extends React.Component {
6869
)
6970

7071
this.handleKeydown = this.handleKeydown.bind(this)
72+
this.closeModal = this.closeModal.bind(this)
7173
this.state = {
7274
query,
7375
filterState,
@@ -108,6 +110,13 @@ class FilterModal extends React.Component {
108110
)
109111
}
110112

113+
closeModal() {
114+
this.props.navigate({
115+
path: rootRoute.path,
116+
search: (search) => search
117+
})
118+
}
119+
111120
selectFiltersAndCloseModal(filters) {
112121
this.props.navigate({
113122
path: rootRoute.path,
@@ -169,13 +178,23 @@ class FilterModal extends React.Component {
169178

170179
render() {
171180
return (
172-
<Modal maxWidth="460px">
173-
<h1 className="text-lg font-bold dark:text-gray-100">
174-
Filter by {formatFilterGroup(this.props.modalType)}
175-
</h1>
181+
<Modal maxWidth="460px" onClose={this.closeModal}>
182+
<div className="flex items-center justify-between gap-3">
183+
<h1 className="text-base md:text-lg font-bold dark:text-gray-100">
184+
Filter by {formatFilterGroup(this.props.modalType)}
185+
</h1>
186+
<button
187+
type="button"
188+
onClick={this.closeModal}
189+
aria-label="Close modal"
190+
className="text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300"
191+
>
192+
<XMarkIcon className="size-5" />
193+
</button>
194+
</div>
176195

177-
<div className="mt-4 border-b border-gray-300 dark:border-gray-700"></div>
178-
<main className="modal__content">
196+
<div className="mt-2 md:mt-4 border-b border-gray-300 dark:border-gray-700"></div>
197+
<main>
179198
<form
180199
className="flex flex-col"
181200
onSubmit={this.handleSubmit.bind(this)}
@@ -192,7 +211,7 @@ class FilterModal extends React.Component {
192211
/>
193212
))}
194213

195-
<div className="mt-6 flex gap-x-4 items-center justify-start">
214+
<div className="mt-6 mb-3 flex gap-x-4 items-center justify-start">
196215
<button
197216
type="submit"
198217
className="button !px-3"

assets/js/dashboard/stats/modals/modal.js

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React, { useEffect } from 'react'
22
import { createPortal } from 'react-dom'
3-
import { XMarkIcon } from '@heroicons/react/20/solid'
43
import { isModifierPressed, isTyping, Keybind } from '../../keybinding'
54
import { rootRoute } from '../../router'
65
import { useAppNavigate } from '../../navigation/use-app-navigate'
@@ -62,7 +61,7 @@ class Modal extends React.Component {
6261
if (maxWidth) {
6362
styleObject.maxWidth = maxWidth
6463
} else {
65-
styleObject.width = viewport <= MD_WIDTH ? 'min-content' : '880px'
64+
styleObject.maxWidth = '880px'
6665
}
6766
return styleObject
6867
}
@@ -79,22 +78,17 @@ class Modal extends React.Component {
7978
/>
8079
<div className="modal is-open" onClick={this.props.onClick}>
8180
<div className="modal__overlay">
82-
<button
83-
className="fixed top-3 right-6 text-gray-300 hover:text-gray-100 transition-colors duration-150"
84-
onClick={this.props.onClose}
85-
aria-label="Close modal"
86-
>
87-
<XMarkIcon className="size-10" />
88-
</button>
89-
<div
90-
ref={this.node}
91-
className="[--gap:4rem] my-[var(--gap)] max-h-[calc(100dvh_-_var(--gap)*2)] flex flex-col bg-white px-6 py-4 mx-auto box-border transition-[height] duration-200 ease-in shadow-2xl rounded-lg dark:bg-gray-900 focus:outline-hidden"
92-
style={this.getStyle()}
93-
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
94-
tabIndex={0}
95-
>
96-
<FocusOnMount focusableRef={this.node} />
97-
{this.props.children}
81+
<div className="[--gap:1rem] sm:[--gap:2rem] md:[--gap:4rem] flex h-full w-full items-end md:items-start justify-center px-[var(--gap)] py-[var(--gap)] box-border">
82+
<div
83+
ref={this.node}
84+
className="max-h-[calc(100dvh_-_var(--gap)*2)] md:min-h-120 w-full flex flex-col bg-white p-3 md:px-6 md:py-4 overflow-hidden box-border transition-[height] duration-200 ease-in shadow-2xl rounded-lg dark:bg-gray-900 focus:outline-hidden"
85+
style={this.getStyle()}
86+
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
87+
tabIndex={0}
88+
>
89+
<FocusOnMount focusableRef={this.node} />
90+
{this.props.children}
91+
</div>
9892
</div>
9993
</div>
10094
</div>

0 commit comments

Comments
 (0)