first commit

This commit is contained in:
2024-03-20 00:12:01 +03:00
commit 1e0ab27b74
148 changed files with 12934 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
.reviewCard {
margin-top: 48px;
border-bottom-left-radius: 40px !important;
border-bottom-right-radius: 40px !important;
overflow: unset !important;
--on-background: #303309;
--on-background-secondary: #616825;
--background: #e6f45d;
}
.reviewCardContent {
margin: -36px;
margin-top: 36px !important;
}
.googlePlayButton {
width: 100%;
}
.main {
padding: 48px;
padding-top: 0;
display: flex;
flex-direction: column;
gap: 48px;
max-width: 1500px;
width: 100%;
align-self: center;
}
.cardsRow {
display: flex;
flex-direction: row;
gap: 48px;
}
.stores {
display: flex;
flex-direction: column;
gap: 16px;
}
.additionalStores {
display: flex;
flex-direction: row;
&>*:first-child {
flex-grow: 1;
}
}
@media screen and (max-width: 980px) {
.cardsRow {
flex-direction: column;
}
.reviewCard {
margin-top: 0;
}
}
@media screen and (max-width: 730px) {
.main {
padding: 24px;
gap: 24px;
}
.cardsRow {
gap: 24px;
}
}
@media screen and (max-width: 500px) {
.main {
padding: 16px;
gap: 16px;
}
.cardsRow {
gap: 16px;
}
.homeLink {
margin: 0 auto;
margin-top: 44px;
}
.description {
text-align: center;
}
}

View File

