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
67 changes: 35 additions & 32 deletions common/styleguide.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import * as HtmlElements from '@expo/html-elements';
import { TextProps } from '@expo/html-elements/build/primitives/Text';
import Link from 'next/link';
import { ComponentType, PropsWithChildren, useContext, useState } from 'react';
import { StyleSheet, TextStyle, View, useWindowDimensions, ViewStyle } from 'react-native';
import { type ComponentType, type PropsWithChildren, useContext, useState } from 'react';
import {
StyleSheet,
TextStyle,
View,
useWindowDimensions,
ViewStyle,
StyleProp,
} from 'react-native';

import CustomAppearanceContext from '../context/CustomAppearanceContext';

Expand Down Expand Up @@ -87,16 +94,16 @@ type CustomTextProps = TextProps &
const createTextComponent = (Element: ComponentType<TextProps>, textStyle?: TextStyles) => {
const TextComponent = ({ children, style, id, numberOfLines }: CustomTextProps) => {
const { isDark } = useContext(CustomAppearanceContext);

const elementStyle = Element?.displayName
? StyleSheet.flatten(textStyles[Element.displayName as keyof typeof textStyles])
: undefined;

return (
<Element
id={id}
numberOfLines={numberOfLines}
style={[
textStyles[Element.displayName],
textStyle,
{ color: isDark ? colors.white : colors.black },
style,
]}>
style={[elementStyle, textStyle, { color: isDark ? colors.white : colors.black }, style]}>
{children}
</Element>
);
Expand All @@ -118,30 +125,22 @@ export const Caption = createTextComponent(HtmlElements.P, textStyles.caption);
export const Label = createTextComponent(HtmlElements.P, textStyles.label);

type AProps = PropsWithChildren<{
style?: TextStyles;
style?: StyleProp<TextStyle>;
target?: string;
href: string;
hoverStyle?: TextStyles;
containerStyle?: ViewStyle;
hoverStyle?: StyleProp<TextStyle>;
containerStyle?: StyleProp<ViewStyle>;
}>;

export const A = ({
href,
target,
children,
style,
hoverStyle,
containerStyle,
...rest
}: AProps) => {
export function A({ href, target, children, style, hoverStyle, containerStyle, ...rest }: AProps) {
const { isDark } = useContext(CustomAppearanceContext);
const [isHovered, setIsHovered] = useState(false);

const linkStyles = getLinkStyles(isDark);
const linkHoverStyles = getLinkHoverStyles();

if ((target === '_self' && !href.startsWith('#')) || href.startsWith('/')) {
const passedStyle = Array.isArray(style) ? StyleSheet.flatten(style) : style;
const passedStyle = StyleSheet.flatten(style);
return (
<Link
href={href}
Expand All @@ -151,7 +150,7 @@ export const A = ({
...linkStyles,
...(passedStyle as any),
...(isHovered && linkHoverStyles),
...(isHovered && hoverStyle),
...(isHovered && hoverStyle && StyleSheet.flatten(hoverStyle)),
}}>
{children}
</Link>
Expand All @@ -174,18 +173,22 @@ export const A = ({
</HtmlElements.A>
</View>
);
};
}

const getLinkStyles = (isDark: boolean) => ({
color: isDark ? colors.white : colors.black,
textDecorationColor: isDark ? colors.gray5 : colors.pewter,
textDecorationLine: 'underline',
fontFamily: 'inherit',
});
function getLinkStyles(isDark: boolean): TextStyle {
return {
color: isDark ? colors.white : colors.black,
textDecorationColor: isDark ? colors.gray5 : colors.pewter,
textDecorationLine: 'underline',
fontFamily: 'inherit',
};
}

const getLinkHoverStyles = () => ({
textDecorationColor: colors.primaryDark,
});
function getLinkHoverStyles(): TextStyle {
return {
textDecorationColor: colors.primaryDark,
};
}

export function HoverEffect({ children }: PropsWithChildren) {
const [isHovered, setIsHovered] = useState(false);
Expand Down
4 changes: 2 additions & 2 deletions components/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { A } from '@expo/html-elements';
import { PropsWithChildren, useContext } from 'react';
import { StyleSheet, TextStyle, Pressable } from 'react-native';
import { StyleSheet, TextStyle, Pressable, StyleProp } from 'react-native';

import { colors, darkColors, HoverEffect, P } from '~/common/styleguide';
import CustomAppearanceContext from '~/context/CustomAppearanceContext';
Expand All @@ -9,7 +9,7 @@ type Props = PropsWithChildren & {
href?: string;
onPress?: () => void;
openInNewTab?: boolean;
style?: TextStyle | TextStyle[];
style?: StyleProp<TextStyle>;
};

export function Button({ children, href, onPress, style, openInNewTab, ...rest }: Props) {
Expand Down
4 changes: 2 additions & 2 deletions components/CheckBox.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { useContext } from 'react';
import { StyleSheet, View, ViewStyle } from 'react-native';
import { StyleProp, StyleSheet, View, ViewStyle } from 'react-native';

import { colors, darkColors } from '~/common/styleguide';
import CustomAppearanceContext from '~/context/CustomAppearanceContext';

import { Check } from './Icons';

type Props = {
style?: ViewStyle | ViewStyle[];
style?: StyleProp<ViewStyle>;
value?: boolean;
color?: string;
};
Expand Down
2 changes: 1 addition & 1 deletion components/Filters/FilterButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const FilterButton = ({
];

const filterCount = Object.keys(query).reduce(
(acc, q) => (params.includes(q) ? acc + 1 : acc),
(acc, q) => (params.includes(q as keyof Query) ? acc + 1 : acc),
0
);
const isFilterCount = !!filterCount;
Expand Down
2 changes: 1 addition & 1 deletion components/Filters/ToggleLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { CheckBox } from '../CheckBox';

type Props = {
query: Query;
paramName: string;
paramName: keyof Query;
title: string;
basePath?: string;
};
Expand Down
15 changes: 11 additions & 4 deletions components/Filters/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export const FILTER_PLATFORMS = [
import { Query } from '~/types';

type FilterParamsType = {
param: keyof Query;
title: string;
};

export const FILTER_PLATFORMS: FilterParamsType[] = [
{
param: 'android',
title: 'Android',
Expand Down Expand Up @@ -29,7 +36,7 @@ export const FILTER_PLATFORMS = [
},
];

export const FILTER_REQUIRES_MAIN_SEARCH = [
export const FILTER_REQUIRES_MAIN_SEARCH: FilterParamsType[] = [
{
param: 'isMaintained',
title: 'Maintained',
Expand All @@ -40,7 +47,7 @@ export const FILTER_REQUIRES_MAIN_SEARCH = [
},
];

export const FILTER_STATUS = [
export const FILTER_STATUS: FilterParamsType[] = [
{
param: 'newArchitecture',
title: 'Supports New Architecture',
Expand All @@ -67,7 +74,7 @@ export const FILTER_STATUS = [
},
];

export const FILTER_COMPATIBILITY = [
export const FILTER_COMPATIBILITY: FilterParamsType[] = [
{
param: 'expoGo',
title: 'Works with Expo Go',
Expand Down
24 changes: 12 additions & 12 deletions components/Filters/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,21 +58,21 @@ export function Filters({ query, style, basePath = '/' }: FiltersProps) {
<Headline style={[styles.title, titleColor]}>Status</Headline>
<View style={styles.optionsContainer}>
{isMainSearch &&
FILTER_REQUIRES_MAIN_SEARCH.map(platform => (
FILTER_REQUIRES_MAIN_SEARCH.map(status => (
<ToggleLink
key={platform.param}
key={status.param}
query={pageQuery}
paramName={platform.param}
title={platform.title}
paramName={status.param}
title={status.title}
basePath={basePath}
/>
))}
{FILTER_STATUS.map(platform => (
{FILTER_STATUS.map(status => (
<ToggleLink
key={platform.param}
key={status.param}
query={pageQuery}
paramName={platform.param}
title={platform.title}
paramName={status.param}
title={status.title}
basePath={basePath}
/>
))}
Expand All @@ -82,12 +82,12 @@ export function Filters({ query, style, basePath = '/' }: FiltersProps) {
<View style={[styles.wrappableContainer, isSmallScreen && { maxWidth: '100%' }]}>
<Headline style={[styles.title, titleColor]}>Compatibility</Headline>
<View style={styles.optionsContainer}>
{FILTER_COMPATIBILITY.map(platform => (
{FILTER_COMPATIBILITY.map(compatibility => (
<ToggleLink
key={platform.param}
key={compatibility.param}
query={pageQuery}
paramName={platform.param}
title={platform.title}
paramName={compatibility.param}
title={compatibility.title}
basePath={basePath}
/>
))}
Expand Down
5 changes: 3 additions & 2 deletions components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { FunctionComponent, SVGAttributes, createElement, useContext } from 'react';
import { ComponentType, createElement, useContext } from 'react';
import { StyleSheet, View, ViewStyle } from 'react-native';

import { A, P, colors, darkColors, useLayout } from '~/common/styleguide';
import CustomAppearanceContext from '~/context/CustomAppearanceContext';

import ContentContainer from './ContentContainer';
import {
IconProps,
Logo,
PlatformAndroid,
PlatformIOS,
Expand All @@ -21,7 +22,7 @@ type PlatformProps = {
name: string;
pkgName: string;
url: string;
Icon: FunctionComponent<SVGAttributes<SVGElement>>;
Icon: ComponentType<IconProps>;
style?: ViewStyle;
};

Expand Down
4 changes: 2 additions & 2 deletions components/Library/UnmaintainedLabel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Fragment, useContext } from 'react';
import { StyleSheet, View } from 'react-native';
import { StyleProp, StyleSheet, TextStyle, View } from 'react-native';

import { A, colors, darkColors, Label, useLayout } from '~/common/styleguide';
import CustomAppearanceContext from '~/context/CustomAppearanceContext';
Expand All @@ -15,7 +15,7 @@ function UnmaintainedLabel({ alternatives }: Props) {
const { isDark } = useContext(CustomAppearanceContext);
const { isSmallScreen } = useLayout();

const linkHoverStyle = isDark && { color: colors.secondary };
const linkHoverStyle: StyleProp<TextStyle> = isDark && { color: colors.secondary };
const contentColor = isDark ? darkColors.secondary : colors.gray5;

return (
Expand Down
4 changes: 2 additions & 2 deletions components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const Search = ({ query, total }: Props) => {
const [isInputFocused, setInputFocused] = useState(false);
const [isFilterVisible, setFilterVisible] = useState(Object.keys(filterParams).length > 0);
const [isApple, setIsApple] = useState<boolean | null>(null);
const inputRef = useRef(null);
const inputRef = useRef<TextInput>(null);

const { isSmallScreen } = useLayout();
const { isDark } = useContext(CustomAppearanceContext);
Expand Down Expand Up @@ -79,7 +79,7 @@ const Search = ({ query, total }: Props) => {
if (inputRef.current && event.key === 'Escape') {
if (search) {
event.preventDefault();
inputRef.current.value = '';
inputRef.current.clear();
void Router.replace(
urlWithQuery('/', {
...query,
Expand Down
55 changes: 29 additions & 26 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as Sentry from '@sentry/react';
import type { AppProps } from 'next/app';
import Head from 'next/head';
import { SafeAreaProvider } from 'react-native-safe-area-context';

Expand All @@ -21,22 +22,23 @@ Sentry.init({
tracesSampleRate: isProd ? 0.5 : 1.0,
});

const App = ({ pageProps, Component }) => (
<CustomAppearanceProvider>
<CustomAppearanceContext.Consumer>
{context => (
<SafeAreaProvider
style={{
flex: 1,
backgroundColor: context.isDark ? darkColors.background : colors.white,
}}>
<Head>
<meta
name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=2,viewport-fit=cover"
/>
<style>
{`html {
function App({ pageProps, Component }: AppProps) {
return (
<CustomAppearanceProvider>
<CustomAppearanceContext.Consumer>
{context => (
<SafeAreaProvider
style={{
flex: 1,
backgroundColor: context.isDark ? darkColors.background : colors.white,
}}>
<Head>
<meta
name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=2,viewport-fit=cover"
/>
<style>
{`html {
background-color: ${context.isDark ? darkColors.veryDark : colors.gray7};
}
*:focus-visible {
Expand All @@ -49,15 +51,16 @@ const App = ({ pageProps, Component }) => (
.TooltipContent svg {
stroke: ${context.isDark ? colors.gray7 : colors.gray6};
}`}
</style>
</Head>
<Header />
<Component {...pageProps} />
<Footer />
</SafeAreaProvider>
)}
</CustomAppearanceContext.Consumer>
</CustomAppearanceProvider>
);
</style>
</Head>
<Header />
<Component {...pageProps} />
<Footer />
</SafeAreaProvider>
)}
</CustomAppearanceContext.Consumer>
</CustomAppearanceProvider>
);
}

export default Sentry.withProfiler(App);
Loading