-
Notifications
You must be signed in to change notification settings - Fork 157
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Adds the ability to view the changelog and displays the latest …
…version number. - Adds a new Footer component. - Adds a new Changelog component that displays the changelog.
- Loading branch information
Showing
14 changed files
with
1,337 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { useState } from 'react'; | ||
import { CSSTransition } from 'react-transition-group'; | ||
import { useFetchChangelog } from '../../services/misc'; | ||
import ChangeLog from '../settings/Changelog'; | ||
|
||
interface FooterProps { | ||
currentVersion: string | ||
} | ||
|
||
const Footer = ({ currentVersion = '' }: FooterProps) => { | ||
const [showChangelog, setShowChangelog] = useState(false); | ||
const { data: changeLogs } = useFetchChangelog(); | ||
const latestVersionNum = changeLogs && Array.isArray(changeLogs) && changeLogs[0] ? changeLogs[0].name : ''; | ||
|
||
return ( | ||
<footer className='text-center flex flex-1 justify-center pb-5 items-end'> | ||
<span className='text-gray-500 text-xs'> | ||
<a className='cursor-pointer' onClick={() => setShowChangelog(true)}>SerpBear v{currentVersion || '0.0.0'}</a> | ||
{currentVersion && latestVersionNum && `v${currentVersion}` !== latestVersionNum && ( | ||
<a className='cursor-pointer text-indigo-700 font-semibold' onClick={() => setShowChangelog(true)}> | ||
{' '}| Update to Version {latestVersionNum} (latest) | ||
</a> | ||
)} | ||
</span> | ||
<CSSTransition in={showChangelog} timeout={300} classNames="settings_anim" unmountOnExit mountOnEnter> | ||
<ChangeLog closeChangeLog={() => setShowChangelog(false)} /> | ||
</CSSTransition> | ||
</footer> | ||
); | ||
}; | ||
|
||
export default Footer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import Icon from './Icon'; | ||
import useOnKey from '../../hooks/useOnKey'; | ||
|
||
type SidePanelProps = { | ||
children: React.ReactNode, | ||
closePanel: Function, | ||
title?: string, | ||
width?: 'large' | 'medium' | 'small', | ||
position?: 'left' | 'right' | ||
} | ||
const SidePanel = ({ children, closePanel, width, position = 'right', title = '' }:SidePanelProps) => { | ||
useOnKey('Escape', closePanel); | ||
const closeOnBGClick = (e:React.SyntheticEvent) => { | ||
e.stopPropagation(); | ||
e.nativeEvent.stopImmediatePropagation(); | ||
if (e.target === e.currentTarget) { closePanel(); } | ||
}; | ||
return ( | ||
<div className="SidePanel fixed w-full h-screen top-0 left-0 z-50" onClick={closeOnBGClick}> | ||
<div className={`absolute w-full max-w-md border-l border-l-gray-400 bg-white customShadow top-0 | ||
${position === 'left' ? 'left-0' : 'right-0'} h-screen`}> | ||
<div className='SidePanel__header px-5 py-4 text-slate-500 border-b border-b-gray-100'> | ||
<h3 className=' text-black text-lg font-bold'>{title}</h3> | ||
<button | ||
className=' absolute top-2 right-2 p-2 px- text-gray-400 hover:text-gray-700 transition-all hover:rotate-90' | ||
onClick={() => closePanel()}> | ||
<Icon type='close' size={24} /> | ||
</button> | ||
</div> | ||
<div>{children}</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default SidePanel; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import React, { useLayoutEffect, useMemo } from 'react'; | ||
import TimeAgo from 'react-timeago'; | ||
import dayjs from 'dayjs'; | ||
import SidePanel from '../common/SidePanel'; | ||
import { useFetchChangelog } from '../../services/misc'; | ||
import Icon from '../common/Icon'; | ||
|
||
const Markdown = React.lazy(() => import('react-markdown')); | ||
|
||
type ChangeLogProps = { | ||
closeChangeLog: Function, | ||
} | ||
|
||
const ChangeLogloader = () => { | ||
return ( | ||
<div className='w-full h-full absolute flex justify-center items-center'> | ||
<Icon type="loading" size={36} color='#999' /> | ||
</div> | ||
); | ||
}; | ||
|
||
const ChangeLog = ({ closeChangeLog }: ChangeLogProps) => { | ||
const { data: changeLogData, isLoading } = useFetchChangelog(); | ||
|
||
useLayoutEffect(() => { | ||
document.body.style.overflow = 'hidden'; | ||
// eslint-disable-next-line no-unused-expressions | ||
() => { | ||
console.log('run CleanUp !'); | ||
document.body.style.overflow = 'auto'; | ||
}; | ||
}, []); | ||
|
||
const onClose = () => { | ||
document.body.style.overflow = 'auto'; | ||
closeChangeLog(); | ||
}; | ||
|
||
const changeLogs = useMemo(() => { | ||
if (changeLogData && Array.isArray(changeLogData)) { | ||
return changeLogData.map(({ name = '', body, published_at }:{name: string, body: string, published_at: string}) => ({ | ||
version: name, | ||
major: !!(name.match(/v\d+\.0+\.0/)), | ||
date: published_at, | ||
content: body.replaceAll(/^(##|###) \[([^\]]+)\]\(([^)]+)\) \(([^)]+)\)/g, '') | ||
.replaceAll(/\(\[(.*?)\]\((https:\/\/github\.com\/towfiqi\/serpbear\/commit\/([a-f0-9]{40}))\)\)/g, ''), | ||
})); | ||
} | ||
return []; | ||
}, [changeLogData]); | ||
|
||
return <SidePanel title='SerpBear Changelog' closePanel={onClose}> | ||
<React.Suspense fallback={<ChangeLogloader />}> | ||
{!isLoading && changeLogs.length > 0 && ( | ||
<div className='changelog-body bg-[#f8f9ff] px-6 pt-4 pb-10 overflow-y-auto styled-scrollbar'> | ||
{changeLogs.map(({ version, content, date, major }) => { | ||
return ( | ||
<div | ||
key={version} | ||
className={`domKeywords bg-white rounded mb-6 border ${major ? ' border-indigo-400' : 'border-transparent'}`}> | ||
<h4 className=' px-5 py-3 border-b border-b-gray-100 flex justify-between text-indigo-700 font-semibold'> | ||
<a href={`https://github.com/towfiqi/serpbear/releases/tag/${version}`}> | ||
{version} {major && <span className=' text-xs bg-amber-100 text-amber-700 px-2 py-1 rounded ml-2'>Major</span>} | ||
</a> | ||
<span className=' text-sm text-gray-500'> | ||
<TimeAgo title={dayjs(date).format('DD-MMM-YYYY, hh:mm:ss A')} date={date} /> | ||
</span> | ||
</h4> | ||
<div className='changelog-content px-5 py-3 text-sm text-left'><Markdown>{content}</Markdown></div> | ||
</div> | ||
); | ||
})} | ||
</div> | ||
)} | ||
{isLoading && <ChangeLogloader />} | ||
</React.Suspense> | ||
</SidePanel>; | ||
}; | ||
|
||
export default ChangeLog; |
Oops, something went wrong.