Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 221 additions & 0 deletions apps/pyconkr/src/components/layout/Footer/Mobile/MobileFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import styled from "@emotion/styled";
import * as Common from "@frontend/common";
import { Article, Email, Facebook, GitHub, Instagram, LinkedIn, X, YouTube } from "@mui/icons-material";
import * as React from "react";

import FlickrIcon from "@apps/pyconkr/assets/thirdparty/flickr.svg?react";

import { useAppContext } from "../../../../contexts/app_context";

interface IconItem {
icon: React.FC<{ width?: number; height?: number }>;
alt: string;
href: string;
}

const defaultIcons: IconItem[] = [
{
icon: Facebook,
alt: "facebook",
href: "https://www.facebook.com/pyconkorea/",
},
{
icon: YouTube,
alt: "YouTube",
href: "https://www.youtube.com/c/PyConKRtube",
},
{ icon: X, alt: "X", href: "https://x.com/PyConKR" },
{ icon: GitHub, alt: "github", href: "https://github.com/pythonkr" },
{
icon: Instagram,
alt: "Instagram",
href: "https://www.instagram.com/pycon_korea/",
},
{
icon: LinkedIn,
alt: "LinkedIn",
href: "https://www.linkedin.com/company/pyconkorea/",
},
{ icon: Article, alt: "blog", href: "https://blog.pycon.kr/" },
{
icon: FlickrIcon,
alt: "Flickr",
href: "https://www.flickr.com/photos/126829363@N08/",
},
];

const Bar: React.FC = () => <div style={{ display: "inline-block", padding: "0 0.25rem" }}>|</div>;

export default function MobileFooter() {
const { sendEmail } = Common.Hooks.Common.useEmail();
const { language } = useAppContext();

const title = language === "ko" ? "Weave with Python, 파이콘 한국 2025" : "Weave with Python, Pycon KR 2025";
const committeeTitle =
language === "ko"
? "파이콘 한국 2025는 파이콘 한국 준비위원회가 만들고 있습니다"
: "PyCon Korea 2025 is organized by the PyCon Korea Organizing Committee";
const djangoTitle = language === "ko" ? "파이썬 웹 프레임워크 Django로 만들었습니다" : "Built with the Django web framework for Python";

const links = [
{
text: language === "ko" ? "파이콘 한국 행동 강령(CoC)" : "PyCon Korea Code of Conduct",
href: "https://pythonkr.github.io/pycon-code-of-conduct/ko/coc/a_intent_and_purpose.html",
},
{
text: language === "ko" ? "서비스 이용 약관" : "Terms of Service",
href: "/about/terms-of-service",
},
{
text: language === "ko" ? "개인 정보 처리 방침" : "Privacy Policy",
href: "/about/privacy-policy",
},
];

return (
<FooterContainer>
<FooterContent>
<FooterSlogan>
<br />
<FooterBoldText children={title} />
<br />
<FooterNormalText children={committeeTitle} />
<br />
<FooterNormalText children={djangoTitle} />
<br />
</FooterSlogan>
<FooterLinks>
{links.map((link, index) => (
<FooterLinkSlogan key={index}>
<Link key={link.text} href={link.href}>
{link.text}
</Link>
{index < links.length - 1 && <Separator>|</Separator>}
</FooterLinkSlogan>
))}
</FooterLinks>
<FooterIcons>
<IconLink onClick={sendEmail} aria-label="이메일 보내기">
<Email width={20} height={20} aria-hidden="true" />
</IconLink>
{defaultIcons.map((icon) => (
<IconLink key={icon.alt} href={icon.href} target="_blank" rel="noopener noreferrer" aria-label={`${icon.alt}로 이동`}>
<icon.icon width={20} height={20} aria-hidden="true" />
</IconLink>
))}
</FooterIcons>
</FooterContent>
</FooterContainer>
);
}

const FooterContainer = styled.footer`
background: linear-gradient(to bottom, #ffffff 0%, #e4fdff 25%, #92c9cc 50%, #5cadb3 75%, #095a5f 100%);
color: ${({ theme }) => theme.palette.common.white};
font-size: 0.75rem;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
max-height: 16rem;
padding: 5rem 0 1rem 0;
`;

const FooterContent = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.75rem;
`;

const FooterText = styled.div`
padding: 0 2rem;
margin: 0.1rem;

font-size: 9pt;

a > button {
margin-left: 0.25rem;
padding: 0.05rem 0.25rem;
font-size: 8pt;
color: ${({ theme }) => theme.palette.common.white};
border-color: ${({ theme }) => theme.palette.common.white};

gap: 0.25rem;

& span {
margin-left: -2px;
margin-right: 0;

& svg {
font-size: 12pt !important;
}
}
}

strong {
font-size: 12pt;
}
`;

const FooterBoldText = styled.text`
font-weight: 600;
`;

const FooterNormalText = styled.text`
font-weight: 400;
`;

const FooterSlogan = styled.div`
text-align: center;
`;

const FooterLinkSlogan = styled.div`
display: flex;
gap: 0.3rem;
`;

const FooterLinks = styled.div`
display: flex;
align-items: center;
gap: 0.3rem;
`;

const FooterIcons = styled.div`
display: flex;
align-items: center;
gap: 9px;
`;

const Link = styled.a`
color: ${({ theme }) => theme.palette.common.white};
text-decoration: none;
&:hover {
text-decoration: underline;
}
`;

const Separator = styled.span`
color: ${({ theme }) => theme.palette.common.white};
opacity: 0.5;
margin: 0.05rem 0;
`;

const IconLink = styled.a`
display: flex;
align-items: center;
justify-content: center;

