build ok,

This commit is contained in:
louiscklaw
2025-04-14 09:26:24 +08:00
commit 6c931c1fe8
770 changed files with 63959 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
import * as React from 'react';
import Timeline from '@mui/lab/Timeline';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { dayjs } from '@/lib/dayjs';
import { ActivityItem } from '@/components/dashboard/jobs/activity-item';
import type { Event } from '@/components/dashboard/jobs/activity-item';
const events = [
{
id: 'EV-004',
createdAt: dayjs().subtract(7, 'minute').subtract(5, 'hour').subtract(1, 'day').toDate(),
type: 'new_job',
author: { name: 'Jie Yan', avatar: '/assets/avatar-8.png' },
job: { title: 'Remote React / React Native Developer' },
},
{
id: 'EV-003',
createdAt: dayjs().subtract(18, 'minute').subtract(3, 'hour').subtract(5, 'day').toDate(),
type: 'new_job',
author: { name: 'Fran Perez', avatar: '/assets/avatar-5.png' },
job: { title: 'Senior Golang Backend Engineer' },
},
{
id: 'EV-002',
createdAt: dayjs().subtract(41, 'minute').subtract(5, 'hour').subtract(7, 'day').toDate(),
type: 'new_member',
author: { name: 'Jie Yan', avatar: '/assets/avatar-8.png' },
member: { name: 'Omar Darboe' },
},
{
id: 'EV-001',
createdAt: dayjs().subtract(7, 'minute').subtract(8, 'hour').subtract(7, 'day').toDate(),
type: 'new_company',
author: { name: 'Jie Yan', avatar: '/assets/avatar-8.png' },
company: { name: 'Stripe' },
},
] satisfies Event[];
export default function Page(): React.JSX.Element {
return (
<Stack spacing={3}>
<div>
<Typography variant="h6">Activity</Typography>
</div>
<Stack spacing={3}>
<Timeline
sx={{
m: 0,
p: 0,
'& .MuiTimelineItem-root': { '&::before': { display: 'none' } },
'& .MuiTimelineDot-root': { background: 'transparent', border: 0, p: 0 },
'& .MuiTimelineConnector-root': { minHeight: '30px' },
}}
>
{events.map((event, index) => (
<ActivityItem connector={index < events.length - 1} event={event} key={event.id} />
))}
</Timeline>
<Box sx={{ display: 'flex', justifyContent: 'center' }}>
<Button color="secondary">Load more</Button>
</Box>
</Stack>
</Stack>
);
}

View File

@@ -0,0 +1,35 @@
import * as React from 'react';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Unstable_Grid2';
import { AssetCard } from '@/components/dashboard/jobs/asset-card';
import type { Asset } from '@/components/dashboard/jobs/types';
const assets = [
{
id: 'ASSET-002',
mimeType: 'image/png',
name: 'company-cover.png',
size: '23 KB',
url: '/assets/image-business-2.png',
},
{ id: 'ASSET-001', mimeType: 'application/pdf', name: 'Presentation.pdf', size: '3 MB', url: '' },
] satisfies Asset[];
export default function Page(): React.JSX.Element {
return (
<Stack spacing={3}>
<div>
<Typography variant="h6">Assets ({assets.length})</Typography>
</div>
<Grid container spacing={3}>
{assets.map((asset) => (
<Grid key={asset.id} md={4} sm={6} xs={12}>
<AssetCard asset={asset} />
</Grid>
))}
</Grid>
</Stack>
);
}

View File

