├── .eslintrc.js
├── .gitignore
├── .prettierrc.json
├── .vscode
└── settings.json
├── apps
├── expo
│ ├── .gitignore
│ ├── app-env.d.ts
│ ├── app.config.ts
│ ├── app
│ │ ├── (tabs).tsx
│ │ └── (tabs)
│ │ │ ├── (home).tsx
│ │ │ ├── (home)
│ │ │ └── index.tsx
│ │ │ ├── account.tsx
│ │ │ ├── menus.tsx
│ │ │ ├── menus
│ │ │ ├── index.tsx
│ │ │ ├── tweet.tsx
│ │ │ └── twitter.tsx
│ │ │ ├── users.tsx
│ │ │ └── users
│ │ │ ├── [id].tsx
│ │ │ └── index.tsx
│ ├── babel.config.js
│ ├── google
│ │ ├── GoogleService-Info.plist
│ │ └── google-services.json
│ ├── index.js
│ ├── metro.config.js
│ ├── package.json
│ ├── src
│ │ └── stack.tsx
│ └── tsconfig.json
└── next
│ ├── .babelrc.json
│ ├── .gitignore
│ ├── app-env.d.ts
│ ├── next-env.d.ts
│ ├── next.config.js
│ ├── package.json
│ ├── pages
│ ├── _app.tsx
│ ├── _document.tsx
│ ├── account.tsx
│ ├── index.tsx
│ ├── menus
│ │ └── twitter
│ │ │ └── index.tsx
│ └── users
│ │ ├── [id].tsx
│ │ └── index.tsx
│ ├── public
│ ├── favicon.ico
│ ├── feed-web.png
│ └── vercel.svg
│ └── tsconfig.json
├── package.json
├── packages
└── app
│ ├── features
│ ├── auth
│ │ ├── context
│ │ │ └── index.tsx
│ │ ├── firebase
│ │ │ ├── index.native.ts
│ │ │ ├── index.ts
│ │ │ ├── init.native.ts
│ │ │ ├── init.web.ts
│ │ │ └── types.ts
│ │ ├── gate
│ │ │ └── index.tsx
│ │ └── my-account
│ │ │ └── screen.tsx
│ ├── home
│ │ └── screen.tsx
│ ├── menu
│ │ ├── list-screen.tsx
│ │ └── twitter
│ │ │ ├── assets
│ │ │ ├── feed.png
│ │ │ ├── list-item.png
│ │ │ ├── preview.png
│ │ │ └── tweet-detail.jpeg
│ │ │ ├── feed.tsx
│ │ │ ├── feed.web.tsx
│ │ │ └── tweet.tsx
│ └── user
│ │ ├── detail-screen.tsx
│ │ └── list-screen.tsx
│ ├── layout
│ └── web
│ │ └── index.tsx
│ ├── package.json
│ ├── provider
│ ├── dripsy.tsx
│ └── index.tsx
│ └── rnw-overrides.d.ts
├── readme.md
├── tsconfig.json
├── turbo.json
└── yarn.lock
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: 'next',
3 | settings: {
4 | next: {
5 | rootDir: 'apps/next/',
6 | },
7 | },
8 | root: true,
9 | }
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 |
33 | # node.js
34 | #
35 | node_modules/
36 | npm-debug.log
37 | yarn-error.log
38 |
39 | # BUCK
40 | buck-out/
41 | \.buckd/
42 | *.keystore
43 |
44 | # fastlane
45 | #
46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
47 | # screenshots whenever they are needed.
48 | # For more information about the recommended setup visit:
49 | # https://docs.fastlane.tools/best-practices/source-control/
50 |
51 | */fastlane/report.xml
52 | */fastlane/Preview.html
53 | */fastlane/screenshots
54 |
55 | # Bundle artifacts
56 | *.jsbundle
57 |
58 | # CocoaPods
59 | /ios/Pods/
60 |
61 | # Expo
62 | .expo/*
63 | web-build/
64 |
65 | **/*/.expo
66 |
67 | **/*/.next
68 |
69 | **/*/ios
70 | **/*/android
71 |
72 | .turbo
73 | build/**
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "useTabs": false,
4 | "tabWidth": 2,
5 | "singleQuote": true
6 | }
7 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib"
3 | }
4 |
--------------------------------------------------------------------------------
/apps/expo/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | project.xcworkspace
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 | *.hprof
33 |
34 | # node.js
35 | #
36 | node_modules/
37 | npm-debug.log
38 | yarn-error.log
39 |
40 | # BUCK
41 | buck-out/
42 | \.buckd/
43 | *.keystore
44 |
45 | # fastlane
46 | #
47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
48 | # screenshots whenever they are needed.
49 | # For more information about the recommended setup visit:
50 | # https://docs.fastlane.tools/best-practices/source-control/
51 |
52 | */fastlane/report.xml
53 | */fastlane/Preview.html
54 | */fastlane/screenshots
55 |
56 | # Bundle artifacts
57 | *.jsbundle
58 |
59 | # CocoaPods
60 | /ios/Pods/
61 |
62 | # Expo
63 | .expo/*
64 | web-build/
65 |
66 | # @generated expo-cli sync-e7dcf75f4e856f7b6f3239b3f3a7dd614ee755a8
67 | # The following patterns were generated by expo-cli
68 |
69 | # OSX
70 | #
71 | .DS_Store
72 |
73 | # Xcode
74 | #
75 | build/
76 | *.pbxuser
77 | !default.pbxuser
78 | *.mode1v3
79 | !default.mode1v3
80 | *.mode2v3
81 | !default.mode2v3
82 | *.perspectivev3
83 | !default.perspectivev3
84 | xcuserdata
85 | *.xccheckout
86 | *.moved-aside
87 | DerivedData
88 | *.hmap
89 | *.ipa
90 | *.xcuserstate
91 | project.xcworkspace
92 |
93 | # Android/IntelliJ
94 | #
95 | build/
96 | .idea
97 | .gradle
98 | local.properties
99 | *.iml
100 | *.hprof
101 |
102 | # node.js
103 | #
104 | node_modules/
105 | npm-debug.log
106 | yarn-error.log
107 |
108 | # BUCK
109 | buck-out/
110 | \.buckd/
111 | *.keystore
112 | !debug.keystore
113 |
114 | # Bundle artifacts
115 | *.jsbundle
116 |
117 | # CocoaPods
118 | /ios/Pods/
119 |
120 | # Expo
121 | .expo/
122 | web-build/
123 | dist/
124 |
125 | # @end expo-cli
--------------------------------------------------------------------------------
/apps/expo/app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/apps/expo/app.config.ts:
--------------------------------------------------------------------------------
1 | import { ExpoConfig } from '@expo/config'
2 |
3 | // you can delete this function once you add your own google creds
4 | const checkIfAndroidConfigIsUpdated = () => {
5 | const android = require('./google/google-services.json')
6 |
7 | if (android.project_info.project_number == '960783729432') {
8 | console.warn(`You need to add your own Firebase credentials. Make sure you edit the following:
9 |
10 | - apps/expo/google/google-services.json
11 | - apps/expo/google/GoogleService-Info.plist
12 | - packages/app/features/auth/firebase/init.web.ts
13 |
14 | `)
15 | }
16 | }
17 | checkIfAndroidConfigIsUpdated()
18 |
19 | export default {
20 | name: 'solito-next-conf',
21 | slug: 'solito-next-conf',
22 | version: '1.0.0',
23 | scheme: 'solito-next-conf',
24 | platforms: ['ios', 'android'],
25 | ios: {
26 | bundleIdentifier: 'com.solito.next-conf',
27 | googleServicesFile: './google/GoogleService-Info.plist',
28 | },
29 | android: {
30 | package: 'com.solito.nextconf',
31 | googleServicesFile: './google/google-services.json',
32 | },
33 | plugins: ['@react-native-firebase/app'],
34 | } as ExpoConfig
35 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs).tsx:
--------------------------------------------------------------------------------
1 | import { Provider } from 'app/provider'
2 | import { StatusBar } from 'expo-status-bar'
3 | import { Tabs } from 'expo-router'
4 | import { useDripsyTheme } from 'dripsy'
5 | import { Ionicons } from '@expo/vector-icons'
6 | import { useAuth } from 'app/features/auth/context'
7 |
8 | function MyTabs() {
9 | const { colors } = useDripsyTheme().theme
10 | const auth = useAuth()
11 |
12 | return (
13 |
23 |
34 | )
35 | },
36 | }}
37 | />
38 |
49 | )
50 | },
51 | tabBarButton: auth ? undefined : () => null,
52 | }}
53 | />
54 |
65 | )
66 | },
67 | }}
68 | />
69 |
80 | )
81 | },
82 | tabBarStyle: {
83 | display: 'none',
84 | },
85 | }}
86 | />
87 |
88 | )
89 | }
90 |
91 | export default function Root() {
92 | return (
93 |
94 |
95 |
96 |
97 | )
98 | }
99 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs)/(home).tsx:
--------------------------------------------------------------------------------
1 | import { useDripsyTheme } from 'dripsy'
2 | import { Stack } from '../../src/stack'
3 |
4 | export default function HomeTab({ children }) {
5 | return (
6 |
7 |
13 |
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs)/(home)/index.tsx:
--------------------------------------------------------------------------------
1 | import { HomeScreen } from 'app/features/home/screen'
2 |
3 | export default HomeScreen
4 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs)/account.tsx:
--------------------------------------------------------------------------------
1 | export { default } from 'app/features/auth/my-account/screen'
2 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs)/menus.tsx:
--------------------------------------------------------------------------------
1 | import { Stack } from '../../src/stack'
2 |
3 | export default function MenusStack() {
4 | return (
5 |
10 |
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs)/menus/index.tsx:
--------------------------------------------------------------------------------
1 | export { MenuListScreen as default } from 'app/features/menu/list-screen'
2 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs)/menus/tweet.tsx:
--------------------------------------------------------------------------------
1 | export { default } from 'app/features/menu/twitter/tweet'
2 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs)/menus/twitter.tsx:
--------------------------------------------------------------------------------
1 | export { default } from 'app/features/menu/twitter/feed'
2 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs)/users.tsx:
--------------------------------------------------------------------------------
1 | import { useDripsyTheme } from 'dripsy'
2 | import { Stack } from '../../src/stack'
3 |
4 | export default function UserTab({ children }) {
5 | return (
6 |
7 |
13 |
19 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs)/users/[id].tsx:
--------------------------------------------------------------------------------
1 | import { UserDetailScreen } from 'app/features/user/detail-screen'
2 |
3 | export default UserDetailScreen
4 |
--------------------------------------------------------------------------------
/apps/expo/app/(tabs)/users/index.tsx:
--------------------------------------------------------------------------------
1 | export { default } from 'app/features/user/list-screen'
2 |
--------------------------------------------------------------------------------
/apps/expo/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true)
3 | return {
4 | presets: [['babel-preset-expo', { jsxRuntime: 'automatic' }]],
5 | plugins: [
6 | 'react-native-reanimated/plugin',
7 | // https://expo.github.io/router/docs/intro#configure-the-babel-plugin
8 | require.resolve('expo-router/babel'),
9 | ],
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/apps/expo/google/GoogleService-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CLIENT_ID
6 | 960783729432-oi7vjohmsjmmchok1410771rakkpkh6m.apps.googleusercontent.com
7 | REVERSED_CLIENT_ID
8 | com.googleusercontent.apps.960783729432-oi7vjohmsjmmchok1410771rakkpkh6m
9 | API_KEY
10 | AIzaSyD_YOZWJkoezJ5lYJUnhg0xrACJRe6neFQ
11 | GCM_SENDER_ID
12 | 960783729432
13 | PLIST_VERSION
14 | 1
15 | BUNDLE_ID
16 | com.solito.next-conf
17 | PROJECT_ID
18 | solito-example
19 | STORAGE_BUCKET
20 | solito-example.appspot.com
21 | IS_ADS_ENABLED
22 |
23 | IS_ANALYTICS_ENABLED
24 |
25 | IS_APPINVITE_ENABLED
26 |
27 | IS_GCM_ENABLED
28 |
29 | IS_SIGNIN_ENABLED
30 |
31 | GOOGLE_APP_ID
32 | 1:960783729432:ios:65ff683ec3df1446b3146d
33 |
34 |
--------------------------------------------------------------------------------
/apps/expo/google/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "960783729432",
4 | "project_id": "solito-example",
5 | "storage_bucket": "solito-example.appspot.com"
6 | },
7 | "client": [
8 | {
9 | "client_info": {
10 | "mobilesdk_app_id": "1:960783729432:android:df8aeb26500d4a79b3146d",
11 | "android_client_info": {
12 | "package_name": "com.solito.nextconf"
13 | }
14 | },
15 | "oauth_client": [
16 | {
17 | "client_id": "960783729432-d9gs06vgugdegpjraa5mb6hclntu68tq.apps.googleusercontent.com",
18 | "client_type": 3
19 | }
20 | ],
21 | "api_key": [
22 | {
23 | "current_key": "AIzaSyAqPvxTjO2tkgNzYjXeq1h_wAh9XUAdhFs"
24 | }
25 | ],
26 | "services": {
27 | "appinvite_service": {
28 | "other_platform_oauth_client": [
29 | {
30 | "client_id": "960783729432-d9gs06vgugdegpjraa5mb6hclntu68tq.apps.googleusercontent.com",
31 | "client_type": 3
32 | },
33 | {
34 | "client_id": "960783729432-oi7vjohmsjmmchok1410771rakkpkh6m.apps.googleusercontent.com",
35 | "client_type": 2,
36 | "ios_info": {
37 | "bundle_id": "com.solito.next-conf"
38 | }
39 | }
40 | ]
41 | }
42 | }
43 | }
44 | ],
45 | "configuration_version": "1"
46 | }
--------------------------------------------------------------------------------
/apps/expo/index.js:
--------------------------------------------------------------------------------
1 | import 'expo-router/entry'
2 |
--------------------------------------------------------------------------------
/apps/expo/metro.config.js:
--------------------------------------------------------------------------------
1 | // Learn more https://docs.expo.io/guides/customizing-metro
2 | /**
3 | * @type {import('expo/metro-config')}
4 | */
5 | const { getDefaultConfig } = require('expo/metro-config')
6 | const path = require('path')
7 |
8 | const projectRoot = __dirname
9 | const workspaceRoot = path.resolve(__dirname, '../..')
10 |
11 | const config = getDefaultConfig(projectRoot)
12 |
13 | config.watchFolders = [workspaceRoot]
14 | config.resolver.nodeModulesPaths = [
15 | path.resolve(projectRoot, 'node_modules'),
16 | path.resolve(workspaceRoot, 'node_modules'),
17 | ]
18 |
19 | module.exports = config
20 |
--------------------------------------------------------------------------------
/apps/expo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@react-native-firebase/app": "~14.9.1",
4 | "@react-native-firebase/auth": "~14.9.1",
5 | "@react-native-menu/menu": "^0.5.3",
6 | "app": "*",
7 | "expo": "~46.0.13",
8 | "expo-router": "^0.0.25",
9 | "expo-splash-screen": "~0.16.2",
10 | "expo-status-bar": "~1.4.0",
11 | "react": "18.0.0",
12 | "react-dom": "18.0.0",
13 | "react-native": "0.69.6",
14 | "react-native-gesture-handler": "~2.5.0",
15 | "react-native-ios-context-menu": "^1.14.0",
16 | "react-native-reanimated": "2.9.1",
17 | "react-native-safe-area-context": "4.3.1",
18 | "react-native-screens": "~3.15.0",
19 | "react-native-web": "~0.18.7"
20 | },
21 | "devDependencies": {
22 | "@babel/core": "^7.18.6",
23 | "@types/react": "~18.0.0",
24 | "@types/react-native": "~0.69.1",
25 | "typescript": "^4.6.3"
26 | },
27 | "scripts": {
28 | "start": "expo start --dev-client",
29 | "android": "expo run:android",
30 | "ios": "expo run:ios"
31 | },
32 | "version": "1.0.0",
33 | "private": true,
34 | "name": "expo-app"
35 | }
36 |
--------------------------------------------------------------------------------
/apps/expo/src/stack.tsx:
--------------------------------------------------------------------------------
1 | import { NativeStack } from 'expo-router'
2 | import { useDripsyTheme } from 'dripsy'
3 |
4 | export function Stack({
5 | children,
6 | ...props
7 | }: React.ComponentProps) {
8 | const { colors } = useDripsyTheme().theme
9 | return (
10 |
24 | {children}
25 |
26 | )
27 | }
28 |
29 | Stack.Screen = NativeStack.Screen
30 |
--------------------------------------------------------------------------------
/apps/expo/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig"
3 | }
4 |
--------------------------------------------------------------------------------
/apps/next/.babelrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "next/babel",
4 | ["babel-preset-expo", { "jsxRuntime": "automatic" }]
5 | ],
6 | "plugins": [
7 | ["@babel/plugin-proposal-class-properties", { "loose": true }],
8 | ["@babel/plugin-proposal-private-methods", { "loose": true }],
9 | ["@babel/plugin-proposal-private-property-in-object", { "loose": true }],
10 | "react-native-reanimated/plugin"
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/apps/next/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env.local
30 | .env.development.local
31 | .env.test.local
32 | .env.production.local
33 |
34 | # vercel
35 | .vercel
36 |
37 | # typescript
38 | *.tsbuildinfo
39 |
--------------------------------------------------------------------------------
/apps/next/app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/apps/next/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/apps/next/next.config.js:
--------------------------------------------------------------------------------
1 | const { withExpo } = require('@expo/next-adapter')
2 | const withFonts = require('next-fonts')
3 | const withImages = require('next-images')
4 | const withPlugins = require('next-compose-plugins')
5 | const withTM = require('next-transpile-modules')([
6 | 'solito',
7 | 'dripsy',
8 | '@dripsy/core',
9 | 'moti',
10 | 'app',
11 | 'zeego',
12 | ])
13 |
14 | /** @type {import('next').NextConfig} */
15 | const nextConfig = {
16 | // reanimated (and thus, Moti) doesn't work with strict mode currently...
17 | // https://github.com/nandorojo/moti/issues/224
18 | // https://github.com/necolas/react-native-web/pull/2330
19 | // https://github.com/nandorojo/moti/issues/224
20 | // once that gets fixed, set this back to true
21 | reactStrictMode: false,
22 | webpack5: true,
23 | images: {
24 | disableStaticImages: true,
25 | },
26 | }
27 |
28 | const transform = withPlugins([withTM, withFonts, withImages, withExpo])
29 |
30 | module.exports = function (name, { defaultConfig }) {
31 | return transform(name, {
32 | ...defaultConfig,
33 | ...nextConfig,
34 | })
35 | }
36 |
--------------------------------------------------------------------------------
/apps/next/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@expo/next-adapter": "^4.0.12",
13 | "app": "*",
14 | "next": "^12.2.5",
15 | "raf": "^3.4.1"
16 | },
17 | "devDependencies": {
18 | "@types/node": "17.0.21",
19 | "eslint-config-next": "12.2.5",
20 | "next-compose-plugins": "^2.2.1",
21 | "next-fonts": "^1.5.1",
22 | "next-images": "^1.8.4",
23 | "next-transpile-modules": "^9.0.0"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/apps/next/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import 'raf/polyfill'
2 | import { WebLayout } from 'app/layout/web'
3 |
4 | const fixReanimatedIssue = () => {
5 | // FIXME remove this once this reanimated fix gets released
6 | // https://github.com/software-mansion/react-native-reanimated/issues/3355
7 | if (process.browser) {
8 | // @ts-ignore
9 | window._frameTimestamp = null
10 | }
11 | }
12 |
13 | fixReanimatedIssue()
14 |
15 | import { Provider } from 'app/provider'
16 | import Head from 'next/head'
17 | import React from 'react'
18 | import type { SolitoAppProps } from 'solito'
19 |
20 | function MyApp({ Component, pageProps }: SolitoAppProps) {
21 | return (
22 | <>
23 |
24 | Solito Example App
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | >
37 | )
38 | }
39 |
40 | export default MyApp
41 |
--------------------------------------------------------------------------------
/apps/next/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | export { default } from '@expo/next-adapter/document'
2 |
--------------------------------------------------------------------------------
/apps/next/pages/account.tsx:
--------------------------------------------------------------------------------
1 | export { default } from 'app/features/auth/my-account/screen'
2 |
--------------------------------------------------------------------------------
/apps/next/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { HomeScreen } from 'app/features/home/screen'
2 |
3 | export default HomeScreen
4 |
--------------------------------------------------------------------------------
/apps/next/pages/menus/twitter/index.tsx:
--------------------------------------------------------------------------------
1 | export { default } from 'app/features/menu/twitter/feed'
2 |
--------------------------------------------------------------------------------
/apps/next/pages/users/[id].tsx:
--------------------------------------------------------------------------------
1 | import { UserDetailScreen } from 'app/features/user/detail-screen'
2 |
3 | export default UserDetailScreen
4 |
--------------------------------------------------------------------------------
/apps/next/pages/users/index.tsx:
--------------------------------------------------------------------------------
1 | export { default } from 'app/features/user/list-screen'
2 |
--------------------------------------------------------------------------------
/apps/next/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nandorojo/nextjs-conf-22-example/3701060984b9aef7d277eeeb80328ae8a25d366f/apps/next/public/favicon.ico
--------------------------------------------------------------------------------
/apps/next/public/feed-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nandorojo/nextjs-conf-22-example/3701060984b9aef7d277eeeb80328ae8a25d366f/apps/next/public/feed-web.png
--------------------------------------------------------------------------------
/apps/next/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/apps/next/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true
17 | },
18 | "include": ["next-env.d.ts", "app-env.d.ts", "**/*.ts", "**/*.tsx"],
19 | "exclude": ["node_modules"]
20 | }
21 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "solito-expo-router",
3 | "private": true,
4 | "workspaces": [
5 | "apps/*",
6 | "packages/*"
7 | ],
8 | "devDependencies": {
9 | "@types/react": "^18.0.17",
10 | "@types/react-native": "^0.69.5",
11 | "eslint": "^8.21.0",
12 | "turbo": "^1.4.2"
13 | },
14 | "scripts": {
15 | "native": "cd apps/expo && expo start",
16 | "web": "cd apps/next && yarn next"
17 | },
18 | "resolutions": {
19 | "metro": "0.72.3",
20 | "typescript": "~4.4"
21 | },
22 | "nohoist": [
23 | "**/expo-router",
24 | "**/expo-router/**"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/packages/app/features/auth/context/index.tsx:
--------------------------------------------------------------------------------
1 | import { createContext, useContext, useSyncExternalStore } from 'react'
2 | import { getCurrentUser, onAuthStateChanged } from '../firebase'
3 | import { Firebase } from '../firebase/types'
4 |
5 | const AuthContext = createContext(null)
6 |
7 | export function AuthProvider({
8 | children,
9 | ...props
10 | }: {
11 | children: React.ReactNode
12 | onAuthStateChanged?: Parameters[0]
13 | }) {
14 | const store = useSyncExternalStore(
15 | (callback) => {
16 | const remove = onAuthStateChanged((user) => {
17 | callback()
18 | props.onAuthStateChanged?.(user)
19 | })
20 |
21 | return () => remove()
22 | },
23 | getCurrentUser,
24 | () => null
25 | )
26 |
27 | return {children}
28 | }
29 |
30 | export function useAuth() {
31 | return useContext(AuthContext)
32 | }
33 |
--------------------------------------------------------------------------------
/packages/app/features/auth/firebase/index.native.ts:
--------------------------------------------------------------------------------
1 | import Constants from 'expo-constants'
2 | import { Firebase } from './types'
3 |
4 | const isExpoGo = Constants.appOwnership == 'expo'
5 |
6 | let exports: Firebase
7 |
8 | // here we check if the user has properly set up their native app
9 | // if not, we fall back to firebase JS
10 |
11 | if (isExpoGo) {
12 | exports = require('./init.web')
13 | } else {
14 | exports = require('./init.native')
15 | }
16 |
17 | module.exports = exports
18 |
--------------------------------------------------------------------------------
/packages/app/features/auth/firebase/index.ts:
--------------------------------------------------------------------------------
1 | export * from './init.web'
2 |
--------------------------------------------------------------------------------
/packages/app/features/auth/firebase/init.native.ts:
--------------------------------------------------------------------------------
1 | import auth from '@react-native-firebase/auth'
2 | import { Firebase } from './types'
3 |
4 | const getIsSignedIn: Firebase['getIsSignedIn'] = () =>
5 | Boolean(auth().currentUser)
6 |
7 | const signOut: Firebase['signOut'] = () => auth().signOut()
8 |
9 | const signInAnonymously: Firebase['signInAnonymously'] = async () => {
10 | return (await auth().signInAnonymously()).user
11 | }
12 |
13 | const onAuthStateChanged: Firebase['onAuthStateChanged'] = (callback) => {
14 | return auth().onAuthStateChanged(callback)
15 | }
16 |
17 | const getCurrentUser: Firebase['getCurrentUser'] = () => auth().currentUser
18 |
19 | export {
20 | getIsSignedIn,
21 | signOut,
22 | signInAnonymously,
23 | onAuthStateChanged,
24 | getCurrentUser,
25 | }
26 |
--------------------------------------------------------------------------------
/packages/app/features/auth/firebase/init.web.ts:
--------------------------------------------------------------------------------
1 | // please note that firebase auth adds about 30kb to your bundle size on Web
2 | import { initializeApp } from 'firebase/app'
3 | import {
4 | initializeAuth,
5 | browserPopupRedirectResolver,
6 | browserLocalPersistence,
7 | signInAnonymously as signInAnonymouslyFirebase,
8 | onAuthStateChanged as onAuthStateChangedFirebase,
9 | } from 'firebase/auth'
10 | import { Firebase } from './types'
11 |
12 | let auth: ReturnType
13 |
14 | if (typeof window !== 'undefined') {
15 | const firebaseApp = initializeApp({
16 | apiKey: 'AIzaSyAQZ1A-bJMQqjdzNQhRPkbA7swEFnwUS_w',
17 | authDomain: 'solito-example.firebaseapp.com',
18 | projectId: 'solito-example',
19 | storageBucket: 'solito-example.appspot.com',
20 | messagingSenderId: '960783729432',
21 | appId: '1:960783729432:web:f2052cb298f0fc7bb3146d',
22 | })
23 |
24 | auth = initializeAuth(firebaseApp, {
25 | persistence: browserLocalPersistence,
26 | })
27 | }
28 |
29 | const getIsSignedIn: Firebase['getIsSignedIn'] = () =>
30 | Boolean(auth?.currentUser)
31 |
32 | const signOut: Firebase['signOut'] = () => auth.signOut()
33 |
34 | const signInAnonymously: Firebase['signInAnonymously'] = async () => {
35 | return (await signInAnonymouslyFirebase(auth)).user
36 | }
37 |
38 | const onAuthStateChanged: Firebase['onAuthStateChanged'] = (callback) => {
39 | return onAuthStateChangedFirebase(auth, callback)
40 | }
41 |
42 | const getCurrentUser: Firebase['getCurrentUser'] = () => auth.currentUser
43 |
44 | export {
45 | getIsSignedIn,
46 | signInAnonymously,
47 | signOut,
48 | onAuthStateChanged,
49 | getCurrentUser,
50 | }
51 |
--------------------------------------------------------------------------------
/packages/app/features/auth/firebase/types.ts:
--------------------------------------------------------------------------------
1 | import type * as firebase from 'firebase/auth'
2 |
3 | type User = Pick
4 |
5 | export type Firebase = {
6 | getIsSignedIn: () => boolean
7 | signInAnonymously: () => Promise
8 | signOut: () => Promise
9 | onAuthStateChanged: (
10 | callback: (user: { uid: string } | null) => void
11 | ) => () => void
12 | getCurrentUser: () => User | null
13 | }
14 |
--------------------------------------------------------------------------------
/packages/app/features/auth/gate/index.tsx:
--------------------------------------------------------------------------------
1 | import { Text, View } from '@dripsy/core'
2 | import { useAuth } from '../context'
3 | import { signInAnonymously } from '../firebase'
4 |
5 | export function AuthGate({
6 | children,
7 | }: {
8 | children: React.ReactNode | ((user: { uid: string }) => React.ReactNode)
9 | }) {
10 | const auth = useAuth()
11 |
12 | if (!auth) {
13 | return (
14 | <>
15 |
23 | Sign In
24 |
25 | >
26 | )
27 | }
28 |
29 | return <>{typeof children == 'function' ? children(auth) : children}>
30 | }
31 |
--------------------------------------------------------------------------------
/packages/app/features/auth/my-account/screen.tsx:
--------------------------------------------------------------------------------
1 | import { Text, View } from 'dripsy'
2 | import { signOut } from '../firebase'
3 | import { AuthGate } from '../gate'
4 |
5 | export default function MyAccountScreen() {
6 | return (
7 |
8 | {({ uid }) => (
9 |
17 | Welcome, {uid}.
18 |
19 | Sign Out
20 |
21 |
22 | )}
23 |
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/packages/app/features/home/screen.tsx:
--------------------------------------------------------------------------------
1 | import { Text, View } from 'dripsy'
2 | import { Link } from 'solito/link'
3 |
4 | export function HomeScreen() {
5 | return (
6 |
14 |
15 |
22 | Hello Solito
23 |
24 |
25 |
26 | )
27 | }
28 |
--------------------------------------------------------------------------------
/packages/app/features/menu/list-screen.tsx:
--------------------------------------------------------------------------------
1 | import { View, Text } from 'dripsy'
2 | import { Link } from 'solito/link'
3 | import { Fragment } from 'react'
4 | import { Ionicons } from '@expo/vector-icons'
5 |
6 | const menus = [
7 | {
8 | name: 'Twitter',
9 | href: '/menus/twitter',
10 | icon: ,
11 | },
12 | ]
13 |
14 | export function MenuListScreen() {
15 | return (
16 |
17 | {menus.map((menu) => (
18 |
19 |
20 |
29 | {menu.icon}
30 | {menu.name}
31 |
32 |
33 |
34 | ))}
35 |
36 | )
37 | }
38 |
--------------------------------------------------------------------------------
/packages/app/features/menu/twitter/assets/feed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nandorojo/nextjs-conf-22-example/3701060984b9aef7d277eeeb80328ae8a25d366f/packages/app/features/menu/twitter/assets/feed.png
--------------------------------------------------------------------------------
/packages/app/features/menu/twitter/assets/list-item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nandorojo/nextjs-conf-22-example/3701060984b9aef7d277eeeb80328ae8a25d366f/packages/app/features/menu/twitter/assets/list-item.png
--------------------------------------------------------------------------------
/packages/app/features/menu/twitter/assets/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nandorojo/nextjs-conf-22-example/3701060984b9aef7d277eeeb80328ae8a25d366f/packages/app/features/menu/twitter/assets/preview.png
--------------------------------------------------------------------------------
/packages/app/features/menu/twitter/assets/tweet-detail.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nandorojo/nextjs-conf-22-example/3701060984b9aef7d277eeeb80328ae8a25d366f/packages/app/features/menu/twitter/assets/tweet-detail.jpeg
--------------------------------------------------------------------------------
/packages/app/features/menu/twitter/feed.tsx:
--------------------------------------------------------------------------------
1 | import { Image as Img, View } from '@dripsy/core'
2 | import { StatusBar, useWindowDimensions } from 'react-native'
3 | import { Link } from 'solito/link'
4 | import { useRouter } from 'solito/router'
5 |
6 | import * as ContextMenu from 'zeego/context-menu'
7 |
8 | export default function TwitterFeed() {
9 | const { push } = useRouter()
10 | return (
11 | <>
12 |
13 | (
15 |
16 |
17 |
18 |
19 |
20 |
21 | push('/menus/tweet')}>
22 | {() => }
23 |
24 |
25 | Delete Tweet
26 |
27 |
28 |
29 |
30 |
31 | Unpin from profile
32 |
33 |
34 |
35 |
36 |
37 |
38 | Change who can reply
39 |
40 |
41 |
42 |
43 |
44 |
45 | Add/remove from Lists
46 |
47 |
48 |
49 |
50 |
51 | )}
52 | />
53 | >
54 | )
55 | }
56 |
57 | const Feed = ({ renderTweet }: { renderTweet: () => JSX.Element }) => {
58 | const { width, height } = useWindowDimensions()
59 | return (
60 | <>
61 |
71 | {renderTweet()}
72 | >
73 | )
74 | }
75 |
76 | function Tweet() {
77 | const { width, height } = useWindowDimensions()
78 | return (
79 |
80 |
85 |
86 | )
87 | }
88 |
89 | function TweetPreview() {
90 | const { width } = useWindowDimensions()
91 | return (
92 |
100 | )
101 | }
102 |
--------------------------------------------------------------------------------
/packages/app/features/menu/twitter/feed.web.tsx:
--------------------------------------------------------------------------------
1 | import { View, Image as Img, styled } from 'dripsy'
2 | import { Platform } from 'react-native'
3 | import { Ionicons } from '@expo/vector-icons'
4 |
5 | import * as ContextMenu from 'zeego/context-menu'
6 |
7 | const Item = ContextMenu.menuify(
8 | styled(function Item(
9 | props: React.ComponentProps
10 | ) {
11 | return
12 | })({
13 | height: 52,
14 | padding: '$3',
15 | flexDirection: 'row-reverse',
16 | alignItems: 'center',
17 | justifyContent: 'flex-end',
18 | }),
19 | 'Item'
20 | )
21 |
22 | const Content = ContextMenu.menuify(
23 | styled((props: React.ComponentProps) => {
24 | return
25 | })({
26 | bg: 'black',
27 | ...Platform.select({
28 | web: {
29 | // twitter dark mode shadow
30 | boxShadow:
31 | 'rgb(255 255 255 / 20%) 0px 0px 15px, rgb(255 255 255 / 15%) 0px 0px 3px 1px',
32 | animationDuration: '400ms',
33 | animationTimingFunction: 'cubic-bezier(0.16, 1, 0.3, 1)',
34 | willChange: 'transform, opacity',
35 | animationKeyframes: {
36 | '0%': { opacity: 0, transform: [{ scale: 0.5 }] },
37 | '100%': { opacity: 1, transform: [{ scale: 1 }] },
38 | },
39 | transformOrigin: 'var(--radix-context-menu-content-transform-origin)',
40 | },
41 | }),
42 | borderRadius: '$3',
43 | }),
44 | 'Content'
45 | )
46 |
47 | const ItemTitle = ContextMenu.menuify(
48 | styled((props: React.ComponentProps) => {
49 | return
50 | })(({ destructive }: { destructive?: boolean }) => ({
51 | color: destructive ? 'rgb(244, 33, 46)' : 'white',
52 | })),
53 | 'ItemTitle'
54 | )
55 |
56 | const ItemIcon = ContextMenu.menuify(
57 | styled(
58 | (
59 | props: React.ComponentProps &
60 | Pick, 'name'> & {
61 | destructive?: boolean
62 | }
63 | ) => {
64 | return (
65 |
66 |
73 |
74 | )
75 | }
76 | )({
77 | mr: '$3',
78 | }),
79 | 'ItemIcon'
80 | )
81 |
82 | export default function TwitterFeedWeb() {
83 | return (
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | -
92 |
93 | Delete Tweet
94 |
95 |
96 | -
97 |
98 | Unpin from profile
99 |
100 |
101 | -
102 |
103 | Change who can reply
104 |
105 |
106 | -
107 |
108 | Add/remove from Lists
109 |
110 |
111 |
112 |
113 | )
114 | }
115 |
116 | function Tweet() {
117 | return (
118 |
127 | )
128 | }
129 |
--------------------------------------------------------------------------------
/packages/app/features/menu/twitter/tweet.tsx:
--------------------------------------------------------------------------------
1 | import { Image as Img, StatusBar } from 'react-native'
2 |
3 | const tweet = require('./assets/tweet-detail.jpeg')
4 |
5 | export default function Tweet() {
6 | return (
7 | <>
8 |
12 |
13 |
14 | >
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app/features/user/detail-screen.tsx:
--------------------------------------------------------------------------------
1 | import { View, Text } from 'dripsy'
2 | import { createParam } from 'solito'
3 | import { Link } from 'solito/link'
4 |
5 | const { useParam } = createParam<{ id: string }>()
6 |
7 | export function UserDetailScreen() {
8 | const [id] = useParam('id')
9 |
10 | return (
11 |
19 |
20 | {id}
21 |
22 |
23 | )
24 | }
25 |
--------------------------------------------------------------------------------
/packages/app/features/user/list-screen.tsx:
--------------------------------------------------------------------------------
1 | import { View, Image, ScrollView, Text } from 'dripsy'
2 | import { Link } from 'solito/link'
3 | import { Fragment } from 'react'
4 | import { AuthGate } from '../auth/gate'
5 |
6 | const users = [
7 | {
8 | id: 'Guillermo Rauch',
9 | avatar:
10 | 'https://pbs.twimg.com/profile_images/1576257734810312704/ucxb4lHy_400x400.jpg',
11 | },
12 | {
13 | id: 'Charlie Cheever',
14 | avatar:
15 | 'https://pbs.twimg.com/profile_images/418503340872306688/cwVZFE3e_400x400.jpeg',
16 | },
17 | {
18 | id: 'Fernando Rojo',
19 | avatar:
20 | 'https://pbs.twimg.com/profile_images/1182392379761987591/9XPy4NfP_400x400.jpg',
21 | },
22 | {
23 | id: 'Evan Bacon',
24 | avatar:
25 | 'https://pbs.twimg.com/profile_images/1576625400205250561/wGfn72X__400x400.jpg',
26 | },
27 | ]
28 |
29 | export default function UsersListScreen() {
30 | return (
31 |
32 |
33 |
36 | {users.map((user) => {
37 | return (
38 |
39 |
40 |
46 |
58 |
59 |
60 |
61 | {user.id}
62 |
63 |
64 |
65 |
66 |
67 | )
68 | })}
69 |
70 |
71 |
72 | )
73 | }
74 |
--------------------------------------------------------------------------------
/packages/app/layout/web/index.tsx:
--------------------------------------------------------------------------------
1 | import { useAuth } from 'app/features/auth/context'
2 | import { View, Text, A } from 'dripsy'
3 | import { useRouter } from 'next/router'
4 | import { Fragment } from 'react'
5 | import { Link } from 'solito/link'
6 |
7 | const tabs: Array<{
8 | pathname: string
9 | isActive(pathname: string): boolean
10 | name: string
11 | protected?: boolean
12 | }> = [
13 | {
14 | pathname: '/',
15 | isActive: (pathname) => pathname === '/',
16 | name: 'Home',
17 | },
18 | {
19 | pathname: '/users',
20 | isActive: (pathname) => pathname.startsWith('/users'),
21 | name: 'Users',
22 | protected: true,
23 | },
24 | {
25 | pathname: '/account',
26 | isActive: (pathname) => pathname.startsWith('/account'),
27 | name: 'My Account',
28 | },
29 | ]
30 |
31 | const height = 34
32 |
33 | // this will only run on Web
34 | export function WebLayout({ children }: { children: React.ReactNode }) {
35 | const { pathname } = useRouter()
36 | const auth = useAuth()
37 | return (
38 | <>
39 |
52 |
59 | {tabs.map((tab) => {
60 | const active = tab.isActive(pathname)
61 | if (tab.protected && !auth) {
62 | return null
63 | }
64 | return (
65 |
66 |
67 |
74 | {tab.name}
75 |
76 |
77 |
78 | )
79 | })}
80 |
81 |
88 | by Fernando Rojo
89 |
90 |
91 | {children}
92 | >
93 | )
94 | }
95 |
--------------------------------------------------------------------------------
/packages/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.0.0",
3 | "name": "app",
4 | "main": "index.ts",
5 | "dependencies": {
6 | "@radix-ui/react-context-menu": "^0",
7 | "dripsy": "^3.6.0",
8 | "expo-linking": "^3.0.0",
9 | "firebase": "9.10.0",
10 | "moti": "0.19.0-alpha.6",
11 | "react-native-reanimated": "2.9.1",
12 | "solito": "latest",
13 | "zeego": "^0.5.0"
14 | },
15 | "sideEffects": false
16 | }
17 |
--------------------------------------------------------------------------------
/packages/app/provider/dripsy.tsx:
--------------------------------------------------------------------------------
1 | import { DripsyProvider, makeTheme } from 'dripsy'
2 |
3 | const theme = makeTheme({
4 | // https://www.dripsy.xyz/usage/theming/create
5 | colors: {
6 | $background: '#161618',
7 | $background2: 'rgb(28, 28, 31)',
8 | $background3: '#28282C',
9 | $purple3: '#32275F',
10 | $text: '#EDEDEF',
11 | },
12 | text: {
13 | body: {
14 | color: '$text',
15 | fontSize: 14,
16 | },
17 | p: {
18 | fontSize: 16,
19 | },
20 | },
21 | space: {
22 | $0: 0,
23 | $1: 4,
24 | $2: 8,
25 | $3: 16,
26 | $4: 32,
27 | $5: 64,
28 | $6: 128,
29 | },
30 | radii: {
31 | $0: 0,
32 | $1: 1,
33 | $2: 2,
34 | $3: 4,
35 | $4: 6,
36 | $5: 8,
37 | $6: 12,
38 | $rounded: 99999,
39 | },
40 | })
41 |
42 | type Theme = typeof theme
43 |
44 | declare module 'dripsy' {
45 | interface DripsyCustomTheme extends Theme {}
46 | }
47 |
48 | export function Dripsy({ children }: { children: React.ReactNode }) {
49 | return (
50 |
55 | {children}
56 |
57 | )
58 | }
59 |
--------------------------------------------------------------------------------
/packages/app/provider/index.tsx:
--------------------------------------------------------------------------------
1 | import { AuthProvider } from 'app/features/auth/context'
2 | import { Dripsy } from './dripsy'
3 |
4 | export function Provider({ children }: { children: React.ReactNode }) {
5 | return (
6 |
7 | {children}
8 |
9 | )
10 | }
11 |
--------------------------------------------------------------------------------
/packages/app/rnw-overrides.d.ts:
--------------------------------------------------------------------------------
1 | // override react-native types with react-native-web types
2 | import 'react-native'
3 |
4 | declare module 'react-native' {
5 | interface PressableStateCallbackType {
6 | hovered?: boolean
7 | focused?: boolean
8 | }
9 | interface ViewStyle {
10 | transitionProperty?: string
11 | transitionDuration?: string
12 | }
13 | interface TextProps {
14 | accessibilityComponentType?: never
15 | accessibilityTraits?: never
16 | href?: string
17 | hrefAttrs?: {
18 | rel: 'noreferrer'
19 | target?: '_blank'
20 | }
21 | }
22 | interface ViewProps {
23 | accessibilityRole?: string
24 | href?: string
25 | hrefAttrs?: {
26 | rel: 'noreferrer'
27 | target?: '_blank'
28 | }
29 | onClick?: (e: React.MouseEvent) => void
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | Here's the code used for my Next.js Conf 2022 [talk](https://www.youtube.com/watch?v=H1gSWXA3qfw).
2 |
3 |
4 |
5 |
6 |
7 | The `video` branch was used while recording. The `setup` branch was made prior. You can also see the [releases](https://github.com/nandorojo/nextjs-conf-22-example/releases) for a breakdown per chapter.
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strictNullChecks": true,
4 | "noUncheckedIndexedAccess": true,
5 | "paths": {
6 | "app/*": ["./packages/app/*"]
7 | }
8 | },
9 | "extends": "expo/tsconfig.base"
10 | }
11 |
--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------
1 | {
2 | "pipeline": {
3 | "build": {
4 | "dependsOn": ["^build"],
5 | "outputs": [".next/**"]
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------