cursor: pointer;

&:hover {
opacity: 0.8;
}

img {
width: 20px;
height: 20px;
}
`;
111 changes: 61 additions & 50 deletions apps/pyconkr/src/components/layout/Footer/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import styled from "@emotion/styled";
import * as Common from "@frontend/common";
import { Article, Email, Facebook, GitHub, Instagram, LinkedIn, OpenInNew, X, YouTube } from "@mui/icons-material";
import { Button } from "@mui/material";
import { Button, useMediaQuery, useTheme } from "@mui/material";
import * as React from "react";

import FlickrIcon from "@apps/pyconkr/assets/thirdparty/flickr.svg?react";

import { useAppContext } from "../../../contexts/app_context";
import MobileFooter from "./Mobile/MobileFooter";

interface IconItem {
icon: React.FC<{ width?: number; height?: number }>;
Expand Down Expand Up @@ -49,6 +50,9 @@ const Bar: React.FC = () => <div style={{ display: "inline-block", padding: "0 0

export default function Footer() {
const { sendEmail } = Common.Hooks.Common.useEmail();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("md"));

const { language } = useAppContext();

const corpPasamoStr = language === "ko" ? "사단법인 파이썬사용자모임" : "Python Korea";
Expand Down Expand Up @@ -83,56 +87,62 @@ export default function Footer() {
},
];

return (
<FooterContainer>
<FooterContent>
<FooterText>
<strong>{corpPasamoStr}</strong>
<br />
{corpAddressStr}
<Bar />
{corpRepresentatorStr}
<Bar />
{corpPhoneStr}
<Bar />
{corpCompanyNumberStr}
<a href="http://www.ftc.go.kr/bizCommPop.do?wrkr_no=3388200046" target="_blank" rel="noreferrer">
<Button variant="outlined" startIcon={<OpenInNew sx={{ fontSize: "7pt" }} />}>
{corpCheckBtnStr}
</Button>
</a>
<br />
{corpMailOrderSalesRegistrationNumberStr}
<Bar />
{hostingProviderStr}
<Bar />
{contractEmailStr}
<a href="mailto:pyconkr@pycon.kr">pyconkr@pycon.kr</a>
</FooterText>
<FooterLinks>
{links.map((link, index) => (
<React.Fragment key={index}>
<Link key={link.text} href={link.href}>
{link.text}
</Link>
{index < links.length - 1 && <Separator>|</Separator>}
</React.Fragment>
))}
</FooterLinks>
<FooterIcons>
<IconLink onClick={sendEmail} aria-label="이메일 보내기">
<Email width={20} height={20} aria-hidden="true" />
</IconLink>
{defaultIcons.map((icon) => (
<IconLink key={icon.alt} href={icon.href} target="_blank" rel="noopener noreferrer" aria-label={`${icon.alt}로 이동`}>
<icon.icon width={20} height={20} aria-hidden="true" />
console.log("isMobile " + isMobile);

if (isMobile) {
return <MobileFooter />;
} else {
return (
<FooterContainer>
<FooterContent>
<FooterText>
<strong>{corpPasamoStr}</strong>
<br />
{corpAddressStr}
<Bar />
{corpRepresentatorStr}
<Bar />
{corpPhoneStr}
<Bar />
{corpCompanyNumberStr}
<a href="http://www.ftc.go.kr/bizCommPop.do?wrkr_no=3388200046" target="_blank" rel="noreferrer">
<Button variant="outlined" startIcon={<OpenInNew sx={{ fontSize: "7pt" }} />}>
{corpCheckBtnStr}
</Button>
</a>
<br />
{corpMailOrderSalesRegistrationNumberStr}
<Bar />
{hostingProviderStr}
<Bar />
{contractEmailStr}
<a href="mailto:pyconkr@pycon.kr">pyconkr@pycon.kr</a>
</FooterText>
<FooterLinks>
{links.map((link, index) => (
<React.Fragment key={index}>
<Link key={link.text} href={link.href}>
{link.text}
</Link>
{index < links.length - 1 && <Separator>|</Separator>}
</React.Fragment>
))}
</FooterLinks>
<FooterIcons>
<IconLink onClick={sendEmail} aria-label="이메일 보내기">
<Email width={20} height={20} aria-hidden="true" />
</IconLink>
))}
</FooterIcons>
<FooterSlogan>{copyrightStr}</FooterSlogan>
</FooterContent>
</FooterContainer>
);
{defaultIcons.map((icon) => (
<IconLink key={icon.alt} href={icon.href} target="_blank" rel="noopener noreferrer" aria-label={`${icon.alt}로 이동`}>
<icon.icon width={20} height={20} aria-hidden="true" />
</IconLink>
))}
</FooterIcons>
<FooterSlogan>{copyrightStr}</FooterSlogan>
</FooterContent>
</FooterContainer>
);
}
}

const FooterContainer = styled.footer`
Expand Down Expand Up @@ -195,6 +205,7 @@ const FooterLinks = styled.div`
align-items: center;
gap: 0.625rem;
`;

const FooterIcons = styled.div`
display: flex;
align-items: center;
Expand Down