@@ -0,0 +1,216 @@
.header {
min-height: 30vh;
padding: 220px 78px;
padding-top: 330px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
position: relative;
width: 100%;
flex-shrink: 0;
}
.content {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
max-width: 1300px;
margin: 0 auto;
}
.description {
font-weight: 600;
font-size: 2rem;
max-width: 780px;
color: #4F3527;
line-height: 150%;
.appName {
font-weight: 700;
color: #361400;
}
.hobbyProject {
}
.notPlanEarnMoney {
margin: 0px 20px;
span {
box-shadow: -16px 0px 0px 2px #FF005C, 16px 0px 0px 2px #FF005C;
background-color: #FF005C;
color: #fff;
box-decoration-break: clone;
border-radius: 9px;
}
}
.contributeArrowWrapper {
display: inline-block;
}
.contributeArrow {
position: relative;
display: inline;
div {
position: absolute;
top: 13px;
left: 26px;
}
}
}
.chipsContainer {
flex-grow: 1;
align-items: center;
display: flex;
flex-direction: column;
transform: rotate(-25deg);
width: max-content;
}
.chip {
padding: 12px 32px;
padding-right: 22px;
border-radius: 40px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
gap: 9px;
font-size: 1.62rem;
font-weight: 600;
width: fit-content;
.icon {
display: flex;
}
}
.openSourceChip {
background-color: #DDF9D0;
color: #339704;
transform: translateX(-50px);
svg {
color: #339704;
width: 35px;
height: 35px;
}
}
.madeWithLoveChip {
background-color: #FFEEF2;
color: #861118;
transform: translateX(50px);
svg {
color: #FF003D;
width: 35px;
height: 35px;
}
}
.gradientContainer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: calc(100% + 300px);
z-index: -100;
}
.transitionToBackgound {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 300px;
background: linear-gradient(180deg, #ffffff00 0%, #ffffff 300px);
}
@media (max-width: 1250px) {
.chipsContainer {
position: absolute;
right: 0;
left: -60px;
margin: auto;
top: 230px;
flex-direction: row;
transform: rotate(356deg);
z-index: -1;
}
.openSourceChip {
transform: translate(90px, -20px) rotate(-15deg);
}
.madeWithLoveChip {
transform: translateX(0px);
}
.header {
padding-top: 390px;
}
}
@media (max-width: 940px) {
.header {
padding: 200px 48px;
padding-top: 360px;
}
.description {
text-align: justify;
max-width: 100%;
}
}
@media (max-width: 800px) {
.header {
padding: 130px 48px;
padding-top: 360px;
}
.description {
font-size: 1.5rem;
line-height: 170%;
.contributeArrow {
div {
top: 8px;
}
svg {
width: auto;
height: 150px;
}
}
}
}
@media (max-width: 640px) {
.header {
padding: 110px 36px;
padding-top: 360px;
}
.chipsContainer {
top: 200px;
scale: 0.7;
}
.description {
.contributeArrow {
div {
top: 10px;
}
svg {
width: auto;
height: 130px;
}
}
}
}

View File

@@ -0,0 +1,127 @@
import styles from './header.module.scss';
import { TopBar } from '@/components/topBar';
import useLocale from '@/utils/useLocale';
import { LocalesMap } from '@/utils/useLocale';
import { clsx } from 'clsx';
import LoveIcon from '@/assets/icons/love.svg';
import OpenSourceIcon from '@/assets/icons/open-source.svg';
import { Gradients } from '@/components/gradients';
import ContributeArrow from '@/assets/images/contribute-arrow.svg';
import ContributeArrowInvert from '@/assets/images/contribute-arrow-invert.svg';
import { useEffect, useRef, useState } from 'react';
import useMediaQuery from '@/utils/useMediaQuery';
export const locales: LocalesMap = {
ru: {
appName: 'RideBus',
description: (
<>
<span className={styles.appName}>RideBus</span> — это <span className={styles.hobbyProject}>хобби-проект</span>{' '}
и я <span className={styles.notPlanEarnMoney}><span>не&nbsp;планирую на нём зарабатывать</span></span>,{' '}
если вы хотите помочь, вот способ, как это <span className={styles.contributeArrowWrapper}>сделать<Arrow /></span>
</>
),
openSource: 'Open source',
madeWithLove: 'Сделано с',
},
en: {
appName: 'RideBus',
description: (
<>
<span className={styles.appName}>RideBus</span> is <span className={styles.hobbyProject}>a hobby project</span>{' '}
and I <span className={styles.notPlanEarnMoney}><span>do&nbsp;not&nbsp;plan to earn money&nbsp;on&nbsp;it</span></span>,{' '}
if you want to help, here is a way how to do <span className={styles.contributeArrowWrapper}>it <Arrow /></span>
</>
),
openSource: 'Open source',
madeWithLove: 'Made with',
},
};
function Arrow() {
const rootRef = useRef<HTMLDivElement>(null);
const [isInvertArrow, setIsInvertArrow] = useState(false);
const breakpoint640 = useMediaQuery('(max-width: 640px)');
const breakpoint800 = useMediaQuery('(max-width: 800px)');
useEffect(() => {
const arrowWidth = breakpoint640 ? 260 : breakpoint800 ? 300 : 460;
const handleResize = () => {
if (rootRef.current) {
const { left } = rootRef.current.getBoundingClientRect();
if (window.innerWidth < left + arrowWidth) {
setIsInvertArrow(true);
} else {
setIsInvertArrow(false);
}
}
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, [breakpoint640, breakpoint800]);
let left = isInvertArrow ? '-130px' : '26px';
if (breakpoint640) {
left = isInvertArrow ? '-95px' : '16px';
}
if (breakpoint800) {
left = isInvertArrow ? '-95px' : '16px';
}
return (
<span ref={rootRef} className={styles.contributeArrow}>
<span style={{ width: '140px', display: 'inline-block' }} />
<div style={{ left }}>
{isInvertArrow ? <ContributeArrowInvert /> : <ContributeArrow />}
</div>
</span>
)
}
type ChipProps = {
className?: string;
label: string;
icon: any;
};
function Chip(props: ChipProps) {
const { className, label, icon } = props;
return (
<div className={clsx(styles.chip, className)}>
<span>{label}</span>
<span className={styles.icon}>{icon}</span>
</div>
);
}
export function Header() {
const t = useLocale(locales);
return (
<header className={styles.header}>
<TopBar notHide />
<div className={styles.content}>
<p className={styles.description}>{t('description')}</p>
<div className={styles.chipsContainer}>
<Chip className={styles.openSourceChip} label={t('openSource')} icon={(<OpenSourceIcon />)} />
<Chip className={styles.madeWithLoveChip} label={t('madeWithLove')} icon={(<LoveIcon />)} />
</div>
</div>
<div className={styles.gradientContainer}>
<div
className={styles.transitionToBackgound}
/>
<Gradients />
</div>
</header>
);
}

View File

@@ -0,0 +1 @@
export * from './header';

View File

@@ -0,0 +1,21 @@
import { LocalesMap } from '@/utils/useLocale';
export const locales: LocalesMap = {
ru: {
pageTitle: 'RideBus - Вклад',
pageDescription:
'RideBus — Приложение, которое поможет вам удобно смотреть расписание общественного транспорта',
appName: 'RideBus',
reviewTitle: 'Оставьте отзыв',
reviewDescription:
'Буду благодарен, если вы оставите свой отзыв о приложении. Отзывы очень важны и помогают улучшать приложение.',
},
en: {
pageTitle: 'RideBus - Contribute',
pageDescription: 'RideBus — An app that helps you conveniently view public transportation schedules',
appName: 'RideBus',
reviewTitle: 'Leave a review',
reviewDescription:
'I would be grateful if you could leave your feedback on the application. Reviews are very important and help us improve application.',
},
};

View File

@@ -0,0 +1 @@
export * from './shareCard';

View File

@@ -0,0 +1,49 @@
.card {
--on-background: #59321c;
--on-background-secondary: #866655;
--background: #ffefe9;
position: relative;
}
.description {
padding: 8px;
margin: -8px;
margin-top: 0;
padding-top: 6px;
}
.heartContiner {
position: absolute;
bottom: -18%;
right: -17%;
z-index: 0;
}
.heartImage {
width: 420px;
height: auto;
}
@media screen and (max-width: 980px) {
.card {
height: min-content;
}
.heartContiner {
bottom: -32%;
right: -4%;
}
}
@media screen and (max-width: 820px) {
.heartContiner {
bottom: -42%;
right: -4%;
}
.heartImage {
width: 300px;
}
.content {
margin-top: 0;
}
}

View File

@@ -0,0 +1,60 @@
import styles from './shareCard.module.scss';
import { Card } from '@/components/card';
import clsx from 'clsx';
import useLocale, { LocalesMap } from '@/utils/useLocale';
import { CursorEffect } from '@/components/cursor';
const locales: LocalesMap = {
ru: {
appName: 'RideBus',
slogan: 'Приложение, которое поможет вам удобно смотреть расписание общественного транспорта',
title: 'Расскажите друзьям',
description:
'Мне очень важно, чтобы мои проекты приносили пользу. Если вы расскажете своим друзьям о своем опыте использования этого приложения и как оно помогло вам, я буду вам очень признателен.',
},
en: {
appName: 'RideBus',
slogan: 'An app that helps you conveniently view public transportation schedules',
title: 'Tell your friends',
description:
'It is very important to me that my projects bring benefits. If you tell your friends about your experience using this application and how it helped you, I will be very grateful to you.',
},
};
export function ShareCard() {
const t = useLocale(locales);
const ShareCard = (
<Card
className={clsx(styles.card)}
title={t('title')}
subtitle={t('description')}
backdropOnText
classes={{ subtitle: styles.description, content: styles.content }}
onClick={() => {
if (navigator.share) {
navigator
.share({
title: t('appName'),
text: t('slogan'),
url: 'https://ridebus.by/',
})
.then(() => {
console.log('Thanks for sharing!');
})
.catch(console.error);
}
}}
>
</Card>
);
if (typeof window !== 'undefined' && (navigator.share as any)) {
return (
<CursorEffect cursorPadding={8} cursorBorderRadius={36}>
{ShareCard}
</CursorEffect>
);
} else {
return ShareCard;
}
}