Skip to content

Commit

Permalink
Merge pull request #39 from BenoitBellegarde/feature/fontsize-mangement
Browse files Browse the repository at this point in the history
feat: Add font size mangement for tab page + improve browser resize detection
  • Loading branch information
BenoitBellegarde authored Nov 23, 2024
2 parents 3705531 + 937af9e commit 044829d
Show file tree
Hide file tree
Showing 13 changed files with 278 additions and 86 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ A web application that delivers an enhanced, ads-free and fast responsive interf
- Chords visualizer with official diagrams from Ultimate Guitar.
- Chords transposer.
- Autoscroll tab.
- Font size management
- Backing track player (using YouTube API).
- Add tabs to favorites without the need for an account (stored in local storage).

Expand Down
15 changes: 11 additions & 4 deletions src/components/Autoscroller.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,21 @@ export default function Autoscroller({
const requestAnimationFrameRef = useRef<number>(0)
const manualScrollintervalRef = useRef<NodeJS.Timeout>(null)

if (typeof document !== 'undefined') {
var isTouch = 'ontouchstart' in document.documentElement
}

const formatSpeed = (scrollSpeed: number) => {
const base100 = 200000
const percent = base100 / scrollSpeed
return Math.round(percent * 100)
}

const handlePlayButton = () => {
setIsScrolling((isScrolling) => !isScrolling)
setIsEnabled((isEnabled) => !isEnabled)
}

const resetRequestAnimationFrame = () => {
cancelAnimationFrame(requestAnimationFrameRef.current)
requestAnimationFrameRef.current = null
Expand Down Expand Up @@ -157,10 +166,8 @@ export default function Autoscroller({
color: 'white',
}}
isActive={isEnabled}
onClick={() => {
setIsScrolling((isScrolling) => !isScrolling)
setIsEnabled((isEnabled) => !isEnabled)
}}
onTouchStart={handlePlayButton}
onMouseDown={!isTouch ? handlePlayButton : undefined}
size={'sm'}
boxShadow="md"
fontWeight={'normal'}
Expand Down
48 changes: 48 additions & 0 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Text, Stack, Divider, Link, IconButton, Flex } from '@chakra-ui/react'
import { FaGithub } from 'react-icons/fa'

export default function Nav({}: {}): JSX.Element {
const version: string = process.env.NEXT_PUBLIC_UT_VERSION
return (
<footer>
<Divider mt={4} />

<Flex
direction={'row'}
justifyContent="space-between"
alignItems={'center'}
p={2}
>
<Text fontSize="md">
Built by{' '}
<Link
href="https://github.com/BenoitBellegarde/"
textDecoration="underline"
_hover={{ textDecoration: 'underline' }}
isExternal
>
Benoit Bellegarde
</Link>
</Text>

<Flex direction={'row'} alignItems={'center'}>
<Text fontSize="md" mr={2}>
ver {version}
</Text>
<IconButton
size={'sm'}
key={'github-icon'}
as={Link}
isExternal
href={'https://github.com/BenoitBellegarde/UltimateTab/'}
aria-label={'Github page'}
bg={'blackAlpha.800'}
color={'white'}
icon={<FaGithub />}
rounded="md"
/>
</Flex>
</Flex>
</footer>
)
}
2 changes: 2 additions & 0 deletions src/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Container, Flex } from '@chakra-ui/react'
import { useRouter } from 'next/router'
import { ReactNode, useRef } from 'react'
import Backdrop from './Backdrop'
import Footer from './Footer'
import Nav from './Nav'

interface LayoutProps {
Expand All @@ -20,6 +21,7 @@ export default function Layout({ children }: LayoutProps): JSX.Element {
<Flex grow={1} direction={flexDirectionContent}>
{children}
</Flex>
<Footer></Footer>
</Flex>
</Container>
</>
Expand Down
127 changes: 77 additions & 50 deletions src/components/TabPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,33 @@ import {
Menu,
MenuButton,
MenuItem,
MenuItemOption,
MenuList,
MenuOptionGroup,
Skeleton,
Text,
Tooltip,
useBreakpointValue,
useColorModeValue,
useToast,
} from '@chakra-ui/react'
import HTMLReactParser from 'html-react-parser'
import { GiGuitarHead } from 'react-icons/gi'
import { RiHeartFill, RiHeartLine } from 'react-icons/ri'
import { MdFontDownload } from 'react-icons/md'
import { FaCircleArrowDown } from 'react-icons/fa6'
import { GiMusicalScore } from 'react-icons/gi'
import { GiCrowbar } from 'react-icons/gi'
import Difficulty from './Difficulty'
import ChordDiagram from './ChordDiagram'
import { Tab, UGChordCollection } from '../types/tabs'
import {
MouseEventHandler,
useEffect,
useLayoutEffect,
useRef,
useState,
} from 'react'
import { MouseEventHandler, useEffect, useRef, useState } from 'react'
import { useRouter } from 'next/router'
import useDebounce from '../hooks/useDebounce'
import { FaPlayCircle } from 'react-icons/fa'
import ChordTransposer from './ChordTransposer'
import BackingtrackPlayer from './BackingtrackPlayer'
import Autoscroller from './Autoscroller'
import useAppStateContext from '../hooks/useAppStateContext'

interface TabPanelProps {
selectedTab: Tab
Expand All @@ -55,17 +53,14 @@ export default function TabPanel({
refetchTab,
}: TabPanelProps) {
const router = useRouter()
const widthBrowser = useDebounce<number>(
typeof document !== 'undefined' ? document.documentElement.clientWidth : 0,
500,
)
const { tabFontSize, setTabFontSize } = useAppStateContext()

const [chordsDiagrams, setChordsDiagrams] = useState<UGChordCollection[]>(
selectedTabContent?.chordsDiagrams,
)
const [showAutoscroll, setShowAutoscroll] = useState<boolean>(false)

const [showBackingTrack, setShowBackingTrack] = useState<boolean>(false)
const firstUpdate = useRef<boolean>(true)

const flexSongNameDirection = useBreakpointValue({
base:
Expand All @@ -76,29 +71,16 @@ export default function TabPanel({
sm: 'row',
})
const borderLightColor = useColorModeValue('gray.200', 'gray.700')
const paddingThirdRow = useBreakpointValue({ base: 2, sm: 1 })
const widthThirdRow = useBreakpointValue({ base: '100%', sm: 'initial' })
const widthThirdRow = useBreakpointValue({ base: '100%', md: 'initial' })
const marginTopThirdRow = useBreakpointValue({ base: 0, md: 2 })
const paddingTopThirdRow = useBreakpointValue({ base: 1, md: 0 })

const fontSizeValues = [50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150]

useEffect(() => {
setChordsDiagrams(selectedTabContent?.chordsDiagrams)
}, [selectedTabContent])

// Refetch tab when resizing browser or changing orientation to get the updated responsive tab from UG
if (typeof document !== 'undefined') {
// Hook executed only in browser to prevent NextJS SSR to return a warning
// eslint-disable-next-line react-hooks/rules-of-hooks
useLayoutEffect(() => {
if (firstUpdate.current) {
firstUpdate.current = false
return
}
if (!selectedTabContent) return

refetchTab()
// Disabling this effect on the first load of the tab to prevent triggering the toast only because of scrollbar appearing/disappearing
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [widthBrowser, refetchTab])
}
return (
<>
<Box
Expand Down Expand Up @@ -216,22 +198,20 @@ export default function TabPanel({
</Menu>
)}
</Flex>
<Flex
justifyContent={'space-between'}
flexDirection={useBreakpointValue({ base: 'column', sm: 'row' })}
>
<Flex justifyContent={'space-between'} flexDirection={'row'}>
<Flex fontSize={'sm'} py={2}>
<Text color={'gray.500'} as="b" mr={1}>
Difficulty
Key
</Text>{' '}
<Difficulty level={selectedTabContent?.difficulty} />
<Icon boxSize={5} as={GiMusicalScore} mr={1} />
{selectedTabContent?.tonality}
</Flex>{' '}
<Flex fontSize={'sm'} py={2}>
<Text color={'gray.500'} as="b" mr={1}>
Tuning
Capo
</Text>{' '}
<Icon boxSize={5} as={GiGuitarHead} mr={1} />
{selectedTabContent?.tuning.join(' ')}
<Icon boxSize={5} as={GiCrowbar} mr={1} />
{selectedTabContent?.capo}
</Flex>{' '}
</Flex>
<Flex
Expand All @@ -240,29 +220,31 @@ export default function TabPanel({
>
<Flex fontSize={'sm'} py={2}>
<Text color={'gray.500'} as="b" mr={1}>
Key
Difficulty
</Text>{' '}
<Icon boxSize={5} as={GiMusicalScore} mr={1} />
{selectedTabContent?.tonality}
<Difficulty level={selectedTabContent?.difficulty} />
</Flex>{' '}
<Flex fontSize={'sm'} py={2}>
<Text color={'gray.500'} as="b" mr={1}>
Capo
Tuning
</Text>{' '}
<Icon boxSize={5} as={GiCrowbar} mr={1} />
{selectedTabContent?.capo}
<Icon boxSize={5} as={GiGuitarHead} mr={1} />
{selectedTabContent?.tuning.join(' ')}
</Flex>{' '}
</Flex>

<Flex
justifyContent={'space-between'}
flexDirection={useBreakpointValue({ base: 'column', sm: 'row' })}
flexDirection={useBreakpointValue({ base: 'column', md: 'row' })}
alignItems={'center'}
>
{chordsDiagrams && selectedTabContent?.type === 'Chords' && (
<Flex
py={paddingThirdRow}
pb={1}
justifyContent={'start'}
w={widthThirdRow}
mt={marginTopThirdRow}
pt={paddingTopThirdRow}
>
<ChordTransposer
chords={chordsDiagrams}
Expand All @@ -271,7 +253,7 @@ export default function TabPanel({
</Flex>
)}

<Flex py={paddingThirdRow} w={widthThirdRow}>
<Flex pb={1} w={widthThirdRow} pt={0} flexWrap={'wrap'}>
<Button
variant="outline"
_hover={{
Expand All @@ -293,6 +275,7 @@ export default function TabPanel({
px="3"
py="4"
mr={2}
mt={useBreakpointValue({ base: 3, md: 2 })}
leftIcon={<Icon as={FaPlayCircle} />}
>
Backing track
Expand All @@ -317,10 +300,50 @@ export default function TabPanel({
fontWeight={'normal'}
px="3"
py="4"
mr={2}
mt={useBreakpointValue({ base: 3, md: 2 })}
leftIcon={<Icon as={FaCircleArrowDown} />}
>
Autoscroll
</Button>
<Menu>
<MenuButton
as={Button}
variant="outline"
_hover={{
bg: 'twitter.300',
color: 'white',
}}
_active={{
bg: 'twitter.600',
color: 'white',
}}
size={'sm'}
boxShadow="md"
fontWeight={'normal'}
px="3"
py="4"
mt={useBreakpointValue({ base: 3, md: 2 })}
rightIcon={<ChevronDownIcon />}
leftIcon={<Icon fontSize={'sm'} as={MdFontDownload} />}
>
Font size
</MenuButton>
<MenuList>
<MenuOptionGroup
value={tabFontSize.toString()}
onChange={(selectedSize: string) => {
setTabFontSize(parseInt(selectedSize))
}}
>
{fontSizeValues.map((size) => (
<MenuItemOption key={size} value={size.toString()}>
{size}%
</MenuItemOption>
))}
</MenuOptionGroup>
</MenuList>
</Menu>
</Flex>
</Flex>
</Skeleton>
Expand All @@ -336,7 +359,11 @@ export default function TabPanel({
justifyContent="center"
>
<Skeleton display={'flex'} w="100%" isLoaded={!isLoading}>
<Flex h={'100%'} w="100%">
<Flex
h={'100%'}
w="100%"
fontSize={`${tabFontSize / 100}rem !important`}
>
{selectedTabContent && HTMLReactParser(selectedTabContent?.htmlTab)}
</Flex>
</Skeleton>
Expand Down
Loading

0 comments on commit 044829d

Please sign in to comment.