From c43fd75aff360e6c2f50579f724f0829664ccd03 Mon Sep 17 00:00:00 2001 From: Mihir Wadekar Date: Thu, 22 Feb 2024 15:14:23 -0800 Subject: [PATCH] Added manifest.json, works with no navbar for PWA (#6640) * Added manifest.json, works on iOS with no navbar for PWA * Added working ios prompt * Some css additions * Fixed some scss errors and flushed out android testing + design accurate component * Added fixes suggested by Marcin (some outstanding) * Added correct common svg * Added new png asset for manifest instead of svg * Added icon from phosphorous and resolved some scss issues * Small .scss fixes * extracted magic strings to a const * no prompt on marketing page * Addressed latest round of fixes suggested by Marcin * Addressed more comments + fixed cancel button that broke last commit * Removed console logs * Fix for icons and background color * Removed OG icon from add to homescreen prompt * Growl now behind prompt * Opening to dashboard * Changed copy * Adding a delay for loading prompt * Removed ternary * Reset back to ternary --------- Co-authored-by: Marcin --- packages/commonwealth/client/index.html | 11 +- packages/commonwealth/client/scripts/App.tsx | 33 ++++- .../client/scripts/hooks/useAppStatus.ts | 19 +++ .../AddToHomeScreenPrompt.tsx | 55 ++++++++ .../AndroidPrompt/AndroidPrompt.scss | 117 ++++++++++++++++++ .../AndroidPrompt/AndroidPrompt.tsx | 100 +++++++++++++++ .../AndroidPrompt/index.ts | 1 + .../IOSPrompt/IOSPrompt.scss | 98 +++++++++++++++ .../IOSPrompt/IOSPrompt.tsx | 49 ++++++++ .../AddToHomeScreenPrompt/IOSPrompt/index.ts | 1 + .../AddToHomeScreenPrompt/constants.ts | 3 + .../AddToHomeScreenPrompt/index.tsx | 1 + .../component_kit/cw_icons/cw_icon_lookup.ts | 2 + .../AccountConnectionIndicator.tsx | 2 +- .../commonwealth/client/styles/shared.scss | 1 + .../static/img/branding/common-white.png | Bin 0 -> 14786 bytes .../static/img/branding/common.png | Bin 0 -> 9239 bytes .../static/img/branding/common.svg | 15 +++ packages/commonwealth/static/manifest.json | 18 +++ 19 files changed, 520 insertions(+), 6 deletions(-) create mode 100644 packages/commonwealth/client/scripts/hooks/useAppStatus.ts create mode 100644 packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AddToHomeScreenPrompt.tsx create mode 100644 packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/AndroidPrompt.scss create mode 100644 packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/AndroidPrompt.tsx create mode 100644 packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/index.ts create mode 100644 packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/IOSPrompt.scss create mode 100644 packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/IOSPrompt.tsx create mode 100644 packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/index.ts create mode 100644 packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/constants.ts create mode 100644 packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/index.tsx create mode 100644 packages/commonwealth/static/img/branding/common-white.png create mode 100644 packages/commonwealth/static/img/branding/common.png create mode 100644 packages/commonwealth/static/img/branding/common.svg create mode 100644 packages/commonwealth/static/manifest.json diff --git a/packages/commonwealth/client/index.html b/packages/commonwealth/client/index.html index e1ab39a9add..2179f9d159a 100644 --- a/packages/commonwealth/client/index.html +++ b/packages/commonwealth/client/index.html @@ -17,7 +17,12 @@ sizes="64x64" href="/static/brand_assets/64x64.png" /> - + + @@ -46,7 +51,7 @@ /> diff --git a/packages/commonwealth/client/scripts/App.tsx b/packages/commonwealth/client/scripts/App.tsx index 5e8874a3326..f07ccbdce76 100644 --- a/packages/commonwealth/client/scripts/App.tsx +++ b/packages/commonwealth/client/scripts/App.tsx @@ -4,11 +4,14 @@ import { QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import useInitApp from 'hooks/useInitApp'; import router from 'navigation/Router'; -import React, { StrictMode } from 'react'; +import React, { StrictMode, useEffect, useState } from 'react'; import { RouterProvider } from 'react-router-dom'; import { ToastContainer } from 'react-toastify'; import { queryClient } from 'state/api/config'; import { openFeatureProvider } from './helpers/feature-flags'; +import useAppStatus from './hooks/useAppStatus'; +import { AddToHomeScreenPrompt } from './views/components/AddToHomeScreenPrompt'; + import CWLoadingSpinner from './views/components/component_kit/new_designs/CWLoadingSpinner'; const Splash = () => { @@ -24,6 +27,26 @@ OpenFeature.setProvider(openFeatureProvider); const App = () => { const { customDomain, isLoading } = useInitApp(); + const { isAddedToHomeScreen, isMarketingPage, isIOS, isAndroid } = + useAppStatus(); + + const [showPrompt, setShowPrompt] = useState(false); + const [isSplashUnloaded, setIsSplashUnloaded] = useState(false); + + useEffect(() => { + if (!isLoading) { + // Delay the unloading of the Splash component + setTimeout(() => { + setIsSplashUnloaded(true); + }, 1000); // Adjust the delay as needed + } + }, [isLoading]); + + useEffect(() => { + if (isSplashUnloaded) { + setShowPrompt(true); + } + }, [isSplashUnloaded]); return ( @@ -32,8 +55,14 @@ const App = () => { {isLoading ? ( ) : ( - + <> + + {isAddedToHomeScreen || isMarketingPage || !showPrompt ? null : ( + + )} + )} + diff --git a/packages/commonwealth/client/scripts/hooks/useAppStatus.ts b/packages/commonwealth/client/scripts/hooks/useAppStatus.ts new file mode 100644 index 00000000000..72de0c522c7 --- /dev/null +++ b/packages/commonwealth/client/scripts/hooks/useAppStatus.ts @@ -0,0 +1,19 @@ +const useAppStatus = () => { + const isAddedToHomeScreen = window.matchMedia( + '(display-mode: standalone)', + ).matches; + const isMarketingPage = window.location.pathname === '/'; + const isIOS = window.navigator.userAgent.match(/(iPad|iPhone|iPod)/g) + ? true + : false; + const isAndroid = window.navigator.userAgent.match(/Android/g) ? true : false; + + return { + isAddedToHomeScreen, + isMarketingPage, + isIOS, + isAndroid, + }; +}; + +export default useAppStatus; diff --git a/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AddToHomeScreenPrompt.tsx b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AddToHomeScreenPrompt.tsx new file mode 100644 index 00000000000..c63ed6ed045 --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AddToHomeScreenPrompt.tsx @@ -0,0 +1,55 @@ +import React, { useEffect, useState } from 'react'; +import { AndroidPrompt } from './AndroidPrompt'; +import { IOSPrompt } from './IOSPrompt'; +import { HIDE_PROMPT, HIDE_PROMPT_DAYS, HIDE_PROMPT_TIME } from './constants'; + +interface AddToHomeScreenPromptProps { + isIOS: boolean; + isAndroid: boolean; +} + +export const AddToHomeScreenPrompt = ({ + isIOS, + isAndroid, +}: AddToHomeScreenPromptProps) => { + const [showPrompt, setShowPrompt] = useState(true); + + useEffect(() => { + const hidePromptTime = localStorage.getItem(HIDE_PROMPT_TIME); + if (hidePromptTime && new Date().getTime() < Number(hidePromptTime)) { + setShowPrompt(false); + } + + if (sessionStorage.getItem(HIDE_PROMPT)) { + setShowPrompt(false); + } + }, [showPrompt]); + + const hidePromptForNDays = () => { + const maxDays = 30; + + let n = Number(localStorage.getItem(HIDE_PROMPT_DAYS)) || 1; + n = n * 2 > maxDays ? maxDays : n * 2; + const hideUntil = new Date().getTime() + n * 24; //* 60 * 60 * 1000; + localStorage.setItem(HIDE_PROMPT_TIME, hideUntil.toString()); + localStorage.setItem(HIDE_PROMPT_DAYS, n.toString()); + + setShowPrompt(false); + }; + + return showPrompt ? ( + isIOS ? ( + + ) : isAndroid ? ( + + ) : null + ) : null; +}; diff --git a/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/AndroidPrompt.scss b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/AndroidPrompt.scss new file mode 100644 index 00000000000..c0fccf595e5 --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/AndroidPrompt.scss @@ -0,0 +1,117 @@ +@import '../../../../../styles/shared'; + +.AndroidPrompt { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + position: fixed; + bottom: 0; + left: 0; + width: 100%; + background-color: rgba(0, 0, 0, 0.5); + z-index: 1002; + + .header { + display: flex; + align-items: center; + padding-top: 8px; + + .icon { + margin-right: 16px; + } + } + + .app { + .app-name { + color: $neutral-900; + text-align: center; + font-variant-numeric: lining-nums tabular-nums; + font-family: $font-family-roboto; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.16px; + } + .app-url { + color: $neutral-500; + text-align: center; + font-variant-numeric: lining-nums tabular-nums; + font-family: $font-family-roboto; + font-size: 12px; + font-style: normal; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.24px; + } + } + + .button-container { + display: flex; + justify-content: flex-end; + gap: 32px; + } + + .prompt-button { + color: $primary-500; + text-align: right; + font-variant-numeric: lining-nums tabular-nums; + font-family: 'Roboto'; + font-size: 16px; + font-style: normal; + font-weight: 500; + line-height: 24px; + letter-spacing: 0.16px; + background-color: $white; + padding: 0px; + margin: 0px; + } + + .prompt-content { + background-color: $white; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); + padding: 8px 24px 8px; + border-radius: 26px; + margin-left: 18px; + margin-right: 18px; + + .title { + font-family: $font-family-roboto; + font-size: 24px; + font-style: normal; + font-weight: 400; + line-height: 24px; + letter-spacing: -0.24px; + color: $neutral-900; + padding: 24px 0px 8px; + } + + .description { + margin-top: 16px; + align-self: stretch; + color: $neutral-900; + font-variant-numeric: lining-nums tabular-nums; + font-family: $font-family-roboto; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.16px; + } + + .hide-prompt { + flex: 1 0 0; + margin-top: 16px; + color: $neutral-900; + font-variant-numeric: lining-nums tabular-nums; + font-family: $font-family-roboto !important; + font-size: 16px !important; + font-style: normal; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.16px; + } + } +} diff --git a/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/AndroidPrompt.tsx b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/AndroidPrompt.tsx new file mode 100644 index 00000000000..d5996de77d4 --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/AndroidPrompt.tsx @@ -0,0 +1,100 @@ +import React, { useState } from 'react'; +import { CWCheckbox } from '../../component_kit/cw_checkbox'; +import { CWText } from '../../component_kit/cw_text'; +import { CWButton } from '../../component_kit/new_designs/cw_button'; +import { HIDE_PROMPT } from '../constants'; +import './AndroidPrompt.scss'; + +interface AndroidPromptProps { + hidePromptAction: () => void; + showPrompt: boolean; + setShowPrompt: (showPrompt: boolean) => void; +} + +export const AndroidPrompt = ({ + hidePromptAction, + showPrompt, + setShowPrompt, +}: AndroidPromptProps) => { + let installPromptEvent = null; + const [checkboxChecked, setCheckboxChecked] = useState(false); + + window.addEventListener('beforeinstallprompt', (event) => { + // Prevent Chrome 67 and earlier from automatically showing the prompt + event.preventDefault(); + + installPromptEvent = event; + }); + + const handleInstallClick = () => { + installPromptEvent.prompt(); + + // Wait for the user to respond to the prompt + installPromptEvent.userChoice.then((choiceResult) => { + if (choiceResult.outcome === 'accepted') { + // Hide after install prompt is accepted + console.log('User accepted the install prompt'); + sessionStorage.setItem(HIDE_PROMPT, 'true'); + setShowPrompt(false); + } else { + // Hide after install prompt is dismissed + sessionStorage.setItem(HIDE_PROMPT, 'true'); + setShowPrompt(false); + } + }); + }; + + const handleCancelClick = () => { + // Hide the prompt for the rest of the session + sessionStorage.setItem(HIDE_PROMPT, 'true'); + setShowPrompt(false); + // If the checkbox is checked, hide the prompt for N days + if (checkboxChecked) { + hidePromptAction(); + } + }; + + const handleCheckboxChange = (event) => { + setCheckboxChecked(event.target.checked); + }; + + return ( +
+
+ Install App +
+
+ Commonwealth +
+
+ Common + common.xyz +
+
+ + For the best mobile experience we recommend installing the Common + web-app. + + +
+ + +
+
+
+ ); +}; diff --git a/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/index.ts b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/index.ts new file mode 100644 index 00000000000..88c96618426 --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/AndroidPrompt/index.ts @@ -0,0 +1 @@ +export * from './AndroidPrompt'; diff --git a/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/IOSPrompt.scss b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/IOSPrompt.scss new file mode 100644 index 00000000000..7a0bb3caf4f --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/IOSPrompt.scss @@ -0,0 +1,98 @@ +@import '../../../../../styles/shared'; + +.IOSPrompt { + display: flex; + align-items: flex-end; + justify-content: center; + position: fixed; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + z-index: 1002; + margin: 0; + box-sizing: border-box; + + .header { + display: flex; + align-items: center; + border-bottom: 1px solid $neutral-200; + padding: 0px 16px 8px 16px; + gap: 16px; + align-self: stretch; + + .title { + color: $neutral-900; + font-family: $font-family-silka; + font-size: 18px; + font-style: normal; + font-weight: 500; + line-height: 24px; + letter-spacing: -0.18px; + } + } + + .prompt-content { + background-color: $white; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); + padding: 16px; + border-radius: 6px; + + .description { + margin-top: 16px; + color: $neutral-500; + font-variant-numeric: lining-nums tabular-nums; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.14px; + flex: 1 0 0; + } + + .instructions { + margin-top: 16px; + + .instruction { + display: flex; + margin: 8px 0px; + font-size: 14px; + color: $neutral-900; + font-variant-numeric: lining-nums tabular-nums; + font-family: $font-family-neue-haas-unica; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.14px; + align-items: flex-start; + gap: 3px; + align-self: stretch; + + .share-icon { + color: $primary-500; + } + } + } + + .hide-prompt { + font-variant-numeric: lining-nums tabular-nums; + font-size: 14px !important; + font-family: $font-family-neue-haas-unica !important; + font-style: normal; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.14px; + } + + .highlight { + background: $neutral-50; + padding-left: 8px; + padding-right: 8px; + color: $neutral-600; + } + } +} diff --git a/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/IOSPrompt.tsx b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/IOSPrompt.tsx new file mode 100644 index 00000000000..31dd9ff7974 --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/IOSPrompt.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { CWIcon } from '../../component_kit/cw_icons/cw_icon'; +import { CWText } from '../../component_kit/cw_text'; +import { CWButton } from '../../component_kit/new_designs/cw_button'; +import './IOSPrompt.scss'; + +interface IOSPromptProps { + hidePromptAction: () => void; + showPrompt: boolean; + setShowPrompt: (showPrompt: boolean) => void; +} + +export const IOSPrompt = ({ + hidePromptAction, + showPrompt, + setShowPrompt, +}: IOSPromptProps) => { + return ( +
+
+
+
+ Commonwealth +
+ Add to Home Screen +
+ + For the best mobile experience we recommend installing the Common + web-app. + +
+ + 1. Tap the share {' '} + icon + + + 2. Select Add to Home Screen + +
+ hidePromptAction()} + /> +
+
+ ); +}; diff --git a/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/index.ts b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/index.ts new file mode 100644 index 00000000000..c34e0691147 --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/IOSPrompt/index.ts @@ -0,0 +1 @@ +export * from './IOSPrompt'; diff --git a/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/constants.ts b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/constants.ts new file mode 100644 index 00000000000..8a7b181e475 --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/constants.ts @@ -0,0 +1,3 @@ +export const HIDE_PROMPT_TIME = 'hidePromptTime'; +export const HIDE_PROMPT_DAYS = 'hidePromptDays'; +export const HIDE_PROMPT = 'hidePrompt'; diff --git a/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/index.tsx b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/index.tsx new file mode 100644 index 00000000000..fa545fd7fc4 --- /dev/null +++ b/packages/commonwealth/client/scripts/views/components/AddToHomeScreenPrompt/index.tsx @@ -0,0 +1 @@ +export * from './AddToHomeScreenPrompt'; diff --git a/packages/commonwealth/client/scripts/views/components/component_kit/cw_icons/cw_icon_lookup.ts b/packages/commonwealth/client/scripts/views/components/component_kit/cw_icons/cw_icon_lookup.ts index f4b438acf02..dea2ddcf325 100644 --- a/packages/commonwealth/client/scripts/views/components/component_kit/cw_icons/cw_icon_lookup.ts +++ b/packages/commonwealth/client/scripts/views/components/component_kit/cw_icons/cw_icon_lookup.ts @@ -26,6 +26,7 @@ import { ClockCounterClockwise, Code, Compass, + Export, Eye, Flag, Heart, @@ -77,6 +78,7 @@ export const iconLookup = { keyLockOpened: withPhosphorIcon(LockKeyOpen), keyLockClosed: withPhosphorIcon(LockKey), eye: withPhosphorIcon(Eye), + export: withPhosphorIcon(Export), archiveTray: withPhosphorIcon(ArchiveTray), arrowLeft: Icons.CWArrowLeft, arrowRight: Icons.CWArrowRight, diff --git a/packages/commonwealth/client/scripts/views/components/sidebar/AccountConnectionIndicator/AccountConnectionIndicator.tsx b/packages/commonwealth/client/scripts/views/components/sidebar/AccountConnectionIndicator/AccountConnectionIndicator.tsx index 1677d1a215d..36ac578522c 100644 --- a/packages/commonwealth/client/scripts/views/components/sidebar/AccountConnectionIndicator/AccountConnectionIndicator.tsx +++ b/packages/commonwealth/client/scripts/views/components/sidebar/AccountConnectionIndicator/AccountConnectionIndicator.tsx @@ -3,8 +3,8 @@ import React from 'react'; import { CWText } from 'views/components/component_kit/cw_text'; import { CWIdentificationTag } from 'views/components/component_kit/new_designs/CWIdentificationTag'; -import { CWButton } from 'views/components/component_kit/new_designs/cw_button'; import useJoinCommunity from 'views/components/SublayoutHeader/useJoinCommunity'; +import { CWButton } from 'views/components/component_kit/new_designs/cw_button'; import './AccountConnectionIndicator.scss'; interface AccountConnectionIndicatorProps { diff --git a/packages/commonwealth/client/styles/shared.scss b/packages/commonwealth/client/styles/shared.scss index dd60ac5bd55..c04f0df6a92 100644 --- a/packages/commonwealth/client/styles/shared.scss +++ b/packages/commonwealth/client/styles/shared.scss @@ -33,6 +33,7 @@ $font-family-neue-haas-unica: NeueHaasUnica, 'Segoe UI', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; $font-family-monospace: 'DM Mono', monospace; +$font-family-roboto: 'Roboto', sans-serif; @mixin visibleScrollbar($theme) { &::-webkit-scrollbar { diff --git a/packages/commonwealth/static/img/branding/common-white.png b/packages/commonwealth/static/img/branding/common-white.png new file mode 100644 index 0000000000000000000000000000000000000000..1867903138fc4f2015b5fca902ddeecfa4fd790a GIT binary patch literal 14786 zcmYMbcRbwB^8ozTqb4B|qDMPK?-D_ja7xZ`qLV0b1ks}eAtAbOdb{9=<0R2eFA)-* z(|hzzLJ<9V`+T3@^Zaoy-n+9ivoo`^yR$P9Fug~#RJW-B0HD>rD!M8F@HLM5^eGtt$Uo6i zQ!#u+v^DJ-ZMW~s|E~~G4SiEu6+c+QX??`IWs7u{$`Wcuxbb4YR(z)9mtVp6zW>w{8`O zx6Ng2_c`y$pXp|Q7P)&@XZM1E zw(6QxZ*B8nly(ab$D@z-XFs_4u8IQDg&Zm2#RHQoVR0KuGq=8^KY|H%i;?bQodn3A zuH?1;7?^AT&>hEa0?JDZha(M-Qw5{ZQv3+c^)}Aa#RayFY$sJBPcw2%(%eFM>k2d4 zC}e^XDp^(f&=W#>2RN{|dxazWBzRw#LXsDvJ1)k=7OMhLxDjei3Y3?zhW`F*Nb}7= zDfPArGA^tI(%Ro3enqnZ2tMlQuQ0cG+|DVN<~u>6g1i+rx2j3=ZNTB@Z2$`P@bBqY zBHcp>sWNZ#REdC|a@L1~YNQx8L!vd<{_mGp9sw0yMe7PCWCaE-$)p%vn&L-SjYbFh zjY!bb$HQKC$Uhcwm}|gHpBpRIDv=Az0ITT?!~36_JtNRJCY*pTEfGwHsmXZ@3T!A+ z9$;)FV)fO#qC^$stCRR2&%PX90mfz`RvoO@4Pg@bw1B^RNo}l;fS4B_1i>XhLg41& zBx<(&YXh@TxX#vpjJBnt1nhIIEDkFgYCY8}46DYmLM!ol;qj!v;7D<)SYaJktDTUD9dSuVI1_J<02bS?PE703aaLB5Bss`5uO+KC{6%qU%fW#m}W;QHJcE^ zOZJXt89>TR>2}3H-E|yZkO#Lfr>aRDT(Hq*?Sd4zjsAx=JX4?Hct{UaXo->wk#5I* zV`M{xgz4s41|kUI^-)>+x6j)Y=>g?Q#j-D7emmUw^b;*LRqOW9Mx%-dW7CM+!wPwZ@A578f2#q24&Tnn@pm!pp@OPN_&!CKlC@ES z9})27-r0I>Irc72gLb_HvQ(OH2>_dxqU340H!DdobCmd25XL8b!<0pAZ^Ue$q9fQ= zgc3-tV%@fkWll%JZqu1((Fw}}*2nI80xLJUe8Ov5*X?I0-21OwIREn^CY?L62=({!VcO5ndvQ1sLFVWnksJ*&v_r?D+BZdN0KG2Ec z-#s)$On9kx0J1gEgx3RhT>7;;Ecj*Y(X4U`x z?K@H@Gkhb~ zTgqjl2izIZy6p<+Dw~a-YaqMudvsoL2Kov&0AS0*w(v0%KLlAv1UP%{=;eHI-q4+- z1srOeCtdG>ILQEIf41@M(0gRO&Y)a+s+^mg$Nh>YT%v|s#{t0M^NTvRDePI5g*s9I z049W~Rn6?Pw?YVWU|*B4WS_Un+V+3{uApSH^viAnz-p@QDCrA?zC;cw;Mq~Ig~x>u zK7!4$x>0IoWSD!z0Q#OxR?m#1#@aIg@a(EvM$I7fu@e6QWzV$xycqG5{7DOV4t$K+ z8M_NfdrS<}u39i_s#5~izbu$nEn26@YlwnlO)ZR#<-VM=rGPStzEp$f@ci#>9;NcH z`y`etZ0UHhM|&^JlV;Nw@l*jItn<{R*ibxwhArkQJDfno%2S1#I z>xtYuIw(hji;+h2If*rkkZ5LHAr>Y@rN*34=03y|PB#N1D{vYO8Df*Q61q>sa<-Z6 zx)BObPS2(c{z#+D9G!jI?zsQ2-Bixe6mt8=r(@4mo6#TBi1!MAzp@aoR@^H_S0p?h zp}@2bw=xiUPVD+vnH4iFE$pU^<`$Q&d;U9U6O^;~JWo2kr_6}bTTI+BUxLn9w8J*RWb9<-8c|BmTyN&I!I3%R)lhai{CyBUl~fazhoQ zFgNZj&MvY4#e|dHU~;I2shNU26*O7*Aqk~s&!xM(`UJuEhBDIU3l;QCAEscam`R7e zPMW{WkcxhF2qN&kfqJnNMt&`R;<;2SkC=+vNR>z2O}ztRNOJIyW!&jFwcGs0=kEiL zFU;@%6XKvj-+e;EflGP!aLN7Wy^GP6kw7$+))p$GDK79x>3d7isq5&?5MuS!rHd<2 z*r%jhGw=P+*YFFCO2@Hz=WHL|to^)o5_+-x{7g1n-mFU_g#HF!u|^GKw^!*^Z`se- zPQhnJDZ3j$YR1`-Qr=S+yyzR^MVT!MY-9)(J-7Vg*}tIa@+Fq_!^LmkzRd{{r`DC+ zQT)5KvXC8g;LH`#WlJs6Br-x=;mta(S44sN0DU4c=I@tr8qf5vzg4|1v!R18VLleyhDcM$&-)II=hcR77Q}c~NB&k>uW|ZG> zq9jpw_e2LK=vWvhW3M4ZXFreL2gGcAwIlCc;8))A*bBD43d~w6gIfDZK=z4KBkm6; z5u3WQVVT@&fSM2 zPr{sMzC1E@6;scPuh^YuA=<0joj)bdl-%$LHcdi=uRz7fyLgb2+5%6VLg+WGaf)0#1MZ=b zYd(fLPeW;-CnRG8l8Z7?o&ic<*Xr=bzZ}H>(n!K;p0dQ9k4L$!vlJ6qfL5wxc~VO; z!n7QQW4&1K`tviV;ab1+kynn@MKCk(m|-cA+_9bTm0F?Jgi0b#NK0Mx2%wx|!UB+l z(7%Z1>i8`~6NvosF1wTgWu3+P%)<9i3_zaTSHH}|nzcN{LbHVAXr27+^5gt;$@qNR ziHL280mVr!9QNo!iHovoxA|fiADy5_@C$|ZK26mQ!Qt54|E&uj&% zQfB!Nga)KT=(CcWcr&y^{wy6vB@uzgSGB^W9+x+NmNFCm_xaqetH+#PM~^yIvv_GG2uReJ)D-J7%s|Uyl<} znj-Z#V)TB#8DyO&w_h0YC?>B%@`6}jMl;)src^(iyaKJ5p(L4tQEw1CaH~X&l+yw0 zd04f}_H;-3A#FrN)peAE^f1q-94x)_9ms$wR!fWn3#|ZW=v2hla{5Vd;ARLt4%O6y z{r|r_Py4LstQ!rJ97sT%9sYVt$=245W!Odbmr_}1wTDygi3@_M}`NM zPvz39E>-SmI|yDj#V@KecYc_S<8La!s(DaCD>tU5(=;V7(vQwI@hscR5^{dmLJ+mVNTbCUg&xKriw@0K4PWRR0H2>iC{=hsWDevva z>XhlNheEpCkO2qZ$o6g$sqjHpsTj0cp1^|Y-u)w51aG=3EO+44o~oz(bb6E|9n|kv zaI-D5rN8a4)V623EER@Uvk|WIxgj-@*q24?K&%qc?nhW-cDTDG`yce(($Ho2^#TEq z9CE2mwwqril-8bRmIeaKjeAK9(*L4reUKDnbdl_4x~NbqOhF|=1Fj#kZ04&1%MG~f zkkxm1(Db|i63B){wn9}T%hNB3Kna!VEf1uAH}dL$ceW3u3(IvYAqzg}*C_P71O#qO za32b&bbxe!0Fa9Co##+~$N)tCbgguupWQ@%S5fz}uZ@z~A!nG{l>!BY&;HY5GD*=Gn zH533;aYBfI7b-Af>+OS`IzjZM;@zxglZYw?b9Y>+cp(E!Ck^q$FiDWAalH|eeFCZ; z0SC#1-GV!OZrcb5G62mC>>8mKs6e>>Ne`yK?2M!byg;5&GxNhl71}$&J5HS-D#(Ou z|APq^lny8rKZ<(v!^!`fvOKQ?2Tm5s2f|z)xRmQs74vODR?21xS`JxpjztDypukLO zmui6tb@hn<6H^Z6>Jiy{_cfb-h z?KpFe{C-cV;qU2IPV8Zyg;(3JTK9i){Mhd((4V-ut2gU}5FkLqE=~|=VEVI89g3Hv zS(-fhQ(v&u4j#E)zy2;QOY_i>{1Z!fTpoU{N_IB()frCZTJ7(HUt9R_zDGM5$u!!d z=3Zb}V(;}63%`J!7uXuTGB{|J?Iy?lm0ttwufE}J?cG59_FbC1u5>(tS^2C7V@nU~ zI^TKiyw`Ws%uhbIc9v6pD!-LLv^w=p`>Dg0t(^E7h#UyD!eE%Q{os|V@+H>iKhnbV#X4cAxWN}GNt_q= zm6*=Q&wHAf>P15h$O}S!sP!-%*ZwB%rF_$$PRdn?CZ4?-UhY3$+tn{sTScj-SFd0D zE-ERQ+@#^R9_zo;PK=N3%T*=mD|FA3CvQc2bB7LwV;u*7(9yCNJt5EK$Z0Z^Uax)K zdUN`ul;wUY3wzVQxPaGi8AjgQ{NYL|GZ%U#ndgZrV#h6`A+#F8btQ63)~~8o%O*U3 z!^B8Tq&t=W?rwwz521`qEk;beKU-nt?2M0VHWvB`x?_IiD0||>-tywmx>2Atp})fC+rT#MWW2VkA#DsxX`@=9=_&#N*e=b3YOy!`<7F7N!PCCR1u;UIsp zSW|@(`i4CUVi1=5`MwDvUXSJ*f&6TJWw7N*D6%81!0PxU6gnua$JL-so~ys)un-~Y zz196W;EvykOwk=XI{_gbpCIL=h#CeIM4LR{CeG4Gaia5$$Mxbyze1;>^b@nDg++6? zVtU$4(?G zx*m;j)-wTz|9r@`g`VmNLN|Lei#1u0P14PGi?y+uF=B&*E{Sl9XF4JDi5Y`;33{1< zPQfPKA`K>(#TCmchN731S>73HGm_h*fxVmblLSAT0OshxmB#md9Ks?z815$&7=N5& z)LF-D+&|fiI|X-yH2Xl>(#qmV`THWLo-Z$|>qX=kJC+SmOnn|gq46kT{6mnw&bGyI z(goLixo{iT=;Ro{FT-(u_;F?G8P-4UL&pO_W6r0nDi6>8fIR@4?8f^#NH+ z@1QDjdCy-BZpQ`<4sWeatiN0AP%{nq**J|`cD>mOdz-)b*Q_<#)NS^Z@G2)q_Ujp5 zlv0b<<3c!UfGNoI-EXC{r_Jvp=`*@+nt=qCMmW6%rN{IN=Xd$4^eUzGKB!JDRQpgw_~zzjEycP84g!C_d_ z!mojM7i}&$=SdDpdkCMBfW+#JX6p>utdF@vcH_^wK5pF%%g@ISDKo#2?d=Ub%rSJX z7NzLf{r$rw(#Y?4(>n1#P()t*P;;VlA`Iaej}IR;dT=^RBN90}2IBjJZU5m z+)qbnn(owwUT^xR`8{cec6~5nDWPt^X2x2aH>MzWNTctN8(e(9rpxvZ#wt~&%cf;E ztU7vgBL1C6pe?hEMQY4~PD9u6iW7*m0$L|BZ(jqL|#hQ}Llp;yZo0GqVel2geFEsbfCcIS2KS3&0E|+8b z_ljTk`LT0bS@lQm!(k^WEuO-SE0Hd)zhkY})HzcMs zE@rMbAo=F6Hs<1Jq^FSi@qmMYA~ZfGwWDt%)h_Zext#YYhFNjj<4U(>CT~BhJX-> z_s1a+$XBV_oVj_dgg8}Ph$ONwcSvn}LB^m)0=;t2CV&?|CDVD*f^3NqUP%B!zAC+z zhh%V2=q46URZQ7;))Pq6``srYqhxYqvNu~NrH!3h8tB2BhhqYb<_~sCd)Kwj_diN$ zy?2eI`tAiuSGQ44`fc8FxtXw@utDtpgI=8;m9Ex>Gm;;3uJ&iCF)S-$i1nq~PFk|| zkgs>Pg2#;LwKOn+mkGy6(QGCfH-q95LAC?!{W|HdOH~7h>>P$E)!k?KyY1W*u2hc6 zQINe{xez!*eXT;O?lTeh>U(BxC4>1y+c;ZIcmKq$yVGApV_(lFTkB0xmuiB50dv(v z+wz?m%gZnEi7!=|cgO?ys+sME}-w$YX+*4)`#C*z^@hrqqAN zdmj5eMe0s^>o9M6`zItUTH~>B{rb%my)GP6UL}#q)Af>oGZ$@XBo9TM)rrpl;vxJg z7}*)KxS>*H3qA^PxkP>_hnkqIzc6;(pj?g>`Dh-{$LO>r!&M~qIHyts%^3pkFieab z8vio1=mp$cvqlK0!i^G=OMNI#?wH(y(Wn#|VztyaY>gdH&UO?G5%dYSn`?ugU4dfY zx`LL4-{2X=THI_!g5ah!Kf<>8Tz#=@_YV(5$bq&p#Z zE4{sxZ(+5#g-Zov^zh)Qz0DfyMp6vn6Q4A^xE227vajS4U6p$;Wwks53YwQbWQ;S1 zruiqX|%S9WMvyep$W20 z7-{x8nfW=sxVN5_=~BCdl)NJLlXn>lWBe|3ri(}wq$Mc^Zrden=33FoeR4Y>sJisY zu_Q#g1S=(XJ{y(C;TzO1VS*?Vv=#vY1OC|d>xIusIJhUoMWGD|VND`-z)?-nME$MVK1$Qs0)_W>`YuW>(p}su)lcu6V(6Cx3en?U? zG+6KF!Q{dyt$j-5$P(9fjQgjPo|HVpaYvROZsv*YE2`6#dsztL;e5T0!I#fn?p8C7 z?t@^KCb9G}rq0VB6xv}vTcjA@u6Wz`bsiEtcE*D4?}8l(OH}vI3Wi6X{zs=LgKJx_ zOU7J(vc9f5!k^zsb=vO5I{S<9ZDgg_G~V*+`ocZunY(G5^{P*3zrnAE&V*IV`W%Qp zn<HJjM>5u z^t|9W8lymb7|T2`a}J>B)z0=F^tNFc59ylBvDGe3_Rg%DJm@{&NUhY*5EkX17)u7> zz*)OZ#E37&`xvFz-%hQV_D+uC?>n@)sS(B97jVol@gn;13GQYHq25@c z&v`!;)%Pzz} z`J)j|IcIHkq{K?!=0AbU+sh&;i)4xx1=UQ#@b3 ziQrQ~O8D*yo4tHu$sXdqGjQn+2jT*h_uu>3oj4JmMmvZpbX<9Xb&9L7$ci`d0wl>#JF*;I;LMu^28?g2&F*F;4VJSr@K0DtuNEc8k(v#1~-`C*Uec&Em{3Q5C@yL`r!bIUn zZ{OJB^~W^}30AfmiTRmzQ*5@V<*D~uDtZjlmcaynMPCToke@4pK;!z>e>Jj&5%J2j zM(&E0a@9yxn4%h|$?Fr7U_x!kCZgop12W?oml1&R~ZyWo2?!ru! zj17MIx3guEIX(M$?U&n9;ns`6n2>?#C+1WdQPh*CB%jYY=X;)Tm)3}*uY?e~uRy)Z zK4c_B%l}lw$|&9sxF@8?oSJ>MhFQ_2ddwW`M;)p($kwW4=KA#3MQ(}U^l=xF`l}A* z!xC_y#7|u__D)wb>Zt&Sr1Dbc;Dq!K125kR(PFhI@hfT#O!W=LunK0C zh=kMM4=+`a)eX^45O7(r%$VyC)NOQITH;`NS3mg=$*vYdn%%kYRPrTq)_wE9W(6S>NjO&t#}W;1-#$@_5WLU)d1nCAz{Qsg1TSC4MV(3iW+s&9naa zp|bc?r!607SgHECpwk}wv%W{v_DWUh_09jc&GK=fDj4)KzAnZ9qN|vJL_`ui7c=Qm z-=YaRpgi=!aUe`;z$@Rg>^tqxghn1mh% zgNF{(l28MF5abhtC|VbW4SnhYIPj=YT8mx^SC-b}aRwN1bp8{z4}h5d7hL>b6w=vk zE2+hk5(@ac^~4ahRkz3OBll!Y!_EAODu$$GN&78B=skNL0%Ck%v~uEE4#&pevTFq$ zK2QqH1Wv|lA)F-gYoFL*1tqi}d}pXgi6jgivEW)`D2OBP+|>3IKd(xkl5g?m8?;M{xW{X^Dv-A%%2px@|uK@@b7P?XxF zGv6t0L>-pP)3{d%#O+o6n^$P>_!y7 z&yNUMC^w`h8eGq;%T*sU60Sh&Y~nK#7CG_5faHQ}m5UD>6(sCQ@N~_-E7^@!&O;sF zw2}<8npS<|b}WM{>O0s1PFV7Cfuv3rH`_|^)ObrMo z^F$i=J``H&>If-}o@6@l=wA>!EIJO$*OLx5=E$?cXc#dapCJ15&iFJ2)N)HEJ#WpO zdirRgmBhR0`8=TG@b%54@PMM)*YJPFa@4eL&e}XEA_uo52T%@M_&))sPe>x4J}A1} zrKY@ml*QfAldos1QiNq0d7|GJ(xXhW)dNstJ64AC$TbQeE+Yv?gd zP(3?Pa!6NTioi2}a6*ogg{aWEiEdq82Tx7kV6vDszmu)rSy0nl+cnow&}W69sB)XwZ52I3tvM zd6xn}=k$VLP6@?)6$~bLIvaI>(1bddm*TP^@Cd^sh*k;~iq%3byOe9~@j;R_5fKTt zn(I)6mUKkIqIrTNVG0}z2W4jQNwA1d|MqbHoy&9e|JRUE!oxf-0yoBPJt1JO^=oLzDs|+6MW6?vT_=7uvCl1Qu zr7_-O8ERU|hKW!fh;*B)lH3&?SV+K3|pUiF3 zXyquHRGzrdKps|2x`5HQ2@@Q?s&mdowhwdT2)Z|unnm--_gl|z8O+bgM5Y-RGL@p9 z*a!1GtV=(qq2&scDO*)jX{5YAgKdj!oi2k*{B!Po^r&C!spneN_ve=F@u)jy&U)3A zkzf#oCF^auOfY=$XM4prco+}=6yzO)i?gR5Y@PUN1VM-UE~OUA_C~@~cE0n}22N6f zhf*8G(@Jo8tUG&T_K<#w=^c*~V5$XMrw73oV=-DmRa1elUi#BR-oy|2nYvnV-_=jo z0#WDpor)5vUrVU9M!?qZfWXlV$!~d}cX+(sF=Kk^lOeic7#w-M$4fKK+#3(!g;$^! zeBjU?y;k{Y4K4S_3GqV$%&21(A3M$CpzN=x1ox7w+Mo+PTJ?GeKm3b8F>RW3ep&S9 zN8M>9D4p_yycth$xP8yg7pWDb@sQj-;U{M-u!$q@?r~6YG?G7A;XeO&^qyLYHZ`NZ z1?P|VN;Ysc7jez^|2r34Gd4!GjljkBu??+T2ktgHKZK|3-x9H`A1ltzq%_`HTY5kH znsfdrP+53e;l`iv$25Xa7TmcP!sJ-xyY?+&#}9L-vJdVv%@lOe*~2=YV9JSDK)!qY z-}2h;;5nlIHQ3w>n%Nb){V>=&nc z!kj<+iP7UZI~WMI=&(kSOv=Yqq{O4jh<{rJip|fMod(++f_D;I-VC!zDlsteDcCLA z9vXPzhJWx>!WSzXdhnd?hvCwl<`VM75nHCwPmy5iY7h6DIUk;QfOBsP#Xq8!uH96Z@4ur*u>Az_gd=ihh;}c1Ae~1Qqni(MJYN zM{FQj$;;`?BPN{^{QU*nrx3#Ww^d=;c8oXJQz89dPk68zt;S)i1qW)1Ddp&u3-3Jj zj~=n40wE$~-T;jOIiKpRT}RA>{3l^faepV-?>+n*p#;g{R(NxLbXa5gH&kC*-2LT? z@e_(e+YPw#M6`kXUJC!{Ik;9#MP_hD77SHmBbA@xz6~Z z{q+I4vNF`iwYBo=O7+)t#y|O?@XR2GVoE>2xqJJ+*;f&m{bQ_L)aZ__&1SvdxL$g% zE}3PpyfS(2=fU6Uu72?4%j`3#XmrQ3PnI{X&)(ypS*qHkc{FZhAfFrH)Wvr>%65&XCq+eo#K0)SeM>ndWN=Fx ze4u_H>me0%D^THzZeFprhi)Erpl6hZylmR&t-XnvOxoj{BTe99XGYc664;rOcm0lw zwEHGGRbgQtD_?pZa&l5?ESYg+mhGZi1ZGFcmGG|DBFjusDb{KpI3upL=GB-Ol@1Z! z3E`DAjW=sG&nXxS11xtl4XS!1uHh7C#ILBEBDX%gLGEuYzb!1evDM^vEpnvv^>VaB zM$Q%t$`VS5_@W&la+~ZEjb2~S4*Zp=e;tQpQW9GKox|3jSZ&wmoN$5lY#OMjMfKlQ zl6f$5U}YxVIli;Ge5X^8rr|k^@wNqXQ<$;-TU6U7aBG;uyu;xE+MoSlj6-!+s!oQH&LZy+o1r!HfVLx{;fSu;fNf}-F;|x zHkl!vcR~d8EAFh9INwBN(}G#N%tDYfga0ys+j4tC2<~9Ya9>@ddIqgW-3klPFV8|z zGsu_`0H5hnIiUqs6P9{rYKEys3ja$pR_v}qz~K7ea9iJUACVUadLB?f`3I}HvGJ;F zz)ArlW-b%11m-on+Lgzns_JzACW7Px&3f%!Z=v+S+~^bMG~b(5$IUPG)^w^>M1X!5 ziZGi;J7sq29S?W`G)Xd^N()&xVkS{Y3RH}DY(1#{GEIS_1OU_RUq<{hgepeNQvpYL zkiv7{x_FegV*_|=0MIdd+kYvk@4XH=0H*+_I5gKM1d;%zs~uSn;kOI-li9(UAIORK z@^6j#u@srU91koHpa&dk0};9ka=rYqX8O<{Bmnxzn{}Q&EkD=x6AR!F8oJQUkNGMD zZT-0Ym4OLRexn!7l0X<^#26xy=nz*6!2xM>dh{s1H2qF2!QGe<%rYNT8_t)~hutm{ z1e3UPBOblyql02W5s_pu*{4S6NaaaAGXfLVQ$rK0rU@>lu6bBO5dc7DBc|WxR}@FW zu~=xs`dr!<918%MY?&sWAOwF{SW9- z-WK}MR_EyvuqKJu&r_63V5=xs3XVwLC7l8@#UZLqR9X}^aR-L_rjHPm0Hi}voXmg{ z+Ui9_UPly6&pPYW%|m9c8zyR$K=&AwF=0EJIZaC)nFSUbG|-R(*FtOZPo9O@-$sRXW!oQ90D!{A zN2GA_RA-40G|!h8FGmCvfCoptw&)&D4P-;qEzt-1imY@%aDzPJUB0P;krz4dNfP+E z{)6U#*V%3vhyO6g0ohrcyb1(&>=$oj*FJ<}asNpr85?fS@&zpJTB!3dI!UO4o2esh z|4{@$z>1GU>a!?^)Vd#DMP4FSLl5mf@WIKKxi zw1`Uk2R5971o-9dL92z_RuMovT~phC83X_{nI#ViA5zQjguv;Of#8pK9>N9rAiPg0 z0fo=0@u)~DsFpEtaIc^s52mJsVyySK=+AX9t3P=G^Df`e90qNr^Z{XOxgO)$Vu%?> z{mlBZ!9Y(#&1YatZ{R;VATzH3z&Sy->a~L<3;qWp035}#_CVhPRAG84SV`2gFyox) zs0M=~jMqVfRRsz1Z9D-hSTxrkk=&5)Zb+N6TFn~v5(I+zI& zP9&^EgzYL|&A$8mca}4yR*^IahFvFoWO}i;O$LZLojK?;A{#~wQ6ntp;cyG$;BhAl zu))X(HBvsn0@y#3C$IaEoY!V*qHpT@N@Cl3|L+?n6gg4wG|P1NL3UMm{?KtG!LN0l zFtF|?1_W!_DtF3Eel2hwor%&T!+dyZ?U!G>4RXNm8&?&c-pGKIHJ$aF?Eb>$lkb-< zTmw3>7xp!^+sre0I1aXg1e_R%%3%cpkV3_cuqyED+q8}+<`bh zV@i$v&MCG}3``U!s!l9`ixl>*pjG^ePB;lLVIyBL>dga*K^ohEWp4eR5U_{}lwHTV z!bd+TcCeD|Egx|EPAhCi%2IBE7c6_j_E#7y-fcrm`yBq32fDSD$Xg&j9Jniw{JFt` zxi1r_r)w~;>Fa`eK(~=mboT8B+4Ru`+AwU(%g2L+-?iL^SwN~eIXaMrc%WQ7Rd$_P zqnsDgqs5plad&?n{_1w+@0%pSB9lz-N3wmqBoFE-q3@V`@9)c)bHu0w-)^8)_Sjz_ z#P8S8x)xt!)POmny`DOXi;#U9*gJC*(7|2E0fVDfht&%8y=@q5|Ei4>$E^^sN^m{? zY4h#M1HX+273W9CeasCFL9I=W3oFqlUy%V1`i1j;i$|Q3UX*&U%;5ic9B0&9{aTB^ axS}46T4^}#1>HOVXsPR|l|Hl%`F{XBjt_1C literal 0 HcmV?d00001 diff --git a/packages/commonwealth/static/img/branding/common.png b/packages/commonwealth/static/img/branding/common.png new file mode 100644 index 0000000000000000000000000000000000000000..c3c2a06768a910ea551a0c4f209dc5aad2f02069 GIT binary patch literal 9239 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 literal 0 HcmV?d00001 diff --git a/packages/commonwealth/static/img/branding/common.svg b/packages/commonwealth/static/img/branding/common.svg new file mode 100644 index 00000000000..2427009c405 --- /dev/null +++ b/packages/commonwealth/static/img/branding/common.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/packages/commonwealth/static/manifest.json b/packages/commonwealth/static/manifest.json new file mode 100644 index 00000000000..5af51dac53d --- /dev/null +++ b/packages/commonwealth/static/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "Common App", + "short_name": "Common", + "description": "Create onchain together - Community forums with onchain rewards, roles and more", + "start_url": "/dashboard", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#ffffff", + "icons": [ + { + "src": "/static/img/branding/common.png", + "sizes": "192x192", + "type": "image/png" + } + ], + "manifest_version": "0.0.1", + "installable": true +}