فهرست منبع

add sponsors section

AykutSarac 2 سال پیش
والد
کامیت
ae667d4a3b
3فایلهای تغییر یافته به همراه127 افزوده شده و 2 حذف شده
  1. 94 0
      src/components/Sponsors/index.tsx
  2. 2 0
      src/containers/Home/index.tsx
  3. 31 2
      src/hooks/store/useConfig.tsx

+ 94 - 0
src/components/Sponsors/index.tsx

@@ -0,0 +1,94 @@
+import React from "react";
+import useConfig from "src/hooks/store/useConfig";
+import styled from "styled-components";
+
+async function getSponsors() {
+  try {
+    const res = await fetch("https://ghs.vercel.app/sponsors/aykutsarac");
+    const data = await res.json();
+
+    if (data.sponsors) {
+      return data.sponsors.map((user) => ({
+        handle: user.handle,
+        avatar: user.avatar,
+        profile: user.profile,
+      }));
+    }
+
+    return [];
+  } catch (error) {
+    console.error(error);
+    return [];
+  }
+}
+
+const StyledSponsorsWrapper = styled.ul`
+  display: flex;
+  width: 100%;
+  margin: 0;
+  padding: 0;
+  list-style: none;
+  gap: 10px;
+  flex-wrap: wrap;
+  align-items: center;
+  justify-content: center;
+`;
+
+const StyledSponsor = styled.li<{ handle: string }>`
+  display: flex;
+  justify-content: center;
+  position: relative;
+
+  &:hover {
+    &::before {
+      content: "${({ handle }) => handle}";
+      position: absolute;
+      top: 0;
+      background: ${({ theme }) => theme.BACKGROUND_PRIMARY};
+      transform: translateY(-130%);
+      padding: 6px 8px;
+      border-radius: 4px;
+      font-weight: 500;
+      font-size: 14px;
+    }
+
+    &::after {
+      content: "";
+      position: absolute;
+      top: 0;
+      transform: translateY(-110%);
+      border-width: 5px;
+      border-style: solid;
+      border-color: ${({ theme }) => theme.BACKGROUND_PRIMARY} transparent
+        transparent transparent;
+    }
+  }
+
+  img {
+    border-radius: 100%;
+  }
+`;
+
+export const Sponsors = () => {
+  const { sponsors, setSponsors } = useConfig();
+
+  React.useEffect(() => {
+    if (!sponsors?.nextDate || sponsors?.nextDate < Date.now()) {
+      getSponsors().then(setSponsors);
+    }
+  }, []);
+
+  if (!sponsors?.users.length) return null;
+
+  return (
+    <StyledSponsorsWrapper>
+      {sponsors.users.map((user) => (
+        <StyledSponsor handle={user.handle} key={user.handle}>
+          <a href={user.profile}>
+            <img src={user.avatar} alt={user.handle} width="40" height="40" />
+          </a>
+        </StyledSponsor>
+      ))}
+    </StyledSponsorsWrapper>
+  );
+};

+ 2 - 0
src/containers/Home/index.tsx

@@ -15,6 +15,7 @@ import { CarbonAds } from "src/components/CarbonAds";
 import pkg from "../../../package.json";
 import * as Styles from "./styles";
 import { GoalsModal } from "../Modals/GoalsModal";
+import { Sponsors } from "src/components/Sponsors";
 
 const Home: React.FC = () => {
   const { push } = useRouter();
@@ -205,6 +206,7 @@ const Home: React.FC = () => {
         >
           Become A Sponsor!
         </Styles.StyledButton>
+        <Sponsors />
       </Styles.StyledSponsorSection>
 
       <Styles.StyledFooter>

+ 31 - 2
src/hooks/store/useConfig.tsx

@@ -3,9 +3,27 @@ import { persist } from "zustand/middleware";
 import { defaultConfig, defaultJson } from "src/constants/data";
 import { StorageConfig } from "src/typings/global";
 
+type Sponsor = {
+  handle: string;
+  avatar: string;
+  profile: string;
+};
+
+function getTomorrow() {
+  const today = new Date();
+  const tomorrow = new Date(today);
+  tomorrow.setDate(tomorrow.getDate() + 1);
+  return new Date(tomorrow).getTime();
+}
+
 export interface Config {
   json: string;
   settings: StorageConfig;
+  sponsors: {
+    users: Sponsor[];
+    nextDate: number;
+  } | null;
+  setSponsors: (sponsors: Sponsor[]) => void;
   updateJson: (json: string) => void;
   loadSettings: (settings: StorageConfig) => void;
   updateSetting: (setting: keyof StorageConfig, value: unknown) => void;
@@ -19,6 +37,15 @@ const useConfig = create(
     (set, get) => ({
       json: JSON.stringify(defaultJson),
       settings: defaultConfig,
+      sponsors: null,
+      setSponsors: (users) =>
+        set((state) => ({
+          ...state,
+          sponsors: {
+            users,
+            nextDate: getTomorrow(),
+          },
+        })),
       updateJson: (json: string) => set((state) => ({ ...state, json })),
       zoomIn: () => {
         const zoomPanPinch = get().settings.zoomPanPinch;
@@ -54,10 +81,12 @@ const useConfig = create(
     }),
     {
       name: "config",
+      version: 1,
       partialize: (state) =>
         ({
-          ...state,
-          json: undefined,
+          sponsors: {
+            ...state.sponsors,
+          },
           settings: {
             ...state.settings,
             zoomPanPinch: undefined,