Skip to content

Commit 8cab31a

Browse files
committed
style: update whole website to more modern style/scheme
1 parent 0ed9dd2 commit 8cab31a

47 files changed

Lines changed: 4317 additions & 3441 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

components/Features.tsx

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import {
2+
CodeBracketIcon,
3+
CommandLineIcon,
4+
BookOpenIcon,
5+
UserGroupIcon,
6+
AcademicCapIcon,
7+
BeakerIcon,
8+
RocketLaunchIcon,
9+
CubeTransparentIcon
10+
} from '@heroicons/react/24/outline'
11+
12+
const features = [
13+
{
14+
name: 'Open Source Learning',
15+
description:
16+
'Practice real-world open source contribution with 134+ beginner-friendly issues across various programming languages and frameworks.',
17+
icon: CodeBracketIcon
18+
},
19+
{
20+
name: 'Structured Progression',
21+
description:
22+
'Issues are categorized into Easy, Medium, and Hard difficulties, allowing you to gradually build your skills and confidence.',
23+
icon: AcademicCapIcon
24+
},
25+
{
26+
name: 'Hands-on Testing',
27+
description:
28+
'Learn and practice testing with Jest, Jasmine, and Vitest through practical exercises and real test implementations.',
29+
icon: BeakerIcon
30+
},
31+
{
32+
name: 'Multi-Language Experience',
33+
description:
34+
'Explore a wide range of programming languages from modern (TypeScript, Rust, Go) to legacy (Fortran, Erlang) systems.',
35+
icon: CubeTransparentIcon
36+
},
37+
{
38+
name: 'Automated Learning',
39+
description:
40+
'Our bot automatically reverts changes after merging, keeping issues fresh for the next contributor while tracking your progress.',
41+
icon: RocketLaunchIcon
42+
},
43+
{
44+
name: 'Git Mastery',
45+
description:
46+
'Perfect your Git workflow through hands-on experience with forking, committing, and merging pull requests.',
47+
icon: CommandLineIcon
48+
},
49+
{
50+
name: 'Comprehensive Resources',
51+
description:
52+
'Access detailed guides, documentation, and learning materials to help you succeed in your contributions.',
53+
icon: BookOpenIcon
54+
},
55+
{
56+
name: 'Community Recognition',
57+
description:
58+
'Get added to our contributors list and join a growing community of developers helping each other learn and grow.',
59+
icon: UserGroupIcon
60+
}
61+
]
62+
63+
const Features = () => {
64+
return (
65+
<div className='bg-gray-50 py-24 sm:py-32'>
66+
<div className='modern-container'>
67+
<div className='mx-auto max-w-2xl lg:text-center'>
68+
<h2 className='text-modern-purple text-2xl font-semibold leading-7'>
69+
Learn By Contributing
70+
</h2>
71+
<p className='mt-4 text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl'>
72+
Master Open Source Development
73+
</p>
74+
<p className='mt-6 text-lg leading-8 text-gray-600'>
75+
An educational platform designed to help both newcomers and seasoned developers
76+
improve their skills through practical open-source contribution, problem-solving,
77+
and hands-on learning.
78+
</p>
79+
</div>
80+
<div className='mx-auto mt-16 max-w-2xl sm:mt-20 lg:mt-24 lg:max-w-none'>
81+
<dl className='grid max-w-xl grid-cols-1 gap-x-8 gap-y-16 lg:max-w-none lg:grid-cols-4'>
82+
{features.map(feature => (
83+
<div key={feature.name} className='flex flex-col'>
84+
<dt className='flex items-center gap-x-3 text-base font-semibold leading-7 text-gray-900'>
85+
<feature.icon
86+
className='text-modern-purple h-5 w-5 flex-none'
87+
aria-hidden='true'
88+
/>
89+
{feature.name}
90+
</dt>
91+
<dd className='mt-4 flex flex-auto flex-col text-base leading-7 text-gray-600'>
92+
<p className='flex-auto'>{feature.description}</p>
93+
</dd>
94+
</div>
95+
))}
96+
</dl>
97+
</div>
98+
</div>
99+
</div>
100+
)
101+
}
102+
103+
export default Features