@@ -0,0 +1,126 @@
import * as React from 'react';
import type { Metadata } from 'next';
import RouterLink from 'next/link';
import Avatar from '@mui/material/Avatar';
import Box from '@mui/material/Box';
import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import Divider from '@mui/material/Divider';
import Link from '@mui/material/Link';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Unstable_Grid2';
import { ArrowLeft as ArrowLeftIcon } from '@phosphor-icons/react/dist/ssr/ArrowLeft';
import { config } from '@/config';
import { paths } from '@/paths';
import { PropertyItem } from '@/components/core/property-item';
import { PropertyList } from '@/components/core/property-list';
import { CompanyTabs } from '@/components/dashboard/jobs/company-tabs';
export const metadata = { title: `Company | Jobs | Dashboard | ${config.site.name}` } satisfies Metadata;
interface Founder {
id: string;
name: string;
avatar?: string;
role: string;
}
const founders = [
{ id: 'USR-008', name: 'Jie Yan', avatar: '/assets/avatar-8.png', role: 'CEO & Co-founder' },
{ id: 'USR-005', name: 'Fran Perez', avatar: '/assets/avatar-5.png', role: 'CTO & Co-founder' },
{ id: 'USR-011', name: 'Omar Darboe', avatar: '/assets/avatar-11.png', role: 'CFO' },
] satisfies Founder[];
interface LayoutProps {
children: React.ReactNode;
}
export default function Layout({ children }: LayoutProps): React.JSX.Element {
return (
<Box
sx={{
maxWidth: 'var(--Content-maxWidth)',
m: 'var(--Content-margin)',
p: 'var(--Content-padding)',
width: 'var(--Content-width)',
}}
>
<Stack spacing={4}>
<div>
<Link
color="text.primary"
component={RouterLink}
href={paths.dashboard.jobs.browse}
sx={{ alignItems: 'center', display: 'inline-flex', gap: 1 }}
variant="subtitle2"
>
<ArrowLeftIcon fontSize="var(--icon-fontSize-md)" />
Jobs
</Link>
</div>
<Grid container spacing={4}>
<Grid lg={8} xs={12}>
<Card>
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', p: 3 }}>
<Avatar src="/assets/company-avatar-1.png" variant="rounded" />
<div>
<Typography variant="h6">Stripe</Typography>
<Typography variant="body2">
The new standard in online payments. Stripe is the best software platform for running an internet
</Typography>
</div>
</Stack>
<Divider />
<CompanyTabs />
<Divider />
<CardContent>{children}</CardContent>
</Card>
</Grid>
<Grid lg={4} xs={12}>
<Card>
<CardContent>
<Stack divider={<Divider />} spacing={2}>
<Stack spacing={2}>
<Typography variant="overline">About</Typography>
<PropertyList orientation="vertical">
{(
[
{ key: 'Website', value: <Link variant="body2">https://stripe.com</Link> },
{ key: 'Industry', value: 'Financial Services' },
{ key: 'Locations', value: 'New York City, Milano, Moscow' },
{ key: 'Company size', value: '50-100' },
] satisfies { key: string; value: React.ReactNode }[]
).map(
(item): React.JSX.Element => (
<PropertyItem key={item.key} name={item.key} value={item.value} />
)
)}
</PropertyList>
</Stack>
<Stack spacing={2}>
<Typography variant="overline">Founders</Typography>
<Stack spacing={2}>
{founders.map((founder) => (
<Stack direction="row" key={founder.id} spacing={2} sx={{ alignItems: 'center' }}>
<Avatar src={founder.avatar} />
<div>
<Typography variant="subtitle2">{founder.name}</Typography>
<Typography color="text.secondary" variant="body2">
{founder.role}
</Typography>
</div>
</Stack>
))}
</Stack>
</Stack>
</Stack>
</CardContent>
</Card>
</Grid>
</Grid>
</Stack>
</Box>
);
}

View File

@@ -0,0 +1,140 @@
import * as React from 'react';
import RouterLink from 'next/link';
import Box from '@mui/material/Box';
import Divider from '@mui/material/Divider';
import ImageList from '@mui/material/ImageList';
import ImageListItem from '@mui/material/ImageListItem';
import Link from '@mui/material/Link';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Unstable_Grid2';
import { ArrowRight as ArrowRightIcon } from '@phosphor-icons/react/dist/ssr/ArrowRight';
import { paths } from '@/paths';
import { dayjs } from '@/lib/dayjs';
import { Description } from '@/components/dashboard/jobs/description';
import { JobsCard } from '@/components/dashboard/jobs/jobs-card';
import { MemberCard } from '@/components/dashboard/jobs/member-card';
import type { Job, Member } from '@/components/dashboard/jobs/types';
const description = `## Stripe is a technology company that builds economic infrastructure for the internet.
Businesses of every size—from new startups to public companies—use our software to accept payments and manage their businesses online.
Stripe's software is used by millions of businesses in over 120 countries and across nearly every industry. We are a global company with a global team that is committed to building a more fair, more inclusive world.
Our mission emphasizes seeking and hiring diverse voices, including those who are traditionally underrepresented in the technology industry, and we consider this to be one of the most important values we hold close. We're a hard-working, fun, and exciting group who value intellectual curiosity and a passion for problem-solving! We have growing offices located in San Francisco, Sunnyvale, Bellevue, Los Angeles, Tokyo, Hamburg, London, and Zurich.`;
const images = [
'/assets/company-image-1.jpg',
'/assets/company-image-2.jpg',
'/assets/company-image-3.jpg',
'/assets/company-image-4.jpg',
'/assets/company-image-5.jpg',
'/assets/company-image-6.jpg',
] satisfies string[];
const jobs = [
{
id: 'JOB-001',
title: 'Senior React Developer',
currency: 'USD',
budgetMin: 94000,
budgetMax: 140000,
isRemote: true,
publishedAt: dayjs().subtract(49, 'minute').subtract(2, 'hour').subtract(7, 'day').toDate(),
},
{
id: 'JOB-002',
title: 'Senior Ruby Engineer',
currency: 'USD',
budgetMin: 120000,
budgetMax: 145000,
isRemote: true,
publishedAt: dayjs().subtract(10, 'minute').subtract(7, 'hour').subtract(8, 'day').toDate(),
},
] satisfies Job[];
const members = [
{
id: 'USR-008',
name: 'Jie Yan',
avatar: '/assets/avatar-8.png',
role: 'CEO & Co-founder',
skills: ['JavaScript', 'React', 'Go'],
},
{
id: 'USR-005',
name: 'Fran Perez',
avatar: '/assets/avatar-5.png',
role: 'CTO & Co-founder',
skills: ['C', 'C++', 'Java'],
},
] satisfies Member[];
export default function Page(): React.JSX.Element {
return (
<Stack spacing={3}>
<Description content={description} />
<ImageList cols={3} gap={24} variant="masonry">
{images.map((image) => (
<ImageListItem key={image}>
<Box alt="Gallery" component="img" src={image} sx={{ height: '100%', width: '100%' }} />
</ImageListItem>
))}
</ImageList>
<Divider />
<Stack spacing={3}>
<Stack
direction="row"
spacing={3}
sx={{ alignItems: 'center', flexWrap: 'wrap', justifyContent: 'space-between' }}
>
<Typography variant="h6">Jobs</Typography>
<Link
color="text.primary"
component={RouterLink}
href={paths.dashboard.jobs.companies.overview('1')}
sx={{ alignItems: 'center', display: 'flex', gap: 1 }}
variant="subtitle2"
>
<Typography variant="subtitle2">Jobs</Typography>
<Box sx={{ display: 'flex', flex: '0 0 auto' }}>
<ArrowRightIcon fontSize="var(--icon-fontSize-md)" />
</Box>
</Link>
</Stack>
<JobsCard jobs={jobs} />
</Stack>
<Divider />
<Stack spacing={3}>
<Stack
direction="row"
spacing={3}
sx={{ alignItems: 'center', flexWrap: 'wrap', justifyContent: 'space-between' }}
>
<Typography variant="h6">Members</Typography>
<Link
color="text.primary"
component={RouterLink}
href={paths.dashboard.jobs.companies.overview('1')}
sx={{ alignItems: 'center', display: 'flex', gap: 1 }}
variant="subtitle2"
>
<Typography variant="subtitle2">Members</Typography>
<Box sx={{ display: 'flex', flex: '0 0 auto' }}>
<ArrowRightIcon fontSize="var(--icon-fontSize-md)" />
</Box>
</Link>
</Stack>
<Grid container spacing={3}>
{members.map((member) => (
<Grid key={member.id} sm={6} xs={12}>
<MemberCard member={member} />
</Grid>
))}
</Grid>
</Stack>
</Stack>
);
}

View File

@@ -0,0 +1,63 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { dayjs } from '@/lib/dayjs';
import { CompanyReviewAdd } from '@/components/dashboard/jobs/review-add';
import { ReviewCard } from '@/components/dashboard/jobs/review-card';
import { ReviewsSummary } from '@/components/dashboard/jobs/reviews-summary';
import type { Review } from '@/components/dashboard/jobs/types';
const reviews = [
{
id: 'REV-003',
title: 'Great company, providing an awesome & easy to use product',
comment:
'I have been working with this company full-time. Great for the work life balance. Cons, decentralized decision making process across the organization.',
rating: 3.8,
author: { name: 'Sofia Rivers', avatar: '/assets/avatar.png' },
createdAt: dayjs().subtract(4, 'minute').subtract(4, 'hour').subtract(2, 'day').toDate(),
},
{
id: 'REV-002',
title: 'Friendly environment',
comment:
'Every day you learn something new - that is a typical day at work in Stripe. I am surrounded by supportive people, from different cultures, we have a strong and unified team and help each other whenever is needed. The most enjoyable part of the job is that you meet new people, experts on different disciplines that might help you in your work, but the hardest part of the job is that there are too many tools and systems to use.',
rating: 3.4,
author: { name: 'Carson Darrin', avatar: '/assets/avatar-3.png' },
createdAt: dayjs().subtract(17, 'minute').subtract(4, 'hour').subtract(5, 'day').toDate(),
},
{
id: 'REV-001',
title: 'Great company, providing an awesome & easy to use product',
comment:
'I have been working with this company full-time. Great for the work life balance. Cons, decentralized decision making process across the organization.',
rating: 3.8,
author: { name: 'Fran Perez', avatar: '/assets/avatar-5.png' },
createdAt: dayjs().subtract(34, 'minute').subtract(5, 'hour').subtract(7, 'day').toDate(),
},
] satisfies Review[];
export default function Page(): React.JSX.Element {
const averageRating = 3.66;
return (
<Stack spacing={3}>
<div>
<Typography variant="h6">Reviews</Typography>
</div>
<Stack spacing={3}>
<ReviewsSummary averageRating={averageRating} totalReviews={reviews.length} />
{reviews.map((review) => (
<ReviewCard key={review.id} review={review} />
))}
<Box sx={{ display: 'flex', justifyContent: 'center' }}>
<Button color="secondary">Load more</Button>
</Box>
<CompanyReviewAdd />
</Stack>
</Stack>
);
}

View File

@@ -0,0 +1,42 @@
import * as React from 'react';
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { MemberCard } from '@/components/dashboard/jobs/member-card';
import type { Member } from '@/components/dashboard/jobs/types';
const members = [
{
id: 'USR-008',
name: 'Jie Yan',
avatar: '/assets/avatar-8.png',
role: 'CEO & Co-founder',
skills: ['JavaScript', 'React', 'Go'],
},
{
id: 'USR-005',
name: 'Fran Perez',
avatar: '/assets/avatar-5.png',
role: 'CTO & Co-founder',
skills: ['C', 'C++', 'Java'],
},
{ id: 'USR-011', name: 'Omar Darboe', avatar: '/assets/avatar-11.png', role: 'CFO', skills: ['Go', 'Python'] },
] satisfies Member[];
export default function Page(): React.JSX.Element {
return (
<Stack spacing={3}>
<div>
<Typography variant="h6">Team ({members.length})</Typography>
</div>
<Grid container spacing={3}>
{members.map((member) => (
<Grid item key={member.id} sm={6} xs={12}>
<MemberCard member={member} />
</Grid>
))}
</Grid>
</Stack>
);
}

View File

@@ -0,0 +1,35 @@
import * as React from 'react';
import type { Metadata } from 'next';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import { config } from '@/config';
import { JobCreateForm } from '@/components/dashboard/jobs/job-create-form';
export const metadata = { title: `Create | Jobs | Dashboard | ${config.site.name}` } satisfies Metadata;
export default function Page(): React.JSX.Element {
return (
<Box sx={{ display: 'flex', flex: '1 1 0', minHeight: 0 }}>
<Box
sx={{
position: 'relative',
overflow: 'hidden',
backgroundImage: 'url(/assets/people-talking.png)',
backgroundPosition: 'center',
backgroundSize: 'cover',
flex: '0 0 auto',
display: { xs: 'none', md: 'block' },
width: { md: '400px', xl: '500px' },
}}
/>
<Box sx={{ flex: '1 1 auto', overflowY: 'auto', p: { xs: 4, sm: 6, md: 8 } }}>
<Stack maxWidth="md" spacing={4}>
<Typography variant="h4">Create job ad</Typography>
<JobCreateForm />
</Stack>
</Box>
</Box>
);
}

View File

@@ -0,0 +1,188 @@
import * as React from 'react';
import type { Metadata } from 'next';
import RouterLink from 'next/link';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import IconButton from '@mui/material/IconButton';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Grid from '@mui/material/Unstable_Grid2';
import { CaretLeft as CaretLeftIcon } from '@phosphor-icons/react/dist/ssr/CaretLeft';
import { CaretRight as CaretRightIcon } from '@phosphor-icons/react/dist/ssr/CaretRight';
import { config } from '@/config';
import { paths } from '@/paths';
import { dayjs } from '@/lib/dayjs';
import { CompanyCard } from '@/components/dashboard/jobs/company-card';
import type { Company } from '@/components/dashboard/jobs/company-card';
import { JobsFilters } from '@/components/dashboard/jobs/jobs-filters';
export const metadata = { title: `Browse | Jobs | Dashboard | ${config.site.name}` } satisfies Metadata;
const companies = [
{
id: 'COM-004',
name: 'Vercel',
logo: '/assets/company-avatar-4.png',
description: 'Develop. Preview. Ship. For the best frontend teams.',
rating: 4.5,
employees: '10-20',
isVerified: true,
jobs: [
{
id: 'JOB-005',
title: 'Remote React / React Native Developer',
currency: 'USD',
budgetMin: 55000,
budgetMax: 75000,
isRemote: true,
publishedAt: dayjs().subtract(24, 'minute').toDate(),
},
{
id: 'JOB-006',
title: 'Senior Golang Backend Engineer',
currency: 'USD',
budgetMin: 80000,
budgetMax: 160000,
country: 'Germany',
state: 'Bavaria',
city: 'Munich',
publishedAt: dayjs().subtract(45, 'minute').subtract(2, 'hour').toDate(),
},
],
},
{
id: 'COM-003',
name: 'Auth0',
logo: '/assets/company-avatar-3.png',
description: 'Secure access for everyone. But not just anyone.',
rating: 4.3,
employees: '50-100',
isVerified: false,
jobs: [
{
id: 'JOB-004',
title: 'Remote React / React Native Developer',
currency: 'USD',
budgetMin: 87000,
budgetMax: 135000,
isRemote: true,
publishedAt: dayjs().subtract(1, 'hour').toDate(),
},
],
},
{
id: 'COM-002',
name: 'Google Cloud',
logo: '/assets/company-avatar-2.png',
description: 'Build, modernize, and scale your applications with Google Cloud.',
rating: 4.5,
employees: '1-10',
isVerified: false,
jobs: [
{
id: 'JOB-003',
title: 'Senior Backend Engineer',
currency: 'USD',
budgetMin: 150000,
budgetMax: 210000,
isRemote: true,
publishedAt: dayjs().subtract(39, 'minute').subtract(7, 'hour').subtract(5, 'day').toDate(),
},
],
},
{
id: 'COM-001',
name: 'Stripe',
logo: '/assets/company-avatar-1.png',
description: 'The new standard in online payments',
rating: 4.9,
employees: '50-100',
isVerified: true,
jobs: [
{
id: 'JOB-001',
title: 'Senior React Developer',
currency: 'USD',
budgetMin: 94000,
budgetMax: 140000,
isRemote: true,
publishedAt: dayjs().subtract(49, 'minute').subtract(2, 'hour').subtract(7, 'day').toDate(),
},
{
id: 'JOB-002',
title: 'Senior Ruby Engineer',
currency: 'USD',
budgetMin: 120000,
budgetMax: 145000,
isRemote: true,
publishedAt: dayjs().subtract(10, 'minute').subtract(7, 'hour').subtract(8, 'day').toDate(),
},
],
},
] satisfies Company[];
export default function Page(): React.JSX.Element {
return (
<Box
sx={{
maxWidth: 'var(--Content-maxWidth)',
m: 'var(--Content-margin)',
p: 'var(--Content-padding)',
width: 'var(--Content-width)',
}}
>
<Stack spacing={4}>
<Box
sx={{
bgcolor: 'var(--mui-palette-neutral-900)',
borderRadius: 1,
color: 'var(--mui-palette-common-white)',
px: 4,
py: 8,
}}
>
<Grid container sx={{ alignItems: 'center' }}>
<Grid sm={7} xs={12}>
<Stack spacing={3}>
<Stack spacing={2}>
<Typography color="inherit" variant="h3">
Reach 50K+ potential candidates.
</Typography>
<Typography color="neutral.400" variant="body1">
Post your job today for free. Promotions start at $99.
</Typography>
</Stack>
<div>
<Button color="primary" component={RouterLink} href={paths.dashboard.jobs.create} variant="contained">
Post a job
</Button>
</div>
</Stack>
</Grid>
<Grid sm={5} sx={{ display: { xs: 'none', sm: 'flex' }, justifyContent: 'center' }}>
<Box
alt="Shield"
component="img"
src="/assets/iconly-glass-shield.svg"
sx={{ height: 'auto', width: '200px' }}
/>
</Grid>
</Grid>
</Box>
<JobsFilters />
{companies.map((company) => (
<CompanyCard company={company} key={company.id} />
))}
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', justifyContent: 'center', px: 3 }}>
<IconButton disabled>
<CaretLeftIcon />
</IconButton>
<IconButton>
<CaretRightIcon />
</IconButton>
</Stack>
</Stack>
</Box>
);
}