mirror of
https://github.com/quantum5/qcal.git
synced 2025-04-24 17:51:57 -04:00
Factor out reusable MobileTooltip component
Also prevents tabIndex from being generated on desktop
This commit is contained in:
parent
1a7c4915e1
commit
8c238c6625
20
common/src/MobileTooltip.scss
Normal file
20
common/src/MobileTooltip.scss
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
@media (pointer: coarse), (hover: none) {
|
||||||
|
.MobileTooltip {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&:focus::after {
|
||||||
|
content: attr(title);
|
||||||
|
position: absolute;
|
||||||
|
top: 90%;
|
||||||
|
left: 0;
|
||||||
|
color: #000;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid;
|
||||||
|
width: fit-content;
|
||||||
|
padding: 3px;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
common/src/MobileTooltip.tsx
Normal file
31
common/src/MobileTooltip.tsx
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import {useEffect} from 'react';
|
||||||
|
|
||||||
|
const MobileTooltipContext = React.createContext(false);
|
||||||
|
|
||||||
|
export function MobileTooltipProvider({children}: React.PropsWithChildren<{}>): JSX.Element {
|
||||||
|
const [mobile, setMobile] = React.useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!window.matchMedia)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const match = window.matchMedia('(pointer: coarse), (hover: none)');
|
||||||
|
const callback = () => setMobile(match.matches);
|
||||||
|
|
||||||
|
callback();
|
||||||
|
match.addEventListener('change', callback);
|
||||||
|
return () => match.removeEventListener('change', callback);
|
||||||
|
}, [setMobile]);
|
||||||
|
|
||||||
|
return <MobileTooltipContext.Provider value={mobile}>
|
||||||
|
{children}
|
||||||
|
</MobileTooltipContext.Provider>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMobileTooltipProps(): { className: string, tabIndex?: number } {
|
||||||
|
return {
|
||||||
|
className: 'MobileTooltip',
|
||||||
|
...React.useContext(MobileTooltipContext) ? {tabIndex: 0} : {},
|
||||||
|
};
|
||||||
|
}
|
|
@ -147,26 +147,6 @@
|
||||||
background: $gray-300;
|
background: $gray-300;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (pointer: coarse), (hover: none) {
|
|
||||||
.Day-rural {
|
|
||||||
position: relative;
|
|
||||||
display: inline-flex;
|
|
||||||
justify-content: center;
|
|
||||||
text-decoration: underline dashed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Day-rural:focus::after {
|
|
||||||
content: attr(title);
|
|
||||||
position: absolute;
|
|
||||||
top: 90%;
|
|
||||||
color: #000;
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid;
|
|
||||||
width: fit-content;
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.Calendar-month-name.input-group {
|
.Calendar-month-name.input-group {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
} from '@common/french';
|
} from '@common/french';
|
||||||
import {jdnDate} from '@common/gregorian';
|
import {jdnDate} from '@common/gregorian';
|
||||||
import {jdnLongCount} from '@common/longCount';
|
import {jdnLongCount} from '@common/longCount';
|
||||||
|
import {useMobileTooltipProps} from '@common/MobileTooltip';
|
||||||
|
|
||||||
type MonthProps = {
|
type MonthProps = {
|
||||||
year: number;
|
year: number;
|
||||||
|
@ -39,10 +40,11 @@ function DayDetail({jdn}: { jdn: number }): JSX.Element {
|
||||||
function NormalDay({year, month, day, todayJDN}: DateProps & { todayJDN: number }): JSX.Element {
|
function NormalDay({year, month, day, todayJDN}: DateProps & { todayJDN: number }): JSX.Element {
|
||||||
const jdn = frJDN(year, month, day);
|
const jdn = frJDN(year, month, day);
|
||||||
const rural = dateRuralName(month, day)!;
|
const rural = dateRuralName(month, day)!;
|
||||||
|
const mobile = useMobileTooltipProps();
|
||||||
return <div className={`Day NormalDay ${jdn === todayJDN ? 'Day-today' : ''}`}>
|
return <div className={`Day NormalDay ${jdn === todayJDN ? 'Day-today' : ''}`}>
|
||||||
<div className="Day-name">{day}</div>
|
<div className="Day-name">{day}</div>
|
||||||
<div className="Day-decade">{decadeNames[(day - 1) % 10]}</div>
|
<div className="Day-decade">{decadeNames[(day - 1) % 10]}</div>
|
||||||
<div className="Day-rural" title={rural.title} tabIndex={0}>{rural.name}</div>
|
<div className="Day-rural"><abbr title={rural.title} {...mobile}>{rural.name}</abbr></div>
|
||||||
<DayDetail jdn={jdn}/>
|
<DayDetail jdn={jdn}/>
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
@import 'bootstrap/scss/forms';
|
@import 'bootstrap/scss/forms';
|
||||||
@import 'bootstrap/scss/root';
|
@import 'bootstrap/scss/root';
|
||||||
@import './consts';
|
@import './consts';
|
||||||
|
@import '@common/MobileTooltip.scss';
|
||||||
|
|
||||||
body {
|
body {
|
||||||
padding-top: $spacer * 4;
|
padding-top: $spacer * 4;
|
||||||
|
|
|
@ -4,12 +4,15 @@ import 'bootstrap/js/dist/collapse';
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import reportWebVitals from './reportWebVitals';
|
import reportWebVitals from './reportWebVitals';
|
||||||
|
import {MobileTooltipProvider} from '@common/MobileTooltip';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<MobileTooltipProvider>
|
||||||
|
<App/>
|
||||||
|
</MobileTooltipProvider>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById('root')
|
document.getElementById('root'),
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
// If you want to start measuring performance in your app, pass a function
|
||||||
|
|
|
@ -167,24 +167,3 @@
|
||||||
.Calendar-today-button {
|
.Calendar-today-button {
|
||||||
max-width: 5em;
|
max-width: 5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (pointer: coarse), (hover: none) {
|
|
||||||
.DayDetail abbr {
|
|
||||||
position: relative;
|
|
||||||
display: inline-flex;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
&:focus::after {
|
|
||||||
content: attr(title);
|
|
||||||
position: absolute;
|
|
||||||
top: 90%;
|
|
||||||
left: 0;
|
|
||||||
color: #000;
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid;
|
|
||||||
width: fit-content;
|
|
||||||
padding: 3px;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {formatJG, jdnGregorian, JulianDay, JulianMonth, monthName, weekdayNames}
|
||||||
import {jdnLongCount} from '@common/longCount';
|
import {jdnLongCount} from '@common/longCount';
|
||||||
import {jdnJulian, julianJDN, julianMonthDays} from '@common/julian';
|
import {jdnJulian, julianJDN, julianMonthDays} from '@common/julian';
|
||||||
import {frDateFormat, frEndJD, frStartJD, jdnFrench} from '@common/french';
|
import {frDateFormat, frEndJD, frStartJD, jdnFrench} from '@common/french';
|
||||||
|
import {useMobileTooltipProps} from '@common/MobileTooltip';
|
||||||
|
|
||||||
type MonthProps = {
|
type MonthProps = {
|
||||||
year: number;
|
year: number;
|
||||||
|
@ -20,18 +21,19 @@ function WeekdayName({name}: { name: string }): JSX.Element {
|
||||||
|
|
||||||
function DayDetail({jdn}: { jdn: number }): JSX.Element {
|
function DayDetail({jdn}: { jdn: number }): JSX.Element {
|
||||||
const lc = jdnLongCount(jdn);
|
const lc = jdnLongCount(jdn);
|
||||||
|
const mobile = useMobileTooltipProps();
|
||||||
return <div className="DayDetail">
|
return <div className="DayDetail">
|
||||||
<div className="DayDetail-jdn"><abbr title="Julian day number" tabIndex={0}>JD</abbr> {jdn}</div>
|
<div className="DayDetail-jdn"><abbr title="Julian day number" {...mobile}>JD</abbr> {jdn}</div>
|
||||||
<div className="DayDetail-gregorian">
|
<div className="DayDetail-gregorian">
|
||||||
<abbr title="Gregorian date" tabIndex={0}>G.</abbr>{' '}
|
<abbr title="Gregorian date" {...mobile}>G.</abbr>{' '}
|
||||||
{formatJG(jdnGregorian(jdn))}
|
{formatJG(jdnGregorian(jdn))}
|
||||||
</div>
|
</div>
|
||||||
{lc && <div className="DayDetail-lc">
|
{lc && <div className="DayDetail-lc">
|
||||||
<abbr title="Mesoamerican long count date" tabIndex={0}>LC</abbr>{' '}
|
<abbr title="Mesoamerican long count date" {...mobile}>LC</abbr>{' '}
|
||||||
{lc.join('.\u200b')}
|
{lc.join('.\u200b')}
|
||||||
</div>}
|
</div>}
|
||||||
{jdn >= frStartJD && jdn <= frEndJD && <div className="DayDetail-fr">
|
{jdn >= frStartJD && jdn <= frEndJD && <div className="DayDetail-fr">
|
||||||
<abbr title="French Republican Calendar" tabIndex={0}>FR</abbr>{' '}
|
<abbr title="French Republican Calendar" {...mobile}>FR</abbr>{' '}
|
||||||
{frDateFormat(jdnFrench(jdn))}
|
{frDateFormat(jdnFrench(jdn))}
|
||||||
</div>}
|
</div>}
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
@import 'bootstrap/scss/forms';
|
@import 'bootstrap/scss/forms';
|
||||||
@import 'bootstrap/scss/root';
|
@import 'bootstrap/scss/root';
|
||||||
@import './consts';
|
@import './consts';
|
||||||
|
@import '@common/MobileTooltip.scss';
|
||||||
|
|
||||||
body {
|
body {
|
||||||
padding-top: $spacer * 4;
|
padding-top: $spacer * 4;
|
||||||
|
|
|
@ -4,12 +4,15 @@ import 'bootstrap/js/dist/collapse';
|
||||||
import './index.scss';
|
import './index.scss';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import reportWebVitals from './reportWebVitals';
|
import reportWebVitals from './reportWebVitals';
|
||||||
|
import {MobileTooltipProvider} from '@common/MobileTooltip';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<MobileTooltipProvider>
|
||||||
|
<App/>
|
||||||
|
</MobileTooltipProvider>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.getElementById('root')
|
document.getElementById('root'),
|
||||||
);
|
);
|
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
// If you want to start measuring performance in your app, pass a function
|
||||||
|
|
Loading…
Reference in a new issue