mirror of
https://github.com/AykutSarac/jsoncrack.com.git
synced 2025-01-20 05:12:54 +08:00
update pricing styles
This commit is contained in:
parent
321a13ab37
commit
319abe039b
@ -53,10 +53,15 @@ const StyledBottomBarItem = styled.button`
|
||||
font-weight: 400;
|
||||
color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
|
||||
|
||||
&:hover {
|
||||
&:hover:not(&:disabled) {
|
||||
background-image: linear-gradient(rgba(0, 0, 0, 0.1) 0 0);
|
||||
color: ${({ theme }) => theme.INTERACTIVE_HOVER};
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
opacity: 0.4;
|
||||
cursor: progress;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledImg = styled.img<{ light: boolean }>`
|
||||
@ -74,6 +79,7 @@ export const BottomBar = () => {
|
||||
const setVisible = useModal(state => state.setVisible);
|
||||
const setHasChanges = useJson(state => state.setHasChanges);
|
||||
const [isPrivate, setIsPrivate] = React.useState(false);
|
||||
const [isUpdating, setIsUpdating] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
setIsPrivate(data?.private ?? false);
|
||||
@ -84,6 +90,7 @@ export const BottomBar = () => {
|
||||
|
||||
if (hasChanges) {
|
||||
try {
|
||||
setIsUpdating(true);
|
||||
toast.loading("Saving JSON...", { id: "jsonSave" });
|
||||
const res = await saveJson({ id: query.json as string, data: getJson() });
|
||||
|
||||
@ -98,6 +105,8 @@ export const BottomBar = () => {
|
||||
}
|
||||
|
||||
toast.error("Failed to save JSON!", { id: "jsonSave" });
|
||||
} finally {
|
||||
setIsUpdating(false);
|
||||
}
|
||||
}
|
||||
}, [getJson, hasChanges, query.json, replace, setHasChanges, setVisible, user]);
|
||||
@ -107,10 +116,24 @@ export const BottomBar = () => {
|
||||
else setVisible("login")(true);
|
||||
};
|
||||
|
||||
const setPrivate = () => {
|
||||
const setPrivate = async () => {
|
||||
try {
|
||||
if (!query.json) return handleSaveJson();
|
||||
setIsPrivate(!isPrivate);
|
||||
updateJson(query.json as string, { private: !isPrivate });
|
||||
if (!isPrivate && user?.type === 0) {
|
||||
return window.open("https://jsoncrack.com/pricing", "_blank");
|
||||
}
|
||||
|
||||
setIsUpdating(true);
|
||||
const res = await updateJson(query.json as string, { private: !isPrivate });
|
||||
if (!res.errors?.items.length) {
|
||||
setIsPrivate(res.data.private);
|
||||
toast.success(`Document set to ${isPrivate ? "public" : "private"}.`);
|
||||
} else throw res.errors;
|
||||
} catch (error) {
|
||||
toast.error("An error occured while updating document!");
|
||||
} finally {
|
||||
setIsUpdating(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@ -120,14 +143,14 @@ export const BottomBar = () => {
|
||||
<VscAccount />
|
||||
{user ? user.name : "Login"}
|
||||
</StyledBottomBarItem>
|
||||
<StyledBottomBarItem onClick={handleSaveJson}>
|
||||
<StyledBottomBarItem onClick={handleSaveJson} disabled={isUpdating}>
|
||||
{hasChanges ? <AiOutlineCloudUpload /> : <AiOutlineCloudSync />}
|
||||
{hasChanges ? "Unsaved Changes" : "Saved"}
|
||||
</StyledBottomBarItem>
|
||||
{data && (
|
||||
<>
|
||||
{typeof data.private !== "undefined" && (
|
||||
<StyledBottomBarItem onClick={setPrivate}>
|
||||
<StyledBottomBarItem onClick={setPrivate} disabled={isUpdating}>
|
||||
{isPrivate ? <AiOutlineLock /> : <AiOutlineUnlock />}
|
||||
{isPrivate ? "Private" : "Public"}
|
||||
</StyledBottomBarItem>
|
||||
|
@ -18,6 +18,7 @@ import { Sponsors } from "src/components/Sponsors";
|
||||
import { SupportButton } from "src/components/SupportButton";
|
||||
import { baseURL } from "src/constants/data";
|
||||
import * as Styles from "./styles";
|
||||
import { PricingCards } from "../PricingCards";
|
||||
|
||||
const Navbar = () => (
|
||||
<Styles.StyledNavbar>
|
||||
@ -282,6 +283,7 @@ const Home: React.FC = () => {
|
||||
<FeaturesSection />
|
||||
<GitHubSection />
|
||||
<EmbedSection />
|
||||
<PricingCards />
|
||||
<SupportSection />
|
||||
<SponsorSection />
|
||||
<SupportButton />
|
||||
|
@ -80,7 +80,7 @@ const AccountView: React.FC<Pick<ModalProps, "setVisible">> = ({ setVisible }) =
|
||||
<StyledContainer>
|
||||
ACCOUNT STATUS
|
||||
<div>
|
||||
{isPremium ? "PREMIUM " : "Normal"}
|
||||
{isPremium ? "PREMIUM " : "Free"}
|
||||
{isPremium && <MdVerified />}
|
||||
</div>
|
||||
</StyledContainer>
|
||||
@ -93,7 +93,11 @@ const AccountView: React.FC<Pick<ModalProps, "setVisible">> = ({ setVisible }) =
|
||||
<div>{user?.signUpAt && new Date(user.signUpAt).toDateString()}</div>
|
||||
</StyledContainer>
|
||||
{isPremium ? (
|
||||
<Button status="DANGER" block>
|
||||
<Button
|
||||
status="DANGER"
|
||||
block
|
||||
onClick={() => window.open("https://patreon.com/jsoncrack", "_blank")}
|
||||
>
|
||||
<IoRocketSharp />
|
||||
Cancel Subscription
|
||||
</Button>
|
||||
|
@ -4,7 +4,13 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import toast from "react-hot-toast";
|
||||
import { AiOutlineEdit, AiOutlineLock, AiOutlinePlus, AiOutlineUnlock } from "react-icons/ai";
|
||||
import {
|
||||
AiOutlineEdit,
|
||||
AiOutlineInfoCircle,
|
||||
AiOutlineLock,
|
||||
AiOutlinePlus,
|
||||
AiOutlineUnlock,
|
||||
} from "react-icons/ai";
|
||||
import { FaTrash } from "react-icons/fa";
|
||||
import { IoRocketSharp } from "react-icons/io5";
|
||||
import { Button } from "src/components/Button";
|
||||
@ -94,6 +100,16 @@ const StyledNameInput = styled.input`
|
||||
font-weight: 600;
|
||||
`;
|
||||
|
||||
const StyledInfoText = styled.span`
|
||||
font-size: 10px;
|
||||
color: ${({ theme }) => theme.INTERACTIVE_NORMAL};
|
||||
|
||||
svg {
|
||||
vertical-align: text-top;
|
||||
margin-right: 4px;
|
||||
}
|
||||
`;
|
||||
|
||||
const GraphCard: React.FC<{ data: Json; refetch: () => void; active: boolean }> = ({
|
||||
data,
|
||||
refetch,
|
||||
@ -241,7 +257,13 @@ export const CloudModal: React.FC<ModalProps> = ({ visible, setVisible }) => {
|
||||
)}
|
||||
</StyledModalContent>
|
||||
</Modal.Content>
|
||||
<Modal.Controls setVisible={setVisible}></Modal.Controls>
|
||||
|
||||
<Modal.Controls setVisible={setVisible}>
|
||||
<StyledInfoText>
|
||||
<AiOutlineInfoCircle />
|
||||
Cloud Save feature is for ease-of-access only and recommended to not store sensitive data.
|
||||
</StyledInfoText>
|
||||
</Modal.Controls>
|
||||
</StyledModal>
|
||||
);
|
||||
};
|
||||
|
129
src/containers/PricingCards/index.tsx
Normal file
129
src/containers/PricingCards/index.tsx
Normal file
@ -0,0 +1,129 @@
|
||||
import React from "react";
|
||||
import { Button } from "src/components/Button";
|
||||
import styled from "styled-components";
|
||||
|
||||
const StyledSectionBody = styled.div`
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
gap: 50px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: rgba(181, 116, 214, 0.23);
|
||||
width: 80%;
|
||||
margin: 5% auto 0;
|
||||
border-radius: 6px;
|
||||
padding: 50px;
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
padding: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledPricingCard = styled.div<{ premium?: boolean }>`
|
||||
padding: 6px;
|
||||
padding-bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
${({ premium }) =>
|
||||
premium
|
||||
? `
|
||||
background: rgba(255, 5, 214, 0.19);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
border: 1px solid rgba(255, 5, 214, 0.74);`
|
||||
: `background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);`};
|
||||
`;
|
||||
|
||||
const StyledPricingCardTitle = styled.h2`
|
||||
text-align: center;
|
||||
font-weight: 800;
|
||||
font-size: 24px;
|
||||
`;
|
||||
|
||||
const StyledPricingCardPrice = styled.h3`
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
font-size: 24px;
|
||||
color: ${({ theme }) => theme.SILVER};
|
||||
`;
|
||||
|
||||
const StyledPricingCardDetails = styled.ul`
|
||||
color: ${({ theme }) => theme.TEXT_NORMAL};
|
||||
line-height: 2.3;
|
||||
padding: 20px;
|
||||
`;
|
||||
|
||||
const StyledPricingCardDetailsItem = styled.li`
|
||||
font-weight: 500;
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
font-size: 14px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
border: 1px solid white;
|
||||
`;
|
||||
|
||||
const StyledPricingSection = styled.section`
|
||||
margin: 0 auto;
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
padding-bottom: 25px;
|
||||
}
|
||||
`;
|
||||
|
||||
export const PricingCards = () => {
|
||||
return (
|
||||
<StyledPricingSection>
|
||||
<h1>Unlock Full Potential of JSON Crack</h1>
|
||||
<StyledSectionBody>
|
||||
<StyledPricingCard>
|
||||
<StyledPricingCardTitle>Free</StyledPricingCardTitle>
|
||||
<StyledPricingCardDetails>
|
||||
<StyledPricingCardDetailsItem>Store up to 15 files</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>
|
||||
Create short-links for saved JSON files
|
||||
</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>Embed saved JSON instantly</StyledPricingCardDetailsItem>
|
||||
</StyledPricingCardDetails>
|
||||
</StyledPricingCard>
|
||||
<StyledPricingCard premium>
|
||||
<StyledPricingCardTitle>Premium</StyledPricingCardTitle>
|
||||
<StyledPricingCardPrice>$5/mo</StyledPricingCardPrice>
|
||||
<StyledPricingCardDetails>
|
||||
<StyledPricingCardDetailsItem>
|
||||
Create and share up to 200 files
|
||||
</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>Store private JSON</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>
|
||||
Get access to JSON Crack API to generate JSON remotely
|
||||
</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>Everything in previous tier</StyledPricingCardDetailsItem>
|
||||
</StyledPricingCardDetails>
|
||||
<StyledButton
|
||||
href="https://www.patreon.com/jsoncrack"
|
||||
target="_blank"
|
||||
status="SUCCESS"
|
||||
block
|
||||
link
|
||||
>
|
||||
GET IT NOW!
|
||||
</StyledButton>
|
||||
</StyledPricingCard>
|
||||
</StyledSectionBody>
|
||||
</StyledPricingSection>
|
||||
);
|
||||
};
|
@ -1,6 +1,7 @@
|
||||
import React from "react";
|
||||
import { Button } from "src/components/Button";
|
||||
import { Footer } from "src/components/Footer";
|
||||
import { PricingCards } from "src/containers/PricingCards";
|
||||
import styled from "styled-components";
|
||||
|
||||
const StyledPageWrapper = styled.div`
|
||||
@ -13,108 +14,18 @@ const StyledHeroSection = styled.section`
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const StyledPricingSection = styled.section`
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
background: rgba(181, 116, 214, 0.23);
|
||||
width: 60%;
|
||||
margin: 5% auto 0;
|
||||
border-radius: 6px;
|
||||
padding: 40px 20px;
|
||||
`;
|
||||
|
||||
const StyledPricingCard = styled.div<{ premium?: boolean }>`
|
||||
padding: 6px;
|
||||
width: 40%;
|
||||
|
||||
${({ premium }) =>
|
||||
premium
|
||||
? `
|
||||
background: rgba(255, 5, 214, 0.19);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
border: 1px solid rgba(255, 5, 214, 0.74);`
|
||||
: `background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(5px);
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);`};
|
||||
`;
|
||||
|
||||
const StyledPricingCardTitle = styled.h2`
|
||||
text-align: center;
|
||||
font-weight: 800;
|
||||
font-size: 24px;
|
||||
`;
|
||||
|
||||
const StyledPricingCardPrice = styled.h3`
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
font-size: 24px;
|
||||
color: ${({ theme }) => theme.SILVER};
|
||||
`;
|
||||
|
||||
const StyledPricingCardDetails = styled.ul`
|
||||
color: ${({ theme }) => theme.TEXT_NORMAL};
|
||||
line-height: 2.3;
|
||||
`;
|
||||
|
||||
const StyledPricingCardDetailsItem = styled.li`
|
||||
font-weight: 500;
|
||||
`;
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
border: 1px solid white;
|
||||
`;
|
||||
|
||||
const Pricing = () => {
|
||||
return (
|
||||
<>
|
||||
<StyledPageWrapper>
|
||||
<Button href="/" link>
|
||||
< Go Back
|
||||
</Button>
|
||||
<StyledHeroSection>
|
||||
<img src="assets/icon.png" alt="json crack" width="400" />
|
||||
<h1>Premium</h1>
|
||||
</StyledHeroSection>
|
||||
<StyledPricingSection>
|
||||
<StyledPricingCard>
|
||||
<StyledPricingCardTitle>Free</StyledPricingCardTitle>
|
||||
<StyledPricingCardDetails>
|
||||
<StyledPricingCardDetailsItem>Store up to 20 files</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>
|
||||
Create short-links for saved JSON files
|
||||
</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>
|
||||
Embed saved JSON instantly
|
||||
</StyledPricingCardDetailsItem>
|
||||
</StyledPricingCardDetails>
|
||||
</StyledPricingCard>
|
||||
<StyledPricingCard premium>
|
||||
<StyledPricingCardTitle>Premium</StyledPricingCardTitle>
|
||||
<StyledPricingCardPrice>$5/mo</StyledPricingCardPrice>
|
||||
<StyledPricingCardDetails>
|
||||
<StyledPricingCardDetailsItem>
|
||||
Create and share up to 200 files
|
||||
</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>Store private JSON</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>
|
||||
Premium role at Discord server
|
||||
</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>
|
||||
Get access to JSON Crack API to generate JSON remotely
|
||||
</StyledPricingCardDetailsItem>
|
||||
<StyledPricingCardDetailsItem>
|
||||
Everything in previous tier
|
||||
</StyledPricingCardDetailsItem>
|
||||
</StyledPricingCardDetails>
|
||||
<StyledButton href="https://www.patreon.com/jsoncrack" status="SUCCESS" block link>
|
||||
GET IT NOW!
|
||||
</StyledButton>
|
||||
</StyledPricingCard>
|
||||
</StyledPricingSection>
|
||||
<PricingCards />
|
||||
</StyledPageWrapper>
|
||||
<Footer />
|
||||
</>
|
||||
|
Loading…
x
Reference in New Issue
Block a user