feat: mobile app package (#1075)

This commit is contained in:
Mo
2022-06-09 09:45:15 -05:00
committed by GitHub
parent 58b63898de
commit 8248a38280
336 changed files with 47696 additions and 22563 deletions

View File

@@ -0,0 +1,29 @@
import styled from 'styled-components/native'
export const Container = styled.View`
flex: 1;
background-color: transparent;
align-items: center;
justify-content: center;
`
export const Content = styled.View`
background-color: ${({ theme }) => theme.stylekitBackgroundColor};
padding: 20px;
border-radius: 10px;
width: 80%;
`
export const Title = styled.Text`
color: ${({ theme }) => theme.stylekitForegroundColor};
font-size: 16px;
font-weight: bold;
text-align: center;
margin-bottom: 5px;
`
export const Subtitle = styled.Text`
color: ${({ theme }) => theme.stylekitForegroundColor};
font-size: 14px;
text-align: center;
`

View File

@@ -0,0 +1,17 @@
import { ModalStackNavigationProp } from '@Root/ModalStack'
import { MODAL_BLOCKING_ALERT } from '@Root/Screens/screens'
import React from 'react'
import { Container, Content, Subtitle, Title } from './BlockingModal.styled'
type Props = ModalStackNavigationProp<typeof MODAL_BLOCKING_ALERT>
export const BlockingModal = ({ route: { params } }: Props) => {
return (
<Container>
<Content>
{params.title && <Title>{params.title}</Title>}
<Subtitle>{params.text}</Subtitle>
</Content>
</Container>
)
}

View File

@@ -0,0 +1,75 @@
import React from 'react'
import styled, { css } from 'styled-components/native'
type Props = {
onPress: () => void
label: string
primary?: boolean
fullWidth?: boolean
last?: boolean
}
const PrimaryButtonContainer = styled.TouchableOpacity.attrs({
activeOpacity: 0.84,
})<{
fullWidth?: boolean
last?: boolean
}>`
background-color: ${({ theme }) => theme.stylekitInfoColor};
padding: 12px 24px;
border-radius: 4px;
border-width: 1px;
border-color: ${({ theme }) => theme.stylekitInfoColor};
margin-bottom: ${({ fullWidth, last }) => (fullWidth && !last ? '16px' : 0)};
${({ fullWidth }) =>
!fullWidth &&
css`
align-self: center;
`};
`
const SecondaryButtonContainer = styled.TouchableHighlight.attrs(({ theme }) => ({
activeOpacity: 0.84,
underlayColor: theme.stylekitBorderColor,
}))<{
fullWidth?: boolean
last?: boolean
}>`
background-color: ${({ theme }) => theme.stylekitBackgroundColor};
padding: 12px 24px;
border-radius: 4px;
border-width: 1px;
border-color: ${({ theme }) => theme.stylekitBorderColor};
margin-bottom: ${({ fullWidth, last }) => (fullWidth && !last ? '16px' : 0)};
${({ fullWidth }) =>
!fullWidth &&
css`
align-self: center;
`};
`
const ButtonLabel = styled.Text<{ primary?: boolean }>`
text-align: center;
text-align-vertical: center;
font-weight: bold;
color: ${({ theme, primary }) => {
return primary ? theme.stylekitInfoContrastColor : theme.stylekitForegroundColor
}};
font-size: ${props => props.theme.mainTextFontSize}px;
`
export const Button: React.FC<Props> = ({ onPress, label, primary, fullWidth, last }: Props) => {
if (primary) {
return (
<PrimaryButtonContainer onPress={onPress} fullWidth={fullWidth} last={last}>
<ButtonLabel primary={primary}>{label}</ButtonLabel>
</PrimaryButtonContainer>
)
} else {
return (
<SecondaryButtonContainer onPress={onPress} fullWidth={fullWidth} last={last}>
<ButtonLabel primary={primary}>{label}</ButtonLabel>
</SecondaryButtonContainer>
)
}
}

View File

@@ -0,0 +1,80 @@
import React from 'react'
import { Platform } from 'react-native'
import styled, { css } from 'styled-components/native'
import { Props as TableCellProps, SectionedTableCellTouchableHighlight } from './SectionedTableCell'
type Props = {
testID?: string
maxHeight?: number
leftAligned?: boolean
bold?: boolean
disabled?: boolean
important?: boolean
onPress: () => void
first?: boolean
last?: boolean
title?: string
}
type ContainerProps = Pick<Props, 'maxHeight'> & TableCellProps
const Container = styled(SectionedTableCellTouchableHighlight).attrs(props => ({
underlayColor: props.theme.stylekitBorderColor,
}))<ContainerProps>`
padding-top: ${12}px;
justify-content: center;
${({ maxHeight }) =>
maxHeight &&
css`
max-height: 50px;
`};
`
const ButtonContainer = styled.View``
type ButtonLabelProps = Pick<Props, 'leftAligned' | 'bold' | 'disabled' | 'important'>
const ButtonLabel = styled.Text<ButtonLabelProps>`
text-align: ${props => (props.leftAligned ? 'left' : 'center')};
text-align-vertical: center;
color: ${props => {
let color = Platform.OS === 'android' ? props.theme.stylekitForegroundColor : props.theme.stylekitInfoColor
if (props.disabled) {
color = 'gray'
} else if (props.important) {
color = props.theme.stylekitDangerColor
}
return color
}};
font-size: ${props => props.theme.mainTextFontSize}px;
${({ bold }) =>
bold &&
css`
font-weight: bold;
`}
${({ disabled }) =>
disabled &&
css`
opacity: 0.6;
`}
`
export const ButtonCell: React.FC<Props> = props => (
<Container
first={props.first}
last={props.last}
maxHeight={props.maxHeight}
testID={props.testID}
disabled={props.disabled}
onPress={props.onPress}
>
<ButtonContainer>
<ButtonLabel
important={props.important}
disabled={props.disabled}
bold={props.bold}
leftAligned={props.leftAligned}
>
{props.title}
</ButtonLabel>
{props.children && props.children}
</ButtonContainer>
</Container>
)

View File

@@ -0,0 +1,112 @@
import React, { useCallback, useEffect, useRef } from 'react'
import { Animated } from 'react-native'
import { TouchableWithoutFeedback } from 'react-native-gesture-handler'
import styled, { css } from 'styled-components/native'
type Props = {
selected: boolean
onPress: () => void
label: string
last?: boolean
}
const Container = styled.View<{
last?: boolean
}>`
border-radius: 100px;
padding: 5px 10px;
border-width: 1px;
${({ last }) =>
!last &&
css`
margin-right: 8px;
`};
`
const Label = styled.Text<{ selected: boolean }>`
font-size: 14px;
`
const ActiveContainer = styled(Container)`
background-color: ${({ theme }) => theme.stylekitInfoColor};
border-color: ${({ theme }) => theme.stylekitInfoColor};
`
const InactiveContainer = styled(Container)`
position: absolute;
background-color: ${({ theme }) => theme.stylekitInfoContrastColor};
border-color: ${({ theme }) => theme.stylekitBorderColor};
`
const ActiveLabel = styled(Label)`
color: ${({ theme }) => theme.stylekitNeutralContrastColor};
`
const InactiveLabel = styled(Label)`
color: ${({ theme }) => theme.stylekitNeutralColor};
`
export const Chip: React.FC<Props> = ({ selected, onPress, label, last }) => {
const animationValue = useRef(new Animated.Value(selected ? 1 : 0)).current
const selectedRef = useRef<boolean>(selected)
const toggleChip = useCallback(() => {
Animated.timing(animationValue, {
toValue: selected ? 1 : 0,
duration: 100,
useNativeDriver: true,
}).start()
}, [animationValue, selected])
useEffect(() => {
if (selected !== selectedRef.current) {
toggleChip()
selectedRef.current = selected
}
}, [selected, toggleChip])
return (
<TouchableWithoutFeedback onPress={onPress}>
<ActiveContainer
as={Animated.View}
last={last}
style={{
opacity: animationValue,
}}
>
<ActiveLabel
as={Animated.Text}
selected={selected}
style={{
opacity: animationValue,
}}
>
{label}
</ActiveLabel>
</ActiveContainer>
<InactiveContainer
as={Animated.View}
last={last}
style={{
opacity: animationValue.interpolate({
inputRange: [0, 1],
outputRange: [1, 0],
}),
}}
>
<InactiveLabel
as={Animated.Text}
selected={selected}
style={{
opacity: animationValue.interpolate({
inputRange: [0, 1],
outputRange: [1, 0],
}),
}}
>
{label}
</InactiveLabel>
</InactiveContainer>
</TouchableWithoutFeedback>
)
}

View File

@@ -0,0 +1,16 @@
import styled from 'styled-components/native'
type Props = {
size?: number
backgroundColor?: string
borderColor?: string
}
export const Circle = styled.View<Props>`
width: ${props => props.size ?? 12}px;
height: ${props => props.size ?? 12}px;
border-radius: ${props => (props.size ?? 12) / 2}px;
background-color: ${props => props.backgroundColor};
border-color: ${props => props.borderColor};
border-width: 1px;
`

View File

@@ -0,0 +1,41 @@
import React from 'react'
import { Platform } from 'react-native'
import styled from 'styled-components/native'
type Props = {
subtitleColor?: string
title: string
subtitle?: string
}
const Container = styled.View`
/* background-color: ${props => props.theme.stylekitContrastBackgroundColor}; */
flex: 1;
justify-content: center;
${Platform.OS === 'android' && 'align-items: flex-start; min-width: 100px;'}
`
const Title = styled.Text`
color: ${props => props.theme.stylekitForegroundColor};
font-weight: bold;
font-size: 18px;
text-align: center;
`
const SubTitle = styled.Text.attrs(() => ({
adjustsFontSizeToFit: true,
numberOfLines: 1,
}))<{ color?: string }>`
color: ${props => props.color ?? props.theme.stylekitForegroundColor};
opacity: ${props => (props.color ? 1 : 0.6)};
font-size: ${Platform.OS === 'android' ? 13 : 12}px;
${Platform.OS === 'ios' && 'text-align: center'}
`
export const HeaderTitleView: React.FC<Props> = props => (
<Container>
<Title>{props.title}</Title>
{props.subtitle && props.subtitle.length > 0 ? (
<SubTitle color={props.subtitleColor}>{props.subtitle}</SubTitle>
) : undefined}
</Container>
)

View File

@@ -0,0 +1,8 @@
import { StyleSheet } from 'react-native'
export const iconStyles = StyleSheet.create({
icon: {
width: 14,
height: 14,
},
})

View File

@@ -0,0 +1,19 @@
import React, { useContext } from 'react'
import Icon from 'react-native-vector-icons/Ionicons'
import { HeaderButton, HeaderButtonProps } from 'react-navigation-header-buttons'
import { ThemeContext } from 'styled-components'
export const IoniconsHeaderButton = (passMeFurther: HeaderButtonProps) => {
// the `passMeFurther` variable here contains props from <Item .../> as well as <HeaderButtons ... />
// and it is important to pass those props to `HeaderButton`
// then you may add some information like icon size or color (if you use icons)
const theme = useContext(ThemeContext)
return (
<HeaderButton
IconComponent={Icon}
iconSize={30}
color={passMeFurther.disabled ? 'gray' : theme.stylekitInfoColor}
{...passMeFurther}
/>
)
}

View File

@@ -0,0 +1,7 @@
import { StyleSheet } from 'react-native'
export const searchBarStyles = StyleSheet.create({
androidSearch: {
height: 30,
},
})

View File

@@ -0,0 +1,94 @@
import { ThemeServiceContext } from '@Style/ThemeService'
import React, { FC, RefObject, useCallback, useContext } from 'react'
import { Platform } from 'react-native'
import IosSearchBar from 'react-native-search-bar'
import AndroidSearchBar from 'react-native-search-box'
import { ThemeContext } from 'styled-components/native'
import { searchBarStyles } from './/SearchBar.styled'
type Props = {
onChangeText: (text: string) => void
onSearchCancel: () => void
iosSearchBarInputRef: RefObject<IosSearchBar>
androidSearchBarInputRef: RefObject<typeof AndroidSearchBar>
onSearchFocusCallback?: () => void
onSearchBlurCallback?: () => void
collapseSearchBarOnBlur?: boolean
}
export const SearchBar: FC<Props> = ({
onChangeText,
onSearchCancel,
iosSearchBarInputRef,
androidSearchBarInputRef,
onSearchFocusCallback,
onSearchBlurCallback,
collapseSearchBarOnBlur = true,
}) => {
const theme = useContext(ThemeContext)
const themeService = useContext(ThemeServiceContext)
const onSearchFocus = useCallback(() => {
onSearchFocusCallback?.()
}, [onSearchFocusCallback])
const onSearchBlur = useCallback(() => {
onSearchBlurCallback?.()
}, [onSearchBlurCallback])
return (
<>
{Platform.OS === 'ios' && (
<IosSearchBar
ref={iosSearchBarInputRef}
keyboardAppearance={themeService?.keyboardColorForActiveTheme()}
placeholder="Search"
hideBackground
appearance={themeService?.keyboardColorForActiveTheme()}
barTintColor={theme.stylekitInfoColor}
textFieldBackgroundColor={theme.stylekitContrastBackgroundColor}
onChangeText={onChangeText}
onSearchButtonPress={() => {
iosSearchBarInputRef.current?.blur()
}}
onCancelButtonPress={() => {
iosSearchBarInputRef.current?.blur()
onSearchCancel()
}}
onFocus={onSearchFocus}
onBlur={onSearchBlur}
/>
)}
{Platform.OS === 'android' && (
<AndroidSearchBar
ref={androidSearchBarInputRef}
onChangeText={onChangeText}
onCancel={() => {
onSearchBlur()
onSearchCancel()
}}
onDelete={onSearchCancel}
onFocus={onSearchFocus}
onBlur={onSearchBlur}
collapseOnBlur={collapseSearchBarOnBlur}
blurOnSubmit={true}
backgroundColor={theme.stylekitBackgroundColor}
titleCancelColor={theme.stylekitInfoColor}
keyboardDismissMode={'interactive'}
keyboardAppearance={themeService?.keyboardColorForActiveTheme()}
inputBorderRadius={4}
tintColorSearch={theme.stylekitForegroundColor}
inputStyle={[
searchBarStyles.androidSearch,
{
color: theme.stylekitForegroundColor,
backgroundColor: theme.stylekitContrastBackgroundColor,
},
]}
placeholderExpandedMargin={25}
searchIconCollapsedMargin={30}
/>
)}
</>
)
}

View File

@@ -0,0 +1,76 @@
import React from 'react'
import { Platform } from 'react-native'
import styled from 'styled-components/native'
type Props = {
title?: string
subtitle?: string
buttonText?: string
buttonAction?: () => void
buttonStyles?: any
tinted?: boolean
backgroundColor?: string
}
const Container = styled.View<Pick<Props, 'backgroundColor'>>`
/* flex: 1; */
/* flex-grow: 0; */
justify-content: space-between;
flex-direction: row;
padding-right: ${props => props.theme.paddingLeft}px;
padding-bottom: 10px;
padding-top: 10px;
background-color: ${props => props.backgroundColor ?? props.theme.stylekitBackgroundColor};
`
const TitleContainer = styled.View``
const Title = styled.Text<Pick<Props, 'tinted'>>`
background-color: ${props => props.theme.stylekitBackgroundColor};
font-size: ${props => {
return Platform.OS === 'android' ? props.theme.mainTextFontSize - 2 : props.theme.mainTextFontSize - 4
}}px;
padding-left: ${props => props.theme.paddingLeft}px;
color: ${props => {
if (props.tinted) {
return props.theme.stylekitInfoColor
}
return Platform.OS === 'android' ? props.theme.stylekitInfoColor : props.theme.stylekitNeutralColor
}};
font-weight: ${Platform.OS === 'android' ? 'bold' : 'normal'};
`
const SubTitle = styled.Text`
background-color: ${props => props.theme.stylekitBackgroundColor};
font-size: ${props => props.theme.mainTextFontSize - 5}px;
margin-top: 4px;
padding-left: ${props => props.theme.paddingLeft}px;
color: ${props => props.theme.stylekitNeutralColor};
`
const ButtonContainer = styled.TouchableOpacity`
flex: 1;
align-items: flex-end;
justify-content: center;
`
const Button = styled.Text`
color: ${props => props.theme.stylekitInfoColor};
`
export const SectionHeader: React.FC<Props> = props => (
<Container>
<TitleContainer>
{!!props.title && (
<Title>
{Platform.select({
ios: props.title.toUpperCase(),
android: props.title,
})}
</Title>
)}
{!!props.subtitle && <SubTitle>{props.subtitle}</SubTitle>}
</TitleContainer>
{!!props.buttonText && (
<ButtonContainer onPress={props.buttonAction}>
<Button style={props.buttonStyles}>{props.buttonText}</Button>
</ButtonContainer>
)}
</Container>
)

View File

@@ -0,0 +1,132 @@
import React, { useContext } from 'react'
import { Platform } from 'react-native'
import Icon from 'react-native-vector-icons/Ionicons'
import { ThemeContext } from 'styled-components'
import styled, { css } from 'styled-components/native'
import { SectionedTableCellTouchableHighlight } from './/SectionedTableCell'
type Props = {
testID?: string
disabled?: boolean
onPress: () => void
onLongPress?: () => void
iconName?: string
selected?: () => boolean
leftAlignIcon?: boolean
color?: string
bold?: boolean
tinted?: boolean
dimmed?: boolean
text: string
first?: boolean
last?: boolean
}
const TouchableContainer = styled(SectionedTableCellTouchableHighlight).attrs(props => ({
underlayColor: props.theme.stylekitBorderColor,
}))`
flex-direction: column;
padding-top: 0px;
padding-bottom: 0px;
min-height: 47px;
background-color: transparent;
`
const ContentContainer = styled.View<Pick<Props, 'leftAlignIcon'>>`
flex: 1;
justify-content: ${props => {
return props.leftAlignIcon ? 'flex-start' : 'space-between'
}};
flex-direction: row;
align-items: center;
`
const IconContainer = styled.View`
width: 30px;
max-width: 30px;
`
type LabelProps = Pick<Props, 'bold' | 'tinted' | 'dimmed' | 'selected' | 'color'>
const Label = styled.Text<LabelProps>`
min-width: 80%;
color: ${props => {
let color = props.theme.stylekitForegroundColor
if (props.tinted) {
color = props.theme.stylekitInfoColor
}
if (props.dimmed) {
color = props.theme.stylekitNeutralColor
}
if (props.color) {
color = props.color
}
return color
}};
font-size: ${props => props.theme.mainTextFontSize}px;
${({ bold, selected }) =>
((selected && selected() === true) || bold) &&
css`
font-weight: bold;
`};
`
export const SectionedAccessoryTableCell: React.FC<Props> = props => {
const themeContext = useContext(ThemeContext)
const onPress = () => {
if (props.disabled) {
return
}
props.onPress()
}
const onLongPress = () => {
if (props.disabled) {
return
}
if (props.onLongPress) {
props.onLongPress()
}
}
const checkmarkName = Platform.OS === 'android' ? 'md-checkbox' : 'ios-checkmark-circle'
const iconName = props.iconName ? props.iconName : props.selected && props.selected() ? checkmarkName : null
const left = props.leftAlignIcon
let iconSize = left ? 25 : 30
let color = left ? themeContext.stylekitForegroundColor : themeContext.stylekitInfoColor
if (Platform.OS === 'android') {
iconSize -= 5
}
if (props.color) {
color = props.color
}
let icon: any = null
if (iconName) {
icon = (
<IconContainer key={iconName}>
<Icon name={iconName} size={iconSize} color={color} />
</IconContainer>
)
}
const textWrapper = (
<Label
tinted={props.tinted}
dimmed={props.dimmed}
bold={props.bold}
selected={props.selected}
color={props.color}
key={1}
>
{props.text}
</Label>
)
return (
<TouchableContainer first={props.first} last={props.last} onPress={onPress} onLongPress={onLongPress}>
<ContentContainer>{props.leftAlignIcon ? [icon, textWrapper] : [textWrapper, icon]}</ContentContainer>
</TouchableContainer>
)
}

View File

@@ -0,0 +1,88 @@
import React from 'react'
import styled, { css } from 'styled-components/native'
export type Option = { selected: boolean; key: string; title: string }
type Props = {
testID?: string
title: string
first?: boolean
height?: number
onPress: (option: Option) => void
options: Option[]
leftAligned?: boolean
}
type ContainerProps = Omit<Props, 'title' | 'onPress' | 'options'>
export const Container = styled.View<ContainerProps>`
border-bottom-color: ${props => props.theme.stylekitBorderColor};
border-bottom-width: 1px;
padding-left: ${props => props.theme.paddingLeft}px;
padding-right: ${props => props.theme.paddingLeft}px;
background-color: ${props => props.theme.stylekitBackgroundColor};
${({ first, theme }) =>
first &&
css`
border-top-color: ${theme.stylekitBorderColor};
border-top-width: ${1}px;
`};
${({ height }) =>
height &&
css`
height: ${height}px;
`};
flex-direction: row;
justify-content: center;
align-items: center;
max-height: 45px;
`
const Title = styled.Text<{ leftAligned?: boolean }>`
font-size: ${props => props.theme.mainTextFontSize}px;
color: ${props => props.theme.stylekitForegroundColor};
text-align: ${props => (props.leftAligned ? 'left' : 'center')};
width: 42%;
min-width: 0px;
`
const OptionsContainer = styled.View`
width: 58%;
flex-direction: row;
align-items: center;
justify-content: center;
background-color: ${props => props.theme.stylekitBackgroundColor};
`
const ButtonTouchable = styled.TouchableHighlight.attrs(props => ({
underlayColor: props.theme.stylekitBorderColor,
}))`
border-left-color: ${props => props.theme.stylekitBorderColor};
border-left-width: 1px;
flex-grow: 1;
padding: 10px;
padding-top: 12px;
`
const ButtonTitle = styled.Text<{ selected: boolean }>`
color: ${props => {
return props.selected ? props.theme.stylekitInfoColor : props.theme.stylekitNeutralColor
}};
font-size: 16px;
text-align: center;
width: 100%;
`
export const SectionedOptionsTableCell: React.FC<Props> = props => (
<Container first={props.first}>
<Title leftAligned={props.leftAligned}>{props.title}</Title>
<OptionsContainer>
{props.options.map(option => {
return (
<ButtonTouchable key={option.title} onPress={() => props.onPress(option)}>
<ButtonTitle selected={option.selected}>{option.title}</ButtonTitle>
</ButtonTouchable>
)
})}
</OptionsContainer>
</Container>
)

View File

@@ -0,0 +1,59 @@
import styled, { css } from 'styled-components/native'
export type Props = {
first?: boolean
last?: boolean
textInputCell?: any
height?: number
extraStyles?: any
}
export const SectionedTableCell = styled.View<Props>`
border-bottom-color: ${props => props.theme.stylekitBorderColor};
border-bottom-width: 1px;
padding-left: ${props => props.theme.paddingLeft}px;
padding-right: ${props => props.theme.paddingLeft}px;
padding-bottom: ${props => (props.textInputCell ? 0 : 12)}px;
background-color: ${props => props.theme.stylekitBackgroundColor};
${({ first, theme }) =>
first &&
css`
border-top-color: ${theme.stylekitBorderColor};
border-top-width: ${1}px;
`};
${({ textInputCell }) =>
textInputCell &&
css`
max-height: 50px;
`};
${({ height }) =>
height &&
css`
height: ${height}px;
`};
`
export const SectionedTableCellTouchableHighlight = styled.TouchableHighlight<Props>`
border-bottom-color: ${props => props.theme.stylekitBorderColor};
border-bottom-width: 1px;
padding-left: ${props => props.theme.paddingLeft}px;
padding-right: ${props => props.theme.paddingLeft}px;
padding-bottom: ${props => (props.textInputCell ? 0 : 12)}px;
background-color: ${props => props.theme.stylekitBackgroundColor};
${({ first, theme }) =>
first &&
css`
border-top-color: ${theme.stylekitBorderColor};
border-top-width: ${1}px;
`};
${({ textInputCell }) =>
textInputCell &&
css`
max-height: 50px;
`};
${({ height }) =>
height &&
css`
height: ${height}px;
`};
`

View File

@@ -0,0 +1,101 @@
import ArchiveIcon from '@standardnotes/icons/dist/mobile-exports/ic-archive.svg'
import AttachmentFileIcon from '@standardnotes/icons/dist/mobile-exports/ic-attachment-file.svg'
import AuthenticatorIcon from '@standardnotes/icons/dist/mobile-exports/ic-authenticator.svg'
import ClearCircleFilledIcon from '@standardnotes/icons/dist/mobile-exports/ic-clear-circle-filled.svg'
import CodeIcon from '@standardnotes/icons/dist/mobile-exports/ic-code.svg'
import FileDocIcon from '@standardnotes/icons/dist/mobile-exports/ic-file-doc.svg'
import FileImageIcon from '@standardnotes/icons/dist/mobile-exports/ic-file-image.svg'
import FileMovIcon from '@standardnotes/icons/dist/mobile-exports/ic-file-mov.svg'
import FileMusicIcon from '@standardnotes/icons/dist/mobile-exports/ic-file-music.svg'
import FileOtherIcon from '@standardnotes/icons/dist/mobile-exports/ic-file-other.svg'
import FilePdfIcon from '@standardnotes/icons/dist/mobile-exports/ic-file-pdf.svg'
import FilePptIcon from '@standardnotes/icons/dist/mobile-exports/ic-file-ppt.svg'
import FileXlsIcon from '@standardnotes/icons/dist/mobile-exports/ic-file-xls.svg'
import FileZipIcon from '@standardnotes/icons/dist/mobile-exports/ic-file-zip.svg'
import LockFilledIcon from '@standardnotes/icons/dist/mobile-exports/ic-lock-filled.svg'
import MarkdownIcon from '@standardnotes/icons/dist/mobile-exports/ic-markdown.svg'
import NotesIcon from '@standardnotes/icons/dist/mobile-exports/ic-notes.svg'
import OpenInIcon from '@standardnotes/icons/dist/mobile-exports/ic-open-in.svg'
import PencilOffIcon from '@standardnotes/icons/dist/mobile-exports/ic-pencil-off.svg'
import PinFilledIcon from '@standardnotes/icons/dist/mobile-exports/ic-pin-filled.svg'
import SpreadsheetsIcon from '@standardnotes/icons/dist/mobile-exports/ic-spreadsheets.svg'
import TasksIcon from '@standardnotes/icons/dist/mobile-exports/ic-tasks.svg'
import PlainTextIcon from '@standardnotes/icons/dist/mobile-exports/ic-text-paragraph.svg'
import RichTextIcon from '@standardnotes/icons/dist/mobile-exports/ic-text-rich.svg'
import TrashFilledIcon from '@standardnotes/icons/dist/mobile-exports/ic-trash-filled.svg'
import UserAddIcon from '@standardnotes/icons/dist/mobile-exports/ic-user-add.svg'
import FilesIllustration from '@standardnotes/icons/dist/mobile-exports/il-files.svg'
import { IconType } from '@standardnotes/snjs'
import React, { FC, useContext } from 'react'
import { SvgProps } from 'react-native-svg'
import { ThemeContext } from 'styled-components'
import { iconStyles } from './/Icon.styled'
type TIcons = {
[key in IconType]: FC<SvgProps>
}
const ICONS: Partial<TIcons> = {
'pencil-off': PencilOffIcon,
'plain-text': PlainTextIcon,
'rich-text': RichTextIcon,
code: CodeIcon,
markdown: MarkdownIcon,
spreadsheets: SpreadsheetsIcon,
tasks: TasksIcon,
authenticator: AuthenticatorIcon,
'trash-filled': TrashFilledIcon,
'pin-filled': PinFilledIcon,
archive: ArchiveIcon,
'user-add': UserAddIcon,
'open-in': OpenInIcon,
notes: NotesIcon,
'attachment-file': AttachmentFileIcon,
'files-illustration': FilesIllustration,
'file-doc': FileDocIcon,
'file-image': FileImageIcon,
'file-mov': FileMovIcon,
'file-music': FileMusicIcon,
'file-other': FileOtherIcon,
'file-pdf': FilePdfIcon,
'file-ppt': FilePptIcon,
'file-xls': FileXlsIcon,
'file-zip': FileZipIcon,
'clear-circle-filled': ClearCircleFilledIcon,
'lock-filled': LockFilledIcon,
}
type Props = {
type: IconType
fill?: string
style?: Record<string, unknown>
width?: number
height?: number
}
export const SnIcon = ({ type, fill, width, height, style = {} }: Props) => {
const theme = useContext(ThemeContext)
const fillColor = fill || theme.stylekitPalSky
const IconComponent = ICONS[type]
if (!IconComponent) {
return null
}
let customSizes = {}
if (width !== undefined) {
customSizes = {
...customSizes,
width,
}
}
if (height !== undefined) {
customSizes = {
...customSizes,
height,
}
}
return <IconComponent fill={fillColor} {...customSizes} style={[iconStyles.icon, style]} />
}

View File

@@ -0,0 +1,7 @@
import styled from 'styled-components/native'
export const TableSection = styled.View`
margin-top: 10px;
margin-bottom: 10px;
background-color: ${props => props.theme.stylekitBackgroundColor};
`

View File

@@ -0,0 +1,31 @@
import { StyleSheet } from 'react-native'
import { DefaultTheme } from 'styled-components/native'
export const useToastStyles = (theme: DefaultTheme) => {
return (props: { [key: string]: unknown }) => {
return StyleSheet.create({
info: {
borderLeftColor: theme.stylekitInfoColor,
height: props.percentComplete !== undefined ? 70 : 60,
},
animatedViewContainer: {
height: 8,
borderWidth: 1,
borderRadius: 8,
borderColor: theme.stylekitInfoColor,
marginRight: 8,
marginLeft: 12,
marginTop: -16,
},
animatedView: {
backgroundColor: theme.stylekitInfoColor,
},
success: {
borderLeftColor: theme.stylekitSuccessColor,
},
error: {
borderLeftColor: theme.stylekitWarningColor,
},
})
}
}

View File

@@ -0,0 +1,53 @@
import { useToastStyles } from '@Components/ToastWrapper.styled'
import { useProgressBar } from '@Root/Hooks/useProgessBar'
import React, { FC, useContext } from 'react'
import { Animated, StyleSheet, View } from 'react-native'
import Toast, { ErrorToast, InfoToast, SuccessToast, ToastConfig } from 'react-native-toast-message'
import { ThemeContext } from 'styled-components'
export const ToastWrapper: FC = () => {
const theme = useContext(ThemeContext)
const styles = useToastStyles(theme)
const { updateProgressBar, progressBarWidth } = useProgressBar()
const toastStyles: ToastConfig = {
info: props => {
const percentComplete = props.props?.percentComplete || 0
updateProgressBar(percentComplete)
return (
<View>
<InfoToast {...props} style={styles(props.props).info} />
{props.props?.percentComplete !== undefined ? (
<View style={[styles(props.props).animatedViewContainer]}>
<Animated.View
style={[
StyleSheet.absoluteFill,
{
...styles(props.props).animatedView,
width: progressBarWidth,
},
]}
/>
</View>
) : null}
</View>
)
},
success: props => {
const percentComplete = props.props?.percentComplete || 0
updateProgressBar(percentComplete)
return <SuccessToast {...props} style={styles(props.props).success} />
},
error: props => {
const percentComplete = props.props?.percentComplete || 0
updateProgressBar(percentComplete)
return <ErrorToast {...props} style={styles(props.props).error} />
},
}
return <Toast config={toastStyles} />
}

View File

@@ -0,0 +1,3 @@
{
"name": "@Components"
}