diff --git a/packages/appreader/.babelrc b/packages/appreader/.babelrc
new file mode 100644
index 000000000..f994b2205
--- /dev/null
+++ b/packages/appreader/.babelrc
@@ -0,0 +1,16 @@
+{
+ "presets": [
+ "@babel/preset-env",
+ "@babel/preset-react",
+ "@babel/preset-typescript"
+ ],
+ "plugins": [
+ [
+ "@babel/plugin-transform-runtime",
+ {
+ "regenerator": true
+ }
+ ]
+ ]
+}
+
diff --git a/packages/appreader/.eslintignore b/packages/appreader/.eslintignore
new file mode 100644
index 000000000..4cc1ec267
--- /dev/null
+++ b/packages/appreader/.eslintignore
@@ -0,0 +1,3 @@
+**/node_modules/*
+**/out/*
+**/.next/*
\ No newline at end of file
diff --git a/packages/appreader/.eslintrc b/packages/appreader/.eslintrc
new file mode 100644
index 000000000..c5a8fdcd8
--- /dev/null
+++ b/packages/appreader/.eslintrc
@@ -0,0 +1,26 @@
+{
+ "parser": "@typescript-eslint/parser",
+ "parserOptions": {
+ "project": "tsconfig.json"
+ },
+ "plugins": ["@typescript-eslint", "functional"],
+ "extends": [
+ "next/core-web-vitals",
+ "plugin:@typescript-eslint/recommended",
+ "plugin:@typescript-eslint/eslint-recommended",
+ "prettier",
+ "plugin:functional/no-object-orientation"
+ ],
+ "root": true,
+ "env": {
+ "es6": true,
+ "browser": true,
+ "jest": true,
+ "node": true
+ },
+ "ignorePatterns": ["next.config.js", "jest.config.js"],
+ "rules": {
+ "functional/no-mixed-type": 0,
+ "react/react-in-jsx-scope": 0
+ }
+}
diff --git a/packages/appreader/additional.d.ts b/packages/appreader/additional.d.ts
new file mode 100644
index 000000000..1ac3c0219
--- /dev/null
+++ b/packages/appreader/additional.d.ts
@@ -0,0 +1,9 @@
+export {}
+
+declare global {
+ interface Window {
+ omnivoreArticle?: any
+ omnivoreEnv?: any
+ fontSize?: number
+ }
+}
diff --git a/packages/appreader/build/index.html b/packages/appreader/build/index.html
new file mode 100644
index 000000000..419d00b00
--- /dev/null
+++ b/packages/appreader/build/index.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/appreader/package.json b/packages/appreader/package.json
new file mode 100644
index 000000000..b2dcc6964
--- /dev/null
+++ b/packages/appreader/package.json
@@ -0,0 +1,37 @@
+{
+ "name": "@omnivore/appreader",
+ "version": "1.0.0",
+ "private": true,
+ "scripts": {
+ "build": "webpack --mode production"
+ },
+ "dependencies": {
+ "@omnivore/web": "1.0.0"
+ },
+ "devDependencies": {
+ "webpack": "^5.70.0",
+ "webpack-cli": "^4.9.2",
+ "@babel/core": "^7.17.7",
+ "@babel/plugin-transform-runtime": "^7.17.0",
+ "@babel/preset-env": "^7.16.11",
+ "@babel/preset-react": "^7.16.7",
+ "@babel/preset-typescript": "^7.16.7",
+ "@babel/runtime": "^7.17.7",
+ "@types/string-replace-loader": "^2.3.2",
+ "@types/webpack-bundle-analyzer": "^4.4.1",
+ "@types/webpack-dev-server": "^4.7.2",
+ "babel-loader": "^8.2.3",
+ "css-loader": "^6.7.1",
+ "eslint-config-next": "12.0.7",
+ "eslint-plugin-functional": "^4.0.2",
+ "eslint-plugin-react": "^7.28.0",
+ "string-replace-loader": "^3.1.0",
+ "style-loader": "^3.3.1",
+ "webpack-bundle-analyzer": "^4.5.0",
+ "webpack-dev-server": "^4.7.4"
+ },
+ "volta": {
+ "node": "14.18.0",
+ "yarn": "1.22.10"
+ }
+}
diff --git a/packages/appreader/src/index.tsx b/packages/appreader/src/index.tsx
new file mode 100644
index 000000000..1c0bdb9e4
--- /dev/null
+++ b/packages/appreader/src/index.tsx
@@ -0,0 +1,56 @@
+import React from "react";
+import ReactDOM from "react-dom";
+import { Box, VStack } from '@omnivore/web/components/elements/LayoutPrimitives'
+import { ArticleContainer } from '@omnivore/web/components/templates/article/ArticleContainer'
+import { ArticleAttributes } from "@omnivore/web/lib/networking/queries/useGetArticleQuery";
+import '@omnivore/web/styles/globals.css'
+import '@omnivore/web/styles/articleInnerStyling.css'
+
+const App = () => {
+ var themeId = window.localStorage.getItem('theme')
+
+ if (themeId) {
+ document.body.classList.remove(
+ 'theme-default',
+ 'White',
+ 'Gray',
+ 'LightGray',
+ 'Dark'
+ )
+ document.body.classList.add(themeId)
+ }
+
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+}
+
+ReactDOM.render(
+ ,
+ document.getElementById("root")
+);
diff --git a/packages/appreader/tsconfig.json b/packages/appreader/tsconfig.json
new file mode 100644
index 000000000..c389b20b6
--- /dev/null
+++ b/packages/appreader/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "allowSyntheticDefaultImports": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react"
+ },
+ "include": ["additional.d.ts", "src"]
+}
\ No newline at end of file
diff --git a/packages/appreader/webpack.config.ts b/packages/appreader/webpack.config.ts
new file mode 100644
index 000000000..c0b47333b
--- /dev/null
+++ b/packages/appreader/webpack.config.ts
@@ -0,0 +1,79 @@
+import path from "path"
+import glob from 'glob'
+import { DefinePlugin } from 'webpack'
+import { Configuration } from "webpack"
+import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
+
+
+const analyze = process.env.ANALYZE
+
+const config: Configuration = {
+ entry: {
+ bundle: './src/index.tsx',
+ fonts: [
+ ...glob.sync('../web/public/static/fonts/Inter/*'),
+ ...glob.sync('../web/public/static/fonts/SFMono/*')
+ ],
+ },
+ module: {
+ rules: [
+ {
+ test: /\.(ts|js)x?$/,
+ exclude: /node_modules/,
+ use: {
+ loader: "babel-loader",
+ options: {
+ presets: [
+ "@babel/preset-env",
+ ["@babel/preset-react", {"runtime": "automatic"}],
+ "@babel/preset-typescript",
+ ],
+ },
+ },
+ },
+ {
+ test: /\.css$/i,
+ use: ['style-loader', {
+ loader: 'css-loader',
+ options: { url: false }
+ }, {
+ // We want paths like `/static/fonts/Inter/Inter.woff2 to become
+ // `Inter.woff2` which is how they will be bundled on iOS.
+ loader: 'string-replace-loader',
+ options: {
+ search: '\(\'/static/fonts/.*/(.*)\'\)',
+ replace(_s: string, _p: string, group: string) {
+ return group
+ },
+ flags: 'g',
+ },
+ }],
+ },
+ {
+ test: /.(ttf|otf|woff(2)?)(\?[a-z0-9]+)?$/,
+ type: 'asset/resource',
+ generator: {
+ filename: '[path][name][ext]'
+ }
+ },
+ ],
+ },
+ plugins: [
+ new DefinePlugin({
+ 'process.env': 'window.omnivoreEnv',
+ }),
+ new BundleAnalyzerPlugin({
+ openAnalyzer: !!analyze,
+ analyzerMode: 'static',
+ })
+ ],
+ resolve: {
+ extensions: [".tsx", ".ts", ".js"],
+ },
+ output: {
+ path: path.resolve(__dirname, "build"),
+ filename: '[name].js',
+ },
+};
+
+export default config;
\ No newline at end of file