components/Hero.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import Link from 'next/link'
2+
import Image from 'next/image'
3+
4+
const Hero = () => {
5+
return (
6+
<div className='bg-white'>
7+
<div className='modern-container'>
8+
<div className='py-16 sm:py-24 lg:py-32'>
9+
<div className='text-center'>
10+
<h1 className='text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl lg:text-6xl'>
11+
Welcome to
12+
<span className='text-modern-purple'> Fork Commit Merge</span>
13+
</h1>
14+
<p className='mx-auto mt-6 max-w-3xl text-lg leading-8 text-gray-600'>
15+
A project to help developers learn and practice Git and contribute
16+
to open source.
17+
</p>
18+
<div className='mt-10 flex items-center justify-center gap-x-6'>
19+
<Link
20+
href='https://github.com/fork-commit-merge/fork-commit-merge'
21+
className='hero-button'
22+
target='_blank'
23+
rel='noopener noreferrer'
24+
>
25+
Get Started
26+
</Link>
27+
<Link href='/faq' className='hero-button-outline'>
28+
FAQ
29+
</Link>
30+
</div>
31+
</div>
32+
</div>
33+
</div>
34+
</div>
35+
)
36+
}
37+
38+
export default Hero

components/Spinner.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { RefreshIcon } from "@heroicons/react/outline";
1+
import { ArrowPathIcon } from '@heroicons/react/24/outline'
22
import React from "react";
33

44
const Spinner = () => (
55
<div className="flex items-center justify-center h-full">
6-
<RefreshIcon className="animate-spin h-16 w-16 text-gray-500" />
6+
<ArrowPathIcon className="animate-spin h-16 w-16 text-gray-500" />
77
</div>
88
);
99

components/Testimonials.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { testimonials } from './data/testimonials'
2+
3+
const Testimonials = () => {
4+
return (
5+
<section className='bg-white py-16'>
6+
<div className='mx-auto max-w-7xl px-4 sm:px-6 lg:px-8'>
7+
<div className='text-center'>
8+
<h2 className='text-3xl font-bold text-gray-900 sm:text-4xl'>
9+
What Our Contributors Say
10+
</h2>
11+
<p className='mt-4 text-lg text-gray-600'>
12+
Join our community of developers who are learning and growing
13+
together
14+
</p>
15+
</div>
16+
17+
<div className='mt-12 flex flex-wrap justify-center gap-6'>
18+
{testimonials.map((testimonial, index) => (
19+
<div
20+
key={index}
21+
className='w-full rounded-lg bg-gray-50 p-6 shadow-sm md:w-[calc(50%-12px)] lg:w-[30%]'
22+
>
23+
<div className='mb-4 flex items-center'>
24+
<img
25+
src={testimonial.imageUrl}
26+
alt={testimonial.name}
27+
className='mr-3 h-10 w-10 rounded-full'
28+
/>
29+
<a
30+
href={testimonial.url}
31+
target='_blank'
32+
rel='noopener noreferrer'
33+
className='hover:text-modern-purple font-semibold text-gray-900'
34+
>
35+
{testimonial.name}
36+
</a>
37+
</div>
38+
<p className='text-gray-600'>"{testimonial.text}"</p>
39+
</div>
40+
))}
41+
</div>
42+
</div>
43+
</section>
44+
)
45+
}
46+
47+
export default Testimonials

components/ThemeSelector.tsx

Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,70 @@
1-
import { useState, useEffect } from 'react';
2-
import { ColorSwatchIcon } from '@heroicons/react/outline';
1+
import { SunIcon, MoonIcon } from '@heroicons/react/24/outline'
2+
import { useState, useEffect } from 'react'
3+
import { ForwardRefExoticComponent, RefAttributes, SVGProps } from 'react'
34

4-
const themes = [
5-
{ name: 'Blue', value: 'blue' },
6-
{ name: 'Green', value: 'green' },
7-
{ name: 'Red', value: 'red' },
8-
{ name: 'Yellow', value: 'yellow' },
9-
{ name: 'Purple', value: 'purple' },
10-
{ name: 'Black', value: 'black' },
11-
];
5+
type Theme = {
6+
name: string
7+
icon: ForwardRefExoticComponent<
8+
Omit<SVGProps<SVGSVGElement>, 'ref'> & RefAttributes<SVGSVGElement>
9+
>
10+
}
11+
12+
const themes: Theme[] = [
13+
{ name: 'light', icon: SunIcon },
14+
{ name: 'dark', icon: MoonIcon }
15+
]
1216

