diff --git a/src/assets/images/appstore_download.svg b/src/assets/images/appstore_download.svg new file mode 100644 index 0000000..0bb64cc --- /dev/null +++ b/src/assets/images/appstore_download.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/playstore_download.svg b/src/assets/images/playstore_download.svg new file mode 100644 index 0000000..6e3f86b --- /dev/null +++ b/src/assets/images/playstore_download.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/images/primal_android.png b/src/assets/images/primal_android.png new file mode 100644 index 0000000..1cf8f91 Binary files /dev/null and b/src/assets/images/primal_android.png differ diff --git a/src/assets/images/primal_android_light.png b/src/assets/images/primal_android_light.png new file mode 100644 index 0000000..2967c7e Binary files /dev/null and b/src/assets/images/primal_android_light.png differ diff --git a/src/assets/images/primal_android_reflection.png b/src/assets/images/primal_android_reflection.png new file mode 100644 index 0000000..4045438 Binary files /dev/null and b/src/assets/images/primal_android_reflection.png differ diff --git a/src/assets/images/primal_android_reflection_light.png b/src/assets/images/primal_android_reflection_light.png new file mode 100644 index 0000000..d7054f8 Binary files /dev/null and b/src/assets/images/primal_android_reflection_light.png differ diff --git a/src/assets/images/primal_iphone.png b/src/assets/images/primal_iphone.png new file mode 100644 index 0000000..e4362d8 Binary files /dev/null and b/src/assets/images/primal_iphone.png differ diff --git a/src/assets/images/primal_iphone_light.png b/src/assets/images/primal_iphone_light.png new file mode 100644 index 0000000..f1976a2 Binary files /dev/null and b/src/assets/images/primal_iphone_light.png differ diff --git a/src/assets/images/primal_iphone_reflection.png b/src/assets/images/primal_iphone_reflection.png new file mode 100644 index 0000000..f01f0de Binary files /dev/null and b/src/assets/images/primal_iphone_reflection.png differ diff --git a/src/assets/images/primal_iphone_reflection_light.png b/src/assets/images/primal_iphone_reflection_light.png new file mode 100644 index 0000000..7acd5cd Binary files /dev/null and b/src/assets/images/primal_iphone_reflection_light.png differ diff --git a/src/components/NavMenu/NavMenu.tsx b/src/components/NavMenu/NavMenu.tsx index 66d2043..37bdd8a 100644 --- a/src/components/NavMenu/NavMenu.tsx +++ b/src/components/NavMenu/NavMenu.tsx @@ -44,6 +44,7 @@ const NavMenu: Component = () => { to: '/downloads', label: intl.formatMessage(t.downloads), icon: 'downloadIcon', + bubble: () => notifications?.downloadsCount || 0, }, { to: '/settings', diff --git a/src/constants.ts b/src/constants.ts index b5c860b..6d3dcbe 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -249,3 +249,6 @@ export const defaultNotificationSettings: Record = { }; export const emojiSearchLimit = 1; + +export const today = (new Date()).getTime(); +export const iosRD = (new Date('07/11/2023')).getTime(); diff --git a/src/contexts/NotificationsContext.tsx b/src/contexts/NotificationsContext.tsx index 9d3a9fc..5100a08 100644 --- a/src/contexts/NotificationsContext.tsx +++ b/src/contexts/NotificationsContext.tsx @@ -1,8 +1,9 @@ import { createStore } from "solid-js/store"; -import { Kind } from "../constants"; +import { andRD, iosRD, Kind, today } from "../constants"; import { createContext, createEffect, + createSignal, onCleanup, useContext } from "solid-js"; @@ -23,15 +24,16 @@ import { useAccountContext } from "./AccountContext"; export type NotificationsContextStore = { notificationCount: number, + downloadsCount: number, actions: { } } export const initialData = { notificationCount: 0, + downloadsCount: 0, }; - export const NotificationsContext = createContext(); export const NotificationsProvider = (props: { children: ContextChildren }) => { @@ -51,6 +53,20 @@ export const NotificationsProvider = (props: { children: ContextChildren }) => { subscribeToNotificationStats(account?.publicKey, subid); } + const calculateDownloadCount = () => { + const iosDownload = localStorage.getItem('iosDownload'); + const andDownload = localStorage.getItem('andDownload'); + + let count = 0; + + if (!iosDownload && today > iosRD) { + count++; + } + + updateStore('downloadsCount', () => count); + + }; + // SOCKET HANDLERS ------------------------------ const onMessage = (event: MessageEvent) => { @@ -73,6 +89,8 @@ export const NotificationsProvider = (props: { children: ContextChildren }) => { updateStore('notificationCount', () => sum) } + calculateDownloadCount(); + } } }; @@ -103,6 +121,8 @@ export const NotificationsProvider = (props: { children: ContextChildren }) => { } }); + createEffect(() => {}); + onCleanup(() => { removeSocketListeners( socket(), diff --git a/src/pages/Downloads.module.scss b/src/pages/Downloads.module.scss index e69de29..b09eb75 100644 --- a/src/pages/Downloads.module.scss +++ b/src/pages/Downloads.module.scss @@ -0,0 +1,208 @@ +.fullHeader { + display: grid; + height: 128px; + align-items: center; + justify-content: left; + + >div { + font-weight: 300; + font-size: 32px; + line-height: 34px; + color: var(--brand-text); + text-transform: lowercase; + } +} + +.callToAction { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + .ctaTitle { + color: var(--text-primary); + text-align: center; + font-size: 36px; + font-weight: 600; + line-height: 36px; + margin-bottom: 8px; + } + + .ctaDescription { + color: var(--text-secondary-2); + text-align: center; + font-size: 16px; + font-weight: 400; + line-height: 24px; + max-width: 430px; + } +} + +.promoHolder { + position: relative; + height: 560px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-top: 24px; + + .phones { + z-index: 10; + } + + .phoneReflections { + margin-top: -27px; + + >img:last-child { + margin-left: 44px; + } + } + + .backdrop { + position: absolute; + top: 24px; + width: 563px; + height: 496px; + border-radius: 563px; + background: linear-gradient(161deg, rgba(255, 159, 47, 0.30) 0%, rgba(250, 67, 67, 0.30) 27.67%, rgba(188, 24, 112, 0.30) 60.59%, rgba(91, 18, 164, 0.30) 85.21%); + filter: blur(60px); + } + + .backdropLight { + position: absolute; + top: 24px; + width: 563px; + height: 496px; + border-radius: 563px; + background: rgba(0, 0, 0, 0.12); + filter: blur(60px); + } +} + +.linkHolder { + display: flex; + justify-content: center; + align-items: center; + margin-top: -27px; + + >div { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 290px; + + &:last-child { + width: 279px; + } + } + + div { + color: var(--text-primary); + text-align: center; + font-size: 18px; + font-weight: 400; + line-height: 20px; + } + + + .appStore { + >a { + margin-top: 16px; + width: 120px; + height: 40px; + } + } + + .playStore { + >a { + margin-top: 16px; + width: 134px; + height: 40px; + } + } +} + +.downloadsSidebar { + .title { + color: var(--text-secondary-2); + font-size: 18px; + font-weight: 800; + line-height: 20px; + text-transform: uppercase; + margin-bottom: 20px; + } + + .list { + >div { + display: flex; + align-items: center; + + .githubIcon { + width: 24px; + height: 24px; + display: inline-block; + margin-right: 9px; + background-image: url( '../assets/icons/github.svg'); + background-size: contain; + } + + .githubIconLight { + width: 24px; + height: 24px; + display: inline-block; + margin-right: 9px; + background-image: url( '../assets/icons/github_light.svg'); + background-size: contain; + } + + + >a { + color: var(--text-secondary-2); + font-size: 16px; + font-weight: 400; + line-height: 40px; + } + } + } +} + +@media only screen and (max-width: 720px) { + .promoHolder { + display: none; + } + + .linkHolder { + margin-top: 20px; + flex-direction: column; + + >div { + > div { + display: none; + } + + >a { + >img { + max-width: none; + width: 188px; + height: 63px; + } + } + + width: 100%; + margin-bottom: 20px; + } + + .appStore { + >a { + width: 188px; + height: 63px; + } + } + + .playStore { + display: none; + } + } +} diff --git a/src/pages/Downloads.tsx b/src/pages/Downloads.tsx index 6a5b412..ea4b761 100644 --- a/src/pages/Downloads.tsx +++ b/src/pages/Downloads.tsx @@ -1,13 +1,155 @@ -import { Component } from 'solid-js'; -import MissingPage from '../components/MissingPage/MissingPage'; +import { Component, onMount, Show } from 'solid-js'; +import Branding from '../components/Branding/Branding'; +import Wormhole from '../components/Wormhole/Wormhole'; +import Search from '../components/Search/Search'; +import iphone from '../assets/images/primal_iphone.png'; +import android from '../assets/images/primal_android.png'; +import iphoneReflection from '../assets/images/primal_iphone_reflection.png'; +import androidReflection from '../assets/images/primal_android_reflection.png'; + +import iphoneLight from '../assets/images/primal_iphone_light.png'; +import androidLight from '../assets/images/primal_android_light.png'; +import iphoneReflectionLight from '../assets/images/primal_iphone_reflection_light.png'; +import androidReflectionLight from '../assets/images/primal_android_reflection_light.png'; + +import appStore from '../assets/images/appstore_download.svg'; +import playStore from '../assets/images/playstore_download.svg'; + +import styles from './Downloads.module.scss'; +import { downloads as t } from '../translations'; +import { useIntl } from '@cookbook/solid-intl'; +import StickySidebar from '../components/StickySidebar/StickySidebar'; +import { useSettingsContext } from '../contexts/SettingsContext'; +import { iosRD, today } from '../constants'; const Downloads: Component = () => { + const intl = useIntl(); + const settings = useSettingsContext(); + + onMount(() => { + if (today > iosRD) { + localStorage.setItem('iosDownload', 'seen'); + } + }); + return ( - <> - - +
+ + + + + + + + + + + +
+ + + +
+
+ {intl.formatMessage(t.title)} +
+
+ +
+
+ {intl.formatMessage(t.callToActionTitle)} +
+
+ {intl.formatMessage(t.callToActionDescription)} +
+
+ + +
+ + +
+
+
+ + +
+ + } + > +
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
{intl.formatMessage(t.appStoreCaption)}
+ + + +
+
+
{intl.formatMessage(t.playStoreCaption)}
+ + + +
+
+ ); } diff --git a/src/translations.ts b/src/translations.ts index 307affb..403c391 100644 --- a/src/translations.ts +++ b/src/translations.ts @@ -79,6 +79,46 @@ export const branding = { description: 'Brand name', }; +export const downloads = { + title: { + id: 'downloads.title', + defaultMessage: 'Downloads', + description: 'Title of the downloads page', + }, + callToActionTitle: { + id: 'downloads.ctaTitle', + defaultMessage: 'Primal iOS TestFlight is Here!', + description: 'Title for the downloads\' page call-to-action', + }, + callToActionDescription: { + id: 'downloads.ctaDescription', + defaultMessage: 'The app features easy onboarding, fast & snappy UI, ability to explore Nostr, and create & manage custom feeds', + description: 'Description for the downloads\' page call-to-action', + }, + appStoreCaption: { + id: 'downloads.appStoreCaption', + defaultMessage: 'TestFlight Available Now', + description: 'AppStore promo caption', + }, + playStoreCaption: { + id: 'downloads.playStoreCaption', + defaultMessage: 'Coming soon to Android', + description: 'PlayStore promo caption', + }, + links: { + webApp: { + id: 'downloads.webAppLink', + defaultMessage: 'Primal Web App', + description: 'Label for the link to the web app', + }, + cachingService: { + id: 'downloads.cachingService', + defaultMessage: 'Primal Caching Service', + description: 'Label for the link to the caching service', + }, + }, +}; + export const exploreSidebarCaption = { id: 'explore.sidebar.caption', defaultMessage: 'trending users',