-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
aaf8b4e
commit 01cc6e8
Showing
5 changed files
with
283 additions
and
22 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,51 @@ | ||
import { Cache } from '@/Cache'; | ||
import MessageAdapterFactory from '@/utils/adapters/MessageAdapterFactory'; | ||
import { NextPage } from 'next'; | ||
import { notFound } from 'next/navigation'; | ||
import ProjectDashboard from '@/components/ProjectDashboard'; | ||
import { RepoGit } from '@/RepoGit'; | ||
import { ServerConfig } from '@/utils/serverConfig'; | ||
|
||
const ProjectPage: NextPage<{ | ||
params: { projectName: string }; | ||
}> = async ({ params }) => { | ||
const serverConfig = await ServerConfig.read(); | ||
const project = serverConfig.projects.find( | ||
(project) => project.name === params.projectName, | ||
); | ||
|
||
if (!project) { | ||
return notFound(); | ||
} | ||
|
||
await RepoGit.cloneIfNotExist(project); | ||
const repoGit = await RepoGit.getRepoGit(project); | ||
const lyraConfig = await repoGit.getLyraConfig(); | ||
const projectConfig = lyraConfig.getProjectConfigByPath(project.projectPath); | ||
const msgAdapter = MessageAdapterFactory.createAdapter(projectConfig); | ||
const messages = await msgAdapter.getMessages(); | ||
const store = await Cache.getProjectStore(projectConfig); | ||
const languages = await Promise.all( | ||
projectConfig.languages.map(async (lang) => { | ||
const translations = await store.getTranslations(lang); | ||
return { | ||
href: `/projects/${project.name}/${lang}`, | ||
language: lang, | ||
messagesLeft: messages.length - Object.keys(translations).length, | ||
progress: translations | ||
? (Object.keys(translations).length / messages.length) * 100 | ||
: 0, | ||
}; | ||
}), | ||
); | ||
|
||
return ( | ||
<ProjectDashboard | ||
languages={languages} | ||
messageCount={messages.length} | ||
project={project.name} | ||
/> | ||
); | ||
}; | ||
|
||
export default ProjectPage; |
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,44 @@ | ||
import { Box, List } from '@mui/joy'; | ||
import { FC, ReactNode } from 'react'; | ||
|
||
export type CardGridProps = { | ||
children: ReactNode; | ||
heading?: ReactNode; | ||
}; | ||
|
||
export const CardGrid: FC<CardGridProps> = ({ children, heading }) => { | ||
return ( | ||
<Box | ||
sx={{ | ||
'@media (min-width: 600px)': { | ||
maxWidth: '900px', | ||
}, | ||
display: 'flex', | ||
flexDirection: 'column', | ||
maxWidth: '600px', | ||
rowGap: 2, | ||
width: '100%', | ||
}} | ||
> | ||
{heading && <Box>{heading}</Box>} | ||
<List | ||
sx={{ | ||
'@media (min-width: 650px)': { | ||
columnGap: 2, | ||
display: 'grid', | ||
gridTemplateColumns: 'repeat(2, 300px);', | ||
}, | ||
'@media (min-width: 950px)': { | ||
gridTemplateColumns: 'repeat(3, 300px);', | ||
}, | ||
display: 'flex', | ||
flexDirection: 'column', | ||
rowGap: 2, | ||
width: '100%', | ||
}} | ||
> | ||
{children} | ||
</List> | ||
</Box> | ||
); | ||
}; |
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
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,99 @@ | ||
import { FC } from 'react'; | ||
import { Box, LinearProgress, Link, Typography } from '@mui/joy'; | ||
|
||
export type LanguageCardProps = { | ||
/** | ||
* The URL of the page containing the project's messages in this language. | ||
*/ | ||
|
||
href: string; | ||
|
||
/** | ||
* The name of the language. | ||
*/ | ||
language: string; | ||
|
||
/** | ||
* The number of messages left to translate in this language. | ||
*/ | ||
messagesLeft: number; | ||
|
||
/** | ||
* The percentage of messages translated in this language. 0 means none, 100 | ||
* means all of them. | ||
*/ | ||
progress: number; | ||
}; | ||
|
||
/** | ||
* A language card can be clicked to navigate to the page containing all a | ||
* project's messages in that language. It display's the name of the language | ||
* and some brief statistics about how complete the translation is. | ||
*/ | ||
const LanguageCard: FC<LanguageCardProps> = ({ | ||
href, | ||
language, | ||
messagesLeft, | ||
progress, | ||
}) => { | ||
return ( | ||
<Box component="li" sx={{ listStyleType: 'none' }} width="100%"> | ||
<Box | ||
bgcolor="neutral.50" | ||
border={1} | ||
borderColor="transparent" | ||
borderRadius={8} | ||
display="flex" | ||
flexDirection="column" | ||
position="relative" | ||
px={1} | ||
py={2} | ||
rowGap={1} | ||
sx={{ | ||
':focus-within, :hover': { | ||
outlineColor: 'focusVisible', | ||
outlineStyle: 'solid', | ||
outlineWidth: 1, | ||
}, | ||
}} | ||
> | ||
<Typography component="h2"> | ||
<Link | ||
href={href} | ||
sx={{ | ||
'::after': { | ||
bottom: 0, | ||
content: '""', | ||
left: 0, | ||
position: 'absolute', | ||
right: 0, | ||
top: 0, | ||
width: '100%', | ||
}, | ||
':hover, :focus': { | ||
outline: 'none', | ||
textDecoration: 'none', | ||
}, | ||
color: 'inherit', | ||
position: 'inherit', | ||
}} | ||
> | ||
{language} | ||
</Link> | ||
<LinearProgress | ||
determinate | ||
size="lg" | ||
sx={{ backgroundColor: '#ffffff' }} | ||
thickness={8} | ||
value={Math.min(progress, 100)} | ||
variant="outlined" | ||
/>{' '} | ||
</Typography> | ||
|
||
<Typography>{messagesLeft} messages to translate</Typography> | ||
</Box> | ||
</Box> | ||
); | ||
}; | ||
|
||
export default LanguageCard; |
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,77 @@ | ||
'use client'; | ||
|
||
import { CardGrid } from '@/components/CardGrid'; | ||
import { FC } from 'react'; | ||
import Link from 'next/link'; | ||
import { Box, Typography, useTheme } from '@mui/joy'; | ||
import LanguageCard, { LanguageCardProps } from '@/components/LanguageCard'; | ||
|
||
type ProjectDashboardProps = { | ||
languages: LanguageCardProps[]; | ||
messageCount: number; | ||
project: string; | ||
}; | ||
|
||
const ProjectDashboard: FC<ProjectDashboardProps> = ({ | ||
languages, | ||
messageCount, | ||
project, | ||
}) => { | ||
const theme = useTheme(); | ||
return ( | ||
<Box | ||
alignItems="center" | ||
display="flex" | ||
flexDirection="column" | ||
justifyContent="center" | ||
minHeight="97vh" | ||
rowGap={2} | ||
> | ||
<Box | ||
alignItems="center" | ||
columnGap={1} | ||
display="flex" | ||
flexDirection="row" | ||
width="100%" | ||
> | ||
<Link href="/"> | ||
<svg | ||
aria-labelledby="homeTitle" | ||
fill={theme.palette.primary[500]} | ||
viewBox="0 0 576 512" | ||
width={22} | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<title id="homeTitle">Home</title> | ||
<path d="M575.8 255.5c0 18-15 32.1-32 32.1h-32l.7 160.2c0 2.7-.2 5.4-.5 8.1V472c0 22.1-17.9 40-40 40H456c-1.1 0-2.2 0-3.3-.1c-1.4 .1-2.8 .1-4.2 .1H416 392c-22.1 0-40-17.9-40-40V448 384c0-17.7-14.3-32-32-32H256c-17.7 0-32 14.3-32 32v64 24c0 22.1-17.9 40-40 40H160 128.1c-1.5 0-3-.1-4.5-.2c-1.2 .1-2.4 .2-3.6 .2H104c-22.1 0-40-17.9-40-40V360c0-.9 0-1.9 .1-2.8V287.6H32c-18 0-32-14-32-32.1c0-9 3-17 10-24L266.4 8c7-7 15-8 22-8s15 2 21 7L564.8 231.5c8 7 12 15 11 24z" /> | ||
</svg> | ||
</Link> | ||
</Box> | ||
<Box | ||
sx={{ | ||
alignItems: 'center', | ||
display: 'flex', | ||
flex: 1, | ||
flexDirection: 'column', | ||
justifyContent: 'center', | ||
width: '100%', | ||
}} | ||
> | ||
<CardGrid | ||
heading={ | ||
<> | ||
<Typography component="h1">{project}</Typography> | ||
<Typography>{messageCount} messages</Typography> | ||
</> | ||
} | ||
> | ||
{languages.map((language, i) => ( | ||
<LanguageCard key={i} {...language} /> | ||
))} | ||
</CardGrid> | ||
</Box> | ||
</Box> | ||
); | ||
}; | ||
|
||
export default ProjectDashboard; |