1317
const ThemeSelector = () => {
14-
const [isOpen, setIsOpen] = useState(false);
15-
const [currentTheme, setCurrentTheme] = useState('blue');
18+
const [isOpen, setIsOpen] = useState(false)
19+
const [theme, setTheme] = useState('dark')
1620

1721
useEffect(() => {
18-
const savedTheme = localStorage.getItem('theme') ?? 'blue';
19-
setCurrentTheme(savedTheme);
20-
document.documentElement.className = `theme-${savedTheme}`;
21-
}, []);
22-
23-
const handleThemeChange = (theme: string) => {
24-
setCurrentTheme(theme);
25-
localStorage.setItem('theme', theme);
26-
document.documentElement.className = `theme-${theme}`;
27-
setIsOpen(false);
28-
};
22+
const savedTheme = localStorage.getItem('theme') || 'dark'
23+
setTheme(savedTheme)
24+
document.documentElement.classList.add(`theme-${savedTheme}`)
25+
}, [])
2926

30-
useEffect(() => {
31-
const handleDropdownChange = () => {
32-
setIsOpen(false);
33-
};
27+
const handleThemeChange = (newTheme: string) => {
28+
setTheme(newTheme)
29+
localStorage.setItem('theme', newTheme)
30+
document.documentElement.classList.remove(`theme-${theme}`)
31+
document.documentElement.classList.add(`theme-${newTheme}`)
32+
setIsOpen(false)
33+
}
3434

35-
window.addEventListener('dropdownOpened', handleDropdownChange);
36-
return () => window.removeEventListener('dropdownOpened', handleDropdownChange);
37-
}, []);
35+
const currentTheme = themes.find(t => t.name === theme)
36+
const CurrentIcon = currentTheme?.icon
3837

3938
return (
40-
<div className="relative inline-block">
39+
<div className='relative'>
4140
<button
4241
onClick={() => setIsOpen(!isOpen)}
43-
className="flex items-center justify-center rounded-full p-2 text-white hover:text-white focus:outline-none"
44-
title="Change theme"
42+
className='focus:ring-modern-purple flex items-center space-x-2 rounded-md px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-offset-2'
4543
>
46-
<ColorSwatchIcon className="h-5 w-5" />
44+
{CurrentIcon && <CurrentIcon className='h-5 w-5' />}
45+
<span className='capitalize'>{theme}</span>
4746
</button>
4847

4948
{isOpen && (
50-
<div className="absolute md:right-0 md:mt-2 mt-2 w-36 rounded-md bg-primary py-1 shadow-lg ring-1 ring-black ring-opacity-5 md:left-auto left-0">
51-
{themes.map((theme) => (
52-
<button
53-
key={theme.value}
54-
onClick={() => handleThemeChange(theme.value)}
55-
className={`block w-full px-4 py-2 text-left text-sm text-gray-100
56-
${currentTheme === theme.value ? 'bg-secondary' : ''}
57-
hover:bg-[#1a1a1a] transition-colors duration-150`}
58-
>
59-
{theme.name}
60-
</button>
61-
))}
49+
<div className='absolute left-0 md:left-auto md:right-0 mt-2 w-48 rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none'>
50+
{themes.map(t => {
51+
const Icon = t.icon
52+
return (
53+
<button
54+
key={t.name}
55+
onClick={() => handleThemeChange(t.name)}
56+
className='flex w-full items-center space-x-2 px-4 py-2 text-sm text-gray-700 hover:bg-gray-100'
57+
>
58+
<Icon className='h-5 w-5' />
59+
<span className='capitalize'>{t.name}</span>
60+
</button>
61+
)
62+
})}
6263
</div>
6364
)}
6465
</div>
65-
);
66-
};
66+
)
67+
}
6768

68-
export default ThemeSelector;
69+
export default ThemeSelector
6970

0 commit comments

Comments
 (0)