diff --git a/Caddyfile.dev b/Caddyfile.dev
index 2cff439..7f50e52 100644
--- a/Caddyfile.dev
+++ b/Caddyfile.dev
@@ -13,19 +13,3 @@ timmypidashev.localhost {
reverse_proxy landing:8000
}
}
-
-about.timmypidashev.localhost {
- encode gzip
-
- reverse_proxy about:3000
-
- @backend_routes {
- path /_event/*
- path /_upload
- path /ping
- }
-
- handle @backend_routes {
- reverse_proxy about:8000
- }
-}
diff --git a/Makefile b/Makefile
index 4d01c63..42af042 100644
--- a/Makefile
+++ b/Makefile
@@ -6,15 +6,10 @@ PROJECT_SOURCES := "https://github.com/timmypidashev/web"
PROJECT_REGISTRY := "ghcr.io/timmypidashev/web"
PROJECT_ORGANIZATION := "org.opencontainers"
-CONTAINER_LANDING_NAME := "landing"
-CONTAINER_LANDING_VERSION := "v1.0.0"
-CONTAINER_LANDING_LOCATION := "src/landing"
-CONTAINER_LANDING_DESCRIPTION := "The landing page for my website."
-
-CONTAINER_ABOUT_NAME := "about"
-CONTAINER_ABOUT_VERSION := "v0.0.0"
-CONTAINER_ABOUT_LOCATION := "src/about"
-CONTAINER_ABOUT_DESCRIPTION := "The about page for my website."
+CONTAINER_WEB_NAME := "web"
+CONTAINER_WEB_VERSION := "v1.0.0"
+CONTAINER_WEB_LOCATION := "src/web"
+CONTAINER_WEB_DESCRIPTION := "My portfolio website!"
.DEFAULT_GOAL := help
.PHONY: run build push prune bump
@@ -147,14 +142,7 @@ define container_build
$(eval TAG := $(PROJECT_REGISTRY)/$(CONTAINER):$(VERSION)), \
)
- sudo mkdir -p $(call container_location,$(CONTAINER))/$(CONTAINER)/shared
- sudo mount -o bind src/shared $(call container_location,$(CONTAINER))/$(CONTAINER)/shared
docker buildx build --load -t $(TAG) -f $(strip $(subst $(SPACE),,$(call container_location,$(CONTAINER))))/Dockerfile.$(ENVIRONMENT) ./$(strip $(subst $(SPACE),,$(call container_location,$(CONTAINER))))/. $(ARGS) $(call labels,$(shell echo $(CONTAINER_NAME) | tr '[:lower:]' '[:upper:]')) --no-cache
- sudo umount -l $(call container_location,$(CONTAINER))/$(CONTAINER)/shared
- sleep 1
- sudo rm -rf $(call container_location,$(CONTAINER))/$(CONTAINER)/shared
- sleep 1
-
endef
define container_location
diff --git a/compose.dev.yml b/compose.dev.yml
index bec4aed..b1ae5cf 100644
--- a/compose.dev.yml
+++ b/compose.dev.yml
@@ -13,28 +13,15 @@ services:
networks:
- caddy
depends_on:
- - landing
- - about
+ - web
- landing:
- container_name: landing
- image: landing:dev
+ web:
+ container_name: web
+ image: web:dev
volumes:
- - ./src/landing/landing:/app/landing
- - ./src/landing/assets:/app/assets
- - ./src/landing/rxconfig.py:/app/rxconfig.py
- - ./src/shared:/app/landing/shared
- networks:
- - caddy
-
- about:
- container_name: about
- image: about:dev
- volumes:
- - ./src/about/about:/app/about
- - ./src/about/assets:/app/assets
- - ./src/about/rxconfig.py:/app/rxconfig.py
- - ./src/shared:/app/about/shared
+ - ./src/web/web:/app/web
+ - ./src/web/assets:/app/assets
+ - ./src/web/rxconfig.py:/app/rxconfig.py
networks:
- caddy
diff --git a/src/about/.web/package.json b/src/about/.web/package.json
deleted file mode 100644
index aab86df..0000000
--- a/src/about/.web/package.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "name": "reflex",
- "scripts": {
- "dev": "next dev",
- "export": "next build",
- "export-sitemap": "next build && next-sitemap",
- "prod": "next start"
- },
- "dependencies": {
- "@emotion/react": "11.11.1",
- "axios": "1.6.0",
- "json5": "2.2.3",
- "next": "14.0.1",
- "next-sitemap": "4.1.8",
- "next-themes": "0.2.1",
- "react": "18.2.0",
- "react-dom": "18.2.0",
- "socket.io-client": "4.6.1",
- "universal-cookie": "4.0.4"
- },
- "devDependencies": {
- "autoprefixer": "10.4.14",
- "postcss": "8.4.31"
- }
-}
\ No newline at end of file
diff --git a/src/about/.web/reflex.json b/src/about/.web/reflex.json
deleted file mode 100644
index 7aecab7..0000000
--- a/src/about/.web/reflex.json
+++ /dev/null
@@ -1 +0,0 @@
-{"version": "0.4.3", "project_hash": 326586468133229768661018683044141625593}
\ No newline at end of file
diff --git a/src/about/Dockerfile.dev b/src/about/Dockerfile.dev
deleted file mode 100644
index f5c6b24..0000000
--- a/src/about/Dockerfile.dev
+++ /dev/null
@@ -1,54 +0,0 @@
-# Stage 1: init
-FROM python:3.11 as init
-
-# Copy local context to `/app` inside container (see .dockerignore)
-WORKDIR /app
-COPY . .
-
-# Create virtualenv which will be copied into the final container
-ENV VIRTUAL_ENV=/app/.venv
-ENV PATH="$VIRTUAL_ENV/bin:$PATH"
-RUN python3.11 -m venv $VIRTUAL_ENV
-
-# Install app requirements and reflex inside virtualenv
-RUN pip install -r requirements.txt
-
-# Deploy templates and prepare app
-RUN reflex init
-
-# Export static copy of frontend to /app/.web/_static
-RUN echo "Exporting reflex app to shrink the docker image size, not actually a prod build."
-RUN reflex export --frontend-only --no-zip
-
-# Copy static files out of /app to save space in backend image
-RUN mv .web/_static /tmp/_static
-RUN rm -rf .web && mkdir .web
-RUN mv /tmp/_static .web/_static
-
-# Stage 2: copy artifacts into slim image
-FROM python:3.11-slim
-WORKDIR /app
-RUN adduser --disabled-password --home /app reflex
-
-# Install Node.js and unzip
-RUN apt-get update && apt-get install -y nodejs unzip curl && curl -fsSL https://bun.sh/install | bash
-
-# Copy only the necessary files from the "init" stage
-COPY --chown=reflex --from=init /app/.venv /app/.venv
-COPY --chown=reflex --from=init /app/requirements.txt /app/requirements.txt
-COPY --chown=reflex --from=init /app /app
-
-# Change the ownership and permissions of /app/.local
-USER root
-RUN mkdir -p /app
-RUN chown -R reflex /app
-USER reflex
-
-# Activate the virtual environment and install application requirements
-ENV PATH="/app/.venv/bin:$PATH"
-RUN python3.11 -m venv /app/.venv
-RUN /app/.venv/bin/pip install -r /app/requirements.txt
-
-# The following lines are for the specific command for the application.
-CMD reflex init && reflex run --env dev
-
diff --git a/src/about/about/about.py b/src/about/about/about.py
deleted file mode 100644
index 8ff44ab..0000000
--- a/src/about/about/about.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""Welcome to Reflex! This file outlines the steps to create a basic app."""
-
-from rxconfig import config
-
-import reflex as rx
-
-docs_url = "https://reflex.dev/docs/getting-started/introduction/"
-filename = f"{config.app_name}/{config.app_name}.py"
-
-
-class State(rx.State):
- """The app state."""
-
-
-def index() -> rx.Component:
- return rx.center(
- rx.theme_panel(),
- rx.vstack(
- rx.heading("Welcome to Reflex!", size="9"),
- rx.text("Get started by editing ", rx.code(filename)),
- rx.button(
- "Check out our docs!",
- on_click=lambda: rx.redirect(docs_url),
- size="4",
- ),
- align="center",
- spacing="7",
- font_size="2em",
- ),
- height="100vh",
- )
-
-
-app = rx.App()
-app.add_page(index)
diff --git a/src/about/rxconfig.py b/src/about/rxconfig.py
deleted file mode 100644
index 250c229..0000000
--- a/src/about/rxconfig.py
+++ /dev/null
@@ -1,5 +0,0 @@
-import reflex as rx
-
-config = rx.Config(
- app_name="about",
-)
\ No newline at end of file
diff --git a/src/landing/.dockerignore b/src/landing/.dockerignore
deleted file mode 100644
index b289110..0000000
--- a/src/landing/.dockerignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.web
-__pycache__/*
-Dockerfile
diff --git a/src/landing/.web/.gitignore b/src/landing/.web/.gitignore
deleted file mode 100644
index 534bc86..0000000
--- a/src/landing/.web/.gitignore
+++ /dev/null
@@ -1,39 +0,0 @@
-# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
-
-/_static
-
-# dependencies
-/node_modules
-/.pnp
-.pnp.js
-
-# testing
-/coverage
-
-# next.js
-/.next/
-/out/
-
-# production
-/build
-
-# misc
-.DS_Store
-*.pem
-
-# debug
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# local env files
-.env.local
-.env.development.local
-.env.test.local
-.env.production.local
-
-# vercel
-.vercel
-
-# DS_Store
-.DS_Store
\ No newline at end of file
diff --git a/src/landing/.web/components/reflex/chakra_color_mode_provider.js b/src/landing/.web/components/reflex/chakra_color_mode_provider.js
deleted file mode 100644
index f897522..0000000
--- a/src/landing/.web/components/reflex/chakra_color_mode_provider.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { useColorMode as chakraUseColorMode } from "@chakra-ui/react"
-import { useTheme } from "next-themes"
-import { useEffect } from "react"
-import { ColorModeContext } from "/utils/context.js"
-
-export default function ChakraColorModeProvider({ children }) {
- const {colorMode, toggleColorMode} = chakraUseColorMode()
- const {theme, setTheme} = useTheme()
-
- useEffect(() => {
- if (colorMode != theme) {
- toggleColorMode()
- }
- }, [theme])
-
- return (
-
- {children}
-
- )
-}
\ No newline at end of file
diff --git a/src/landing/.web/components/reflex/radix_themes_color_mode_provider.js b/src/landing/.web/components/reflex/radix_themes_color_mode_provider.js
deleted file mode 100644
index e2dd563..0000000
--- a/src/landing/.web/components/reflex/radix_themes_color_mode_provider.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import { useTheme } from "next-themes"
-import { useEffect, useState } from "react"
-import { ColorModeContext, defaultColorMode } from "/utils/context.js"
-
-
-export default function RadixThemesColorModeProvider({ children }) {
- const {theme, setTheme} = useTheme()
- const [colorMode, setColorMode] = useState(defaultColorMode)
-
- useEffect(() => {
- setColorMode(theme)
- }, [theme])
-
- const toggleColorMode = () => {
- setTheme(theme === "light" ? "dark" : "light")
- }
- return (
-
- {children}
-
- )
- }
\ No newline at end of file
diff --git a/src/landing/.web/jsconfig.json b/src/landing/.web/jsconfig.json
deleted file mode 100644
index 3c8a325..0000000
--- a/src/landing/.web/jsconfig.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "compilerOptions": {
- "baseUrl": ".",
- "paths": {
- "@/*": ["public/*"]
- }
- }
-}
\ No newline at end of file
diff --git a/src/landing/.web/next.config.js b/src/landing/.web/next.config.js
deleted file mode 100644
index 42dad1d..0000000
--- a/src/landing/.web/next.config.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = {basePath: "", compress: true, reactStrictMode: true, trailingSlash: true};
diff --git a/src/landing/.web/postcss.config.js b/src/landing/.web/postcss.config.js
deleted file mode 100644
index 33ad091..0000000
--- a/src/landing/.web/postcss.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-module.exports = {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- },
-}
diff --git a/src/landing/.web/styles/tailwind.css b/src/landing/.web/styles/tailwind.css
deleted file mode 100644
index b5c61c9..0000000
--- a/src/landing/.web/styles/tailwind.css
+++ /dev/null
@@ -1,3 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
diff --git a/src/landing/.web/utils/client_side_routing.js b/src/landing/.web/utils/client_side_routing.js
deleted file mode 100644
index 75fb581..0000000
--- a/src/landing/.web/utils/client_side_routing.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { useEffect, useRef, useState } from "react";
-import { useRouter } from "next/router";
-
-/**
- * React hook for use in /404 page to enable client-side routing.
- *
- * Uses the next/router to redirect to the provided URL when loading
- * the 404 page (for example as a fallback in static hosting situations).
- *
- * @returns {boolean} routeNotFound - true if the current route is an actual 404
- */
-export const useClientSideRouting = () => {
- const [routeNotFound, setRouteNotFound] = useState(false)
- const didRedirect = useRef(false)
- const router = useRouter()
- useEffect(() => {
- if (
- router.isReady &&
- !didRedirect.current // have not tried redirecting yet
- ) {
- didRedirect.current = true // never redirect twice to avoid "Hard Navigate" error
- // attempt to redirect to the route in the browser address bar once
- router.replace({
- pathname: window.location.pathname,
- query: window.location.search.slice(1),
- })
- .catch((e) => {
- setRouteNotFound(true) // navigation failed, so this is a real 404
- })
- }
- }, [router.isReady]);
-
- // Return the reactive bool, to avoid flashing 404 page until we know for sure
- // the route is not found.
- return routeNotFound
-}
\ No newline at end of file
diff --git a/src/landing/.web/utils/helpers/dataeditor.js b/src/landing/.web/utils/helpers/dataeditor.js
deleted file mode 100644
index 9ff3682..0000000
--- a/src/landing/.web/utils/helpers/dataeditor.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import { GridCellKind } from "@glideapps/glide-data-grid";
-
-export function getDEColumn(columns, col) {
- let c = columns[col];
- c.pos = col;
- return c;
-}
-
-export function getDERow(data, row) {
- return data[row];
-}
-
-export function locateCell(row, column) {
- if (Array.isArray(row)) {
- return row[column.pos];
- } else {
- return row[column.id];
- }
-}
-
-export function formatCell(value, column) {
- const editable = column.editable ?? true;
- switch (column.type) {
- case "int":
- case "float":
- return {
- kind: GridCellKind.Number,
- data: value,
- displayData: value + "",
- readonly: !editable,
- allowOverlay: editable,
- };
- case "datetime":
- // value = moment format?
- case "str":
- return {
- kind: GridCellKind.Text,
- data: value,
- displayData: value,
- readonly: !editable,
- allowOverlay: editable,
- };
- case "bool":
- return {
- kind: GridCellKind.Boolean,
- data: value,
- readonly: !editable,
- };
- default:
- console.log(
- "Warning: column.type is undefined for column.title=" + column.title
- );
- return {
- kind: GridCellKind.Text,
- data: value,
- displayData: column.type,
- };
- }
-}
-
-export function formatDataEditorCells(col, row, columns, data) {
- if (row < data.length && col < columns.length) {
- const column = getDEColumn(columns, col);
- const rowData = getDERow(data, row);
- const cellData = locateCell(rowData, column);
- return formatCell(cellData, column);
- }
- return { kind: GridCellKind.Loading };
-}
diff --git a/src/landing/.web/utils/helpers/range.js b/src/landing/.web/utils/helpers/range.js
deleted file mode 100644
index 7d1aeda..0000000
--- a/src/landing/.web/utils/helpers/range.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Simulate the python range() builtin function.
- * inspired by https://dev.to/guyariely/using-python-range-in-javascript-337p
- *
- * If needed outside of an iterator context, use `Array.from(range(10))` or
- * spread syntax `[...range(10)]` to get an array.
- *
- * @param {number} start: the start or end of the range.
- * @param {number} stop: the end of the range.
- * @param {number} step: the step of the range.
- * @returns {object} an object with a Symbol.iterator method over the range
- */
-export default function range(start, stop, step) {
- return {
- [Symbol.iterator]() {
- if (stop === undefined) {
- stop = start;
- start = 0;
- }
- if (step === undefined) {
- step = 1;
- }
-
- let i = start - step;
-
- return {
- next() {
- i += step;
- if ((step > 0 && i < stop) || (step < 0 && i > stop)) {
- return {
- value: i,
- done: false,
- };
- }
- return {
- value: undefined,
- done: true,
- };
- },
- };
- },
- };
- }
\ No newline at end of file
diff --git a/src/landing/.web/utils/state.js b/src/landing/.web/utils/state.js
deleted file mode 100644
index 51e8c6b..0000000
--- a/src/landing/.web/utils/state.js
+++ /dev/null
@@ -1,728 +0,0 @@
-// State management for Reflex web apps.
-import axios from "axios";
-import io from "socket.io-client";
-import JSON5 from "json5";
-import env from "/env.json";
-import Cookies from "universal-cookie";
-import { useEffect, useReducer, useRef, useState } from "react";
-import Router, { useRouter } from "next/router";
-import {
- initialEvents,
- initialState,
- onLoadInternalEvent,
- state_name,
-} from "utils/context.js";
-
-// Endpoint URLs.
-const EVENTURL = env.EVENT;
-const UPLOADURL = env.UPLOAD;
-
-// These hostnames indicate that the backend and frontend are reachable via the same domain.
-const SAME_DOMAIN_HOSTNAMES = ["localhost", "0.0.0.0", "::", "0:0:0:0:0:0:0:0"];
-
-// Global variable to hold the token.
-let token;
-
-// Key for the token in the session storage.
-const TOKEN_KEY = "token";
-
-// create cookie instance
-const cookies = new Cookies();
-
-// Dictionary holding component references.
-export const refs = {};
-
-// Flag ensures that only one event is processing on the backend concurrently.
-let event_processing = false;
-// Array holding pending events to be processed.
-const event_queue = [];
-
-// Pending upload promises, by id
-const upload_controllers = {};
-
-/**
- * Generate a UUID (Used for session tokens).
- * Taken from: https://stackoverflow.com/questions/105034/how-do-i-create-a-guid-uuid
- * @returns A UUID.
- */
-export const generateUUID = () => {
- let d = new Date().getTime(),
- d2 = (performance && performance.now && performance.now() * 1000) || 0;
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
- let r = Math.random() * 16;
- if (d > 0) {
- r = (d + r) % 16 | 0;
- d = Math.floor(d / 16);
- } else {
- r = (d2 + r) % 16 | 0;
- d2 = Math.floor(d2 / 16);
- }
- return (c == "x" ? r : (r & 0x7) | 0x8).toString(16);
- });
-};
-
-/**
- * Get the token for the current session.
- * @returns The token.
- */
-export const getToken = () => {
- if (token) {
- return token;
- }
- if (typeof window !== "undefined") {
- if (!window.sessionStorage.getItem(TOKEN_KEY)) {
- window.sessionStorage.setItem(TOKEN_KEY, generateUUID());
- }
- token = window.sessionStorage.getItem(TOKEN_KEY);
- }
- return token;
-};
-
-/**
- * Get the URL for the backend server
- * @param url_str The URL string to parse.
- * @returns The given URL modified to point to the actual backend server.
- */
-export const getBackendURL = (url_str) => {
- // Get backend URL object from the endpoint.
- const endpoint = new URL(url_str);
- if (
- typeof window !== "undefined" &&
- SAME_DOMAIN_HOSTNAMES.includes(endpoint.hostname)
- ) {
- // Use the frontend domain to access the backend
- const frontend_hostname = window.location.hostname;
- endpoint.hostname = frontend_hostname;
- if (window.location.protocol === "https:") {
- if (endpoint.protocol === "ws:") {
- endpoint.protocol = "wss:";
- } else if (endpoint.protocol === "http:") {
- endpoint.protocol = "https:";
- }
- endpoint.port = ""; // Assume websocket is on https port via load balancer.
- }
- }
- return endpoint;
-};
-
-/**
- * Apply a delta to the state.
- * @param state The state to apply the delta to.
- * @param delta The delta to apply.
- */
-export const applyDelta = (state, delta) => {
- return { ...state, ...delta };
-};
-
-/**
- * Handle frontend event or send the event to the backend via Websocket.
- * @param event The event to send.
- * @param socket The socket object to send the event on.
- *
- * @returns True if the event was sent, false if it was handled locally.
- */
-export const applyEvent = async (event, socket) => {
- // Handle special events
- if (event.name == "_redirect") {
- if (event.payload.external) window.open(event.payload.path, "_blank");
- else Router.push(event.payload.path);
- return false;
- }
-
- if (event.name == "_console") {
- console.log(event.payload.message);
- return false;
- }
-
- if (event.name == "_remove_cookie") {
- cookies.remove(event.payload.key, { ...event.payload.options });
- queueEvents(initialEvents(), socket);
- return false;
- }
-
- if (event.name == "_clear_local_storage") {
- localStorage.clear();
- queueEvents(initialEvents(), socket);
- return false;
- }
-
- if (event.name == "_remove_local_storage") {
- localStorage.removeItem(event.payload.key);
- queueEvents(initialEvents(), socket);
- return false;
- }
-
- if (event.name == "_set_clipboard") {
- const content = event.payload.content;
- navigator.clipboard.writeText(content);
- return false;
- }
-
- if (event.name == "_download") {
- const a = document.createElement("a");
- a.hidden = true;
- a.href = event.payload.url;
- a.download = event.payload.filename;
- a.click();
- a.remove();
- return false;
- }
-
- if (event.name == "_alert") {
- alert(event.payload.message);
- return false;
- }
-
- if (event.name == "_set_focus") {
- const ref =
- event.payload.ref in refs ? refs[event.payload.ref] : event.payload.ref;
- ref.current.focus();
- return false;
- }
-
- if (event.name == "_set_value") {
- const ref =
- event.payload.ref in refs ? refs[event.payload.ref] : event.payload.ref;
- if (ref.current) {
- ref.current.value = event.payload.value;
- }
- return false;
- }
-
- if (event.name == "_call_script") {
- try {
- const eval_result = eval(event.payload.javascript_code);
- if (event.payload.callback) {
- if (!!eval_result && typeof eval_result.then === "function") {
- eval(event.payload.callback)(await eval_result);
- } else {
- eval(event.payload.callback)(eval_result);
- }
- }
- } catch (e) {
- console.log("_call_script", e);
- }
- return false;
- }
-
- // Update token and router data (if missing).
- event.token = getToken();
- if (
- event.router_data === undefined ||
- Object.keys(event.router_data).length === 0
- ) {
- event.router_data = (({ pathname, query, asPath }) => ({
- pathname,
- query,
- asPath,
- }))(Router);
- }
-
- // Send the event to the server.
- if (socket) {
- socket.emit(
- "event",
- JSON.stringify(event, (k, v) => (v === undefined ? null : v))
- );
- return true;
- }
-
- return false;
-};
-
-/**
- * Send an event to the server via REST.
- * @param event The current event.
- * @param socket The socket object to send the response event(s) on.
- *
- * @returns Whether the event was sent.
- */
-export const applyRestEvent = async (event, socket) => {
- let eventSent = false;
- if (event.handler == "uploadFiles") {
- // Start upload, but do not wait for it, which would block other events.
- uploadFiles(
- event.name,
- event.payload.files,
- event.payload.upload_id,
- event.payload.on_upload_progress,
- socket
- );
- return false;
- }
- return eventSent;
-};
-
-/**
- * Queue events to be processed and trigger processing of queue.
- * @param events Array of events to queue.
- * @param socket The socket object to send the event on.
- */
-export const queueEvents = async (events, socket) => {
- event_queue.push(...events);
- await processEvent(socket.current);
-};
-
-/**
- * Process an event off the event queue.
- * @param socket The socket object to send the event on.
- */
-export const processEvent = async (socket) => {
- // Only proceed if the socket is up, otherwise we throw the event into the void
- if (!socket) {
- return;
- }
-
- // Only proceed if we're not already processing an event.
- if (event_queue.length === 0 || event_processing) {
- return;
- }
-
- // Set processing to true to block other events from being processed.
- event_processing = true;
-
- // Apply the next event in the queue.
- const event = event_queue.shift();
-
- let eventSent = false;
- // Process events with handlers via REST and all others via websockets.
- if (event.handler) {
- eventSent = await applyRestEvent(event, socket);
- } else {
- eventSent = await applyEvent(event, socket);
- }
- // If no event was sent, set processing to false.
- if (!eventSent) {
- event_processing = false;
- // recursively call processEvent to drain the queue, since there is
- // no state update to trigger the useEffect event loop.
- await processEvent(socket);
- }
-};
-
-/**
- * Connect to a websocket and set the handlers.
- * @param socket The socket object to connect.
- * @param dispatch The function to queue state update
- * @param transports The transports to use.
- * @param setConnectErrors The function to update connection error value.
- * @param client_storage The client storage object from context.js
- */
-export const connect = async (
- socket,
- dispatch,
- transports,
- setConnectErrors,
- client_storage = {}
-) => {
- // Get backend URL object from the endpoint.
- const endpoint = getBackendURL(EVENTURL);
-
- // Create the socket.
- socket.current = io(endpoint.href, {
- path: endpoint["pathname"],
- transports: transports,
- autoUnref: false,
- });
-
- function checkVisibility() {
- if (document.visibilityState === "visible") {
- if (!socket.current.connected) {
- console.log("Socket is disconnected, attempting to reconnect ");
- socket.current.connect();
- } else {
- console.log("Socket is reconnected ");
- }
- }
- }
-
- // Once the socket is open, hydrate the page.
- socket.current.on("connect", () => {
- setConnectErrors([]);
- });
-
- socket.current.on("connect_error", (error) => {
- setConnectErrors((connectErrors) => [connectErrors.slice(-9), error]);
- });
- // On each received message, queue the updates and events.
- socket.current.on("event", (message) => {
- const update = JSON5.parse(message);
- for (const substate in update.delta) {
- dispatch[substate](update.delta[substate]);
- }
- applyClientStorageDelta(client_storage, update.delta);
- event_processing = !update.final;
- if (update.events) {
- queueEvents(update.events, socket);
- }
- });
-
- document.addEventListener("visibilitychange", checkVisibility);
-};
-
-/**
- * Upload files to the server.
- *
- * @param state The state to apply the delta to.
- * @param handler The handler to use.
- * @param upload_id The upload id to use.
- * @param on_upload_progress The function to call on upload progress.
- * @param socket the websocket connection
- *
- * @returns The response from posting to the UPLOADURL endpoint.
- */
-export const uploadFiles = async (
- handler,
- files,
- upload_id,
- on_upload_progress,
- socket
-) => {
- // return if there's no file to upload
- if (files === undefined || files.length === 0) {
- return false;
- }
-
- if (upload_controllers[upload_id]) {
- console.log("Upload already in progress for ", upload_id);
- return false;
- }
-
- let resp_idx = 0;
- const eventHandler = (progressEvent) => {
- // handle any delta / event streamed from the upload event handler
- const chunks = progressEvent.event.target.responseText.trim().split("\n");
- chunks.slice(resp_idx).map((chunk) => {
- try {
- socket._callbacks.$event.map((f) => {
- f(chunk);
- });
- resp_idx += 1;
- } catch (e) {
- if (progressEvent.progress === 1) {
- // Chunk may be incomplete, so only report errors when full response is available.
- console.log("Error parsing chunk", chunk, e);
- }
- return;
- }
- });
- };
-
- const controller = new AbortController();
- const config = {
- headers: {
- "Reflex-Client-Token": getToken(),
- "Reflex-Event-Handler": handler,
- },
- signal: controller.signal,
- onDownloadProgress: eventHandler,
- };
- if (on_upload_progress) {
- config["onUploadProgress"] = on_upload_progress;
- }
- const formdata = new FormData();
-
- // Add the token and handler to the file name.
- files.forEach((file) => {
- formdata.append("files", file, file.path || file.name);
- });
-
- // Send the file to the server.
- upload_controllers[upload_id] = controller;
-
- try {
- return await axios.post(getBackendURL(UPLOADURL), formdata, config);
- } catch (error) {
- if (error.response) {
- // The request was made and the server responded with a status code
- // that falls out of the range of 2xx
- console.log(error.response.data);
- } else if (error.request) {
- // The request was made but no response was received
- // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
- // http.ClientRequest in node.js
- console.log(error.request);
- } else {
- // Something happened in setting up the request that triggered an Error
- console.log(error.message);
- }
- return false;
- } finally {
- delete upload_controllers[upload_id];
- }
-};
-
-/**
- * Create an event object.
- * @param name The name of the event.
- * @param payload The payload of the event.
- * @param handler The client handler to process event.
- * @returns The event object.
- */
-export const Event = (name, payload = {}, handler = null) => {
- return { name, payload, handler };
-};
-
-/**
- * Package client-side storage values as payload to send to the
- * backend with the hydrate event
- * @param client_storage The client storage object from context.js
- * @returns payload dict of client storage values
- */
-export const hydrateClientStorage = (client_storage) => {
- const client_storage_values = {};
- if (client_storage.cookies) {
- for (const state_key in client_storage.cookies) {
- const cookie_options = client_storage.cookies[state_key];
- const cookie_name = cookie_options.name || state_key;
- const cookie_value = cookies.get(cookie_name);
- if (cookie_value !== undefined) {
- client_storage_values[state_key] = cookies.get(cookie_name);
- }
- }
- }
- if (client_storage.local_storage && typeof window !== "undefined") {
- for (const state_key in client_storage.local_storage) {
- const options = client_storage.local_storage[state_key];
- const local_storage_value = localStorage.getItem(
- options.name || state_key
- );
- if (local_storage_value !== null) {
- client_storage_values[state_key] = local_storage_value;
- }
- }
- }
- if (client_storage.cookies || client_storage.local_storage) {
- return client_storage_values;
- }
- return {};
-};
-
-/**
- * Update client storage values based on backend state delta.
- * @param client_storage The client storage object from context.js
- * @param delta The state update from the backend
- */
-const applyClientStorageDelta = (client_storage, delta) => {
- // find the main state and check for is_hydrated
- const unqualified_states = Object.keys(delta).filter(
- (key) => key.split(".").length === 1
- );
- if (unqualified_states.length === 1) {
- const main_state = delta[unqualified_states[0]];
- if (main_state.is_hydrated !== undefined && !main_state.is_hydrated) {
- // skip if the state is not hydrated yet, since all client storage
- // values are sent in the hydrate event
- return;
- }
- }
- // Save known client storage values to cookies and localStorage.
- for (const substate in delta) {
- for (const key in delta[substate]) {
- const state_key = `${substate}.${key}`;
- if (client_storage.cookies && state_key in client_storage.cookies) {
- const cookie_options = { ...client_storage.cookies[state_key] };
- const cookie_name = cookie_options.name || state_key;
- delete cookie_options.name; // name is not a valid cookie option
- cookies.set(cookie_name, delta[substate][key], cookie_options);
- } else if (
- client_storage.local_storage &&
- state_key in client_storage.local_storage &&
- typeof window !== "undefined"
- ) {
- const options = client_storage.local_storage[state_key];
- localStorage.setItem(options.name || state_key, delta[substate][key]);
- }
- }
- }
-};
-
-/**
- * Establish websocket event loop for a NextJS page.
- * @param dispatch The reducer dispatch function to update state.
- * @param initial_events The initial app events.
- * @param client_storage The client storage object from context.js
- *
- * @returns [addEvents, connectErrors] -
- * addEvents is used to queue an event, and
- * connectErrors is an array of reactive js error from the websocket connection (or null if connected).
- */
-export const useEventLoop = (
- dispatch,
- initial_events = () => [],
- client_storage = {}
-) => {
- const socket = useRef(null);
- const router = useRouter();
- const [connectErrors, setConnectErrors] = useState([]);
-
- // Function to add new events to the event queue.
- const addEvents = (events, _e, event_actions) => {
- if (event_actions?.preventDefault && _e?.preventDefault) {
- _e.preventDefault();
- }
- if (event_actions?.stopPropagation && _e?.stopPropagation) {
- _e.stopPropagation();
- }
- queueEvents(events, socket);
- };
-
- const sentHydrate = useRef(false); // Avoid double-hydrate due to React strict-mode
- useEffect(() => {
- if (router.isReady && !sentHydrate.current) {
- const events = initial_events();
- addEvents(
- events.map((e) => ({
- ...e,
- router_data: (({ pathname, query, asPath }) => ({
- pathname,
- query,
- asPath,
- }))(router),
- }))
- );
- sentHydrate.current = true;
- }
- }, [router.isReady]);
-
- // Main event loop.
- useEffect(() => {
- // Skip if the router is not ready.
- if (!router.isReady) {
- return;
- }
- // only use websockets if state is present
- if (Object.keys(initialState).length > 1) {
- // Initialize the websocket connection.
- if (!socket.current) {
- connect(
- socket,
- dispatch,
- ["websocket", "polling"],
- setConnectErrors,
- client_storage
- );
- }
- (async () => {
- // Process all outstanding events.
- while (event_queue.length > 0 && !event_processing) {
- await processEvent(socket.current);
- }
- })();
- }
- });
-
- // localStorage event handling
- useEffect(() => {
- const storage_to_state_map = {};
-
- if (client_storage.local_storage && typeof window !== "undefined") {
- for (const state_key in client_storage.local_storage) {
- const options = client_storage.local_storage[state_key];
- if (options.sync) {
- const local_storage_value_key = options.name || state_key;
- storage_to_state_map[local_storage_value_key] = state_key;
- }
- }
- }
-
- // e is StorageEvent
- const handleStorage = (e) => {
- if (storage_to_state_map[e.key]) {
- const vars = {};
- vars[storage_to_state_map[e.key]] = e.newValue;
- const event = Event(
- `${state_name}.update_vars_internal_state.update_vars_internal`,
- { vars: vars }
- );
- addEvents([event], e);
- }
- };
-
- window.addEventListener("storage", handleStorage);
- return () => window.removeEventListener("storage", handleStorage);
- });
-
- // Route after the initial page hydration.
- useEffect(() => {
- const change_complete = () => addEvents(onLoadInternalEvent());
- router.events.on("routeChangeComplete", change_complete);
- return () => {
- router.events.off("routeChangeComplete", change_complete);
- };
- }, [router]);
-
- return [addEvents, connectErrors];
-};
-
-/***
- * Check if a value is truthy in python.
- * @param val The value to check.
- * @returns True if the value is truthy, false otherwise.
- */
-export const isTrue = (val) => {
- return Array.isArray(val) ? val.length > 0 : !!val;
-};
-
-/**
- * Get the value from a ref.
- * @param ref The ref to get the value from.
- * @returns The value.
- */
-export const getRefValue = (ref) => {
- if (!ref || !ref.current) {
- return;
- }
- if (ref.current.type == "checkbox") {
- return ref.current.checked; // chakra
- } else if (
- ref.current.className?.includes("rt-CheckboxButton") ||
- ref.current.className?.includes("rt-SwitchButton")
- ) {
- return ref.current.ariaChecked == "true"; // radix
- } else if (ref.current.className?.includes("rt-SliderRoot")) {
- // find the actual slider
- return ref.current.querySelector(".rt-SliderThumb")?.ariaValueNow;
- } else {
- //querySelector(":checked") is needed to get value from radio_group
- return (
- ref.current.value ||
- (ref.current.querySelector &&
- ref.current.querySelector(":checked") &&
- ref.current.querySelector(":checked")?.value)
- );
- }
-};
-
-/**
- * Get the values from a ref array.
- * @param refs The refs to get the values from.
- * @returns The values array.
- */
-export const getRefValues = (refs) => {
- if (!refs) {
- return;
- }
- // getAttribute is used by RangeSlider because it doesn't assign value
- return refs.map((ref) =>
- ref.current
- ? ref.current.value || ref.current.getAttribute("aria-valuenow")
- : null
- );
-};
-
-/**
- * Spread two arrays or two objects.
- * @param first The first array or object.
- * @param second The second array or object.
- * @returns The final merged array or object.
- */
-export const spreadArraysOrObjects = (first, second) => {
- if (Array.isArray(first) && Array.isArray(second)) {
- return [...first, ...second];
- } else if (typeof first === "object" && typeof second === "object") {
- return { ...first, ...second };
- } else {
- throw new Error("Both parameters must be either arrays or objects.");
- }
-};
diff --git a/src/landing/assets/favicon.ico b/src/landing/assets/favicon.ico
deleted file mode 100644
index 166ae99..0000000
Binary files a/src/landing/assets/favicon.ico and /dev/null differ
diff --git a/src/landing/landing/__init__.py b/src/landing/landing/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/src/landing/landing/components/__init__.py b/src/landing/landing/components/__init__.py
deleted file mode 100644
index 994f7d0..0000000
--- a/src/landing/landing/components/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from landing.shared.components import navbar
-from .footer import footer
diff --git a/src/landing/requirements.txt b/src/landing/requirements.txt
deleted file mode 100644
index 239ae56..0000000
--- a/src/landing/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-reflex==0.4.4
diff --git a/src/shared/pages/__init__.py b/src/shared/pages/__init__.py
deleted file mode 100644
index 895ac1f..0000000
--- a/src/shared/pages/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from .page404 import page404
diff --git a/src/about/.dockerignore b/src/web/.dockerignore
similarity index 100%
rename from src/about/.dockerignore
rename to src/web/.dockerignore
diff --git a/src/about/.web/.gitignore b/src/web/.web/.gitignore
similarity index 100%
rename from src/about/.web/.gitignore
rename to src/web/.web/.gitignore
diff --git a/src/landing/.web/bun.lockb b/src/web/.web/bun.lockb
similarity index 100%
rename from src/landing/.web/bun.lockb
rename to src/web/.web/bun.lockb
diff --git a/src/about/.web/components/reflex/chakra_color_mode_provider.js b/src/web/.web/components/reflex/chakra_color_mode_provider.js
similarity index 100%
rename from src/about/.web/components/reflex/chakra_color_mode_provider.js
rename to src/web/.web/components/reflex/chakra_color_mode_provider.js
diff --git a/src/about/.web/components/reflex/radix_themes_color_mode_provider.js b/src/web/.web/components/reflex/radix_themes_color_mode_provider.js
similarity index 100%
rename from src/about/.web/components/reflex/radix_themes_color_mode_provider.js
rename to src/web/.web/components/reflex/radix_themes_color_mode_provider.js
diff --git a/src/landing/.web/env.json b/src/web/.web/env.json
similarity index 100%
rename from src/landing/.web/env.json
rename to src/web/.web/env.json
diff --git a/src/about/.web/jsconfig.json b/src/web/.web/jsconfig.json
similarity index 100%
rename from src/about/.web/jsconfig.json
rename to src/web/.web/jsconfig.json
diff --git a/src/about/.web/next.config.js b/src/web/.web/next.config.js
similarity index 100%
rename from src/about/.web/next.config.js
rename to src/web/.web/next.config.js
diff --git a/src/landing/.web/package.json b/src/web/.web/package.json
similarity index 100%
rename from src/landing/.web/package.json
rename to src/web/.web/package.json
diff --git a/src/landing/.web/pages/404.js b/src/web/.web/pages/404.js
similarity index 100%
rename from src/landing/.web/pages/404.js
rename to src/web/.web/pages/404.js
diff --git a/src/landing/.web/pages/_app.js b/src/web/.web/pages/_app.js
similarity index 100%
rename from src/landing/.web/pages/_app.js
rename to src/web/.web/pages/_app.js
diff --git a/src/landing/.web/pages/_document.js b/src/web/.web/pages/_document.js
similarity index 100%
rename from src/landing/.web/pages/_document.js
rename to src/web/.web/pages/_document.js
diff --git a/src/landing/.web/pages/index.js b/src/web/.web/pages/index.js
similarity index 100%
rename from src/landing/.web/pages/index.js
rename to src/web/.web/pages/index.js
diff --git a/src/about/.web/postcss.config.js b/src/web/.web/postcss.config.js
similarity index 100%
rename from src/about/.web/postcss.config.js
rename to src/web/.web/postcss.config.js
diff --git a/src/landing/.web/public/css/scrollbar.css b/src/web/.web/public/css/scrollbar.css
similarity index 100%
rename from src/landing/.web/public/css/scrollbar.css
rename to src/web/.web/public/css/scrollbar.css
diff --git a/src/about/assets/favicon.ico b/src/web/.web/public/favicon.ico
similarity index 100%
rename from src/about/assets/favicon.ico
rename to src/web/.web/public/favicon.ico
diff --git a/src/landing/.web/public/fonts/ComicCode-Bold.otf b/src/web/.web/public/fonts/ComicCode-Bold.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCode-Bold.otf
rename to src/web/.web/public/fonts/ComicCode-Bold.otf
diff --git a/src/landing/.web/public/fonts/ComicCode-BoldItalic.otf b/src/web/.web/public/fonts/ComicCode-BoldItalic.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCode-BoldItalic.otf
rename to src/web/.web/public/fonts/ComicCode-BoldItalic.otf
diff --git a/src/landing/.web/public/fonts/ComicCode-Italic.otf b/src/web/.web/public/fonts/ComicCode-Italic.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCode-Italic.otf
rename to src/web/.web/public/fonts/ComicCode-Italic.otf
diff --git a/src/landing/.web/public/fonts/ComicCode-Medium.otf b/src/web/.web/public/fonts/ComicCode-Medium.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCode-Medium.otf
rename to src/web/.web/public/fonts/ComicCode-Medium.otf
diff --git a/src/landing/.web/public/fonts/ComicCode-MediumItalic.otf b/src/web/.web/public/fonts/ComicCode-MediumItalic.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCode-MediumItalic.otf
rename to src/web/.web/public/fonts/ComicCode-MediumItalic.otf
diff --git a/src/landing/.web/public/fonts/ComicCode-Regular.otf b/src/web/.web/public/fonts/ComicCode-Regular.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCode-Regular.otf
rename to src/web/.web/public/fonts/ComicCode-Regular.otf
diff --git a/src/landing/.web/public/fonts/ComicCode-Regular.svg b/src/web/.web/public/fonts/ComicCode-Regular.svg
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCode-Regular.svg
rename to src/web/.web/public/fonts/ComicCode-Regular.svg
diff --git a/src/landing/.web/public/fonts/ComicCodeLigatures-Bold.otf b/src/web/.web/public/fonts/ComicCodeLigatures-Bold.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCodeLigatures-Bold.otf
rename to src/web/.web/public/fonts/ComicCodeLigatures-Bold.otf
diff --git a/src/landing/.web/public/fonts/ComicCodeLigatures-BoldItalic.otf b/src/web/.web/public/fonts/ComicCodeLigatures-BoldItalic.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCodeLigatures-BoldItalic.otf
rename to src/web/.web/public/fonts/ComicCodeLigatures-BoldItalic.otf
diff --git a/src/landing/.web/public/fonts/ComicCodeLigatures-Italic.otf b/src/web/.web/public/fonts/ComicCodeLigatures-Italic.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCodeLigatures-Italic.otf
rename to src/web/.web/public/fonts/ComicCodeLigatures-Italic.otf
diff --git a/src/landing/.web/public/fonts/ComicCodeLigatures-Medium.otf b/src/web/.web/public/fonts/ComicCodeLigatures-Medium.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCodeLigatures-Medium.otf
rename to src/web/.web/public/fonts/ComicCodeLigatures-Medium.otf
diff --git a/src/landing/.web/public/fonts/ComicCodeLigatures-MediumItalic.otf b/src/web/.web/public/fonts/ComicCodeLigatures-MediumItalic.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCodeLigatures-MediumItalic.otf
rename to src/web/.web/public/fonts/ComicCodeLigatures-MediumItalic.otf
diff --git a/src/landing/.web/public/fonts/ComicCodeLigatures-Regular.otf b/src/web/.web/public/fonts/ComicCodeLigatures-Regular.otf
similarity index 100%
rename from src/landing/.web/public/fonts/ComicCodeLigatures-Regular.otf
rename to src/web/.web/public/fonts/ComicCodeLigatures-Regular.otf
diff --git a/src/landing/.web/public/fonts/fonts.css b/src/web/.web/public/fonts/fonts.css
similarity index 100%
rename from src/landing/.web/public/fonts/fonts.css
rename to src/web/.web/public/fonts/fonts.css
diff --git a/src/landing/.web/reflex.install_frontend_packages.cached b/src/web/.web/reflex.install_frontend_packages.cached
similarity index 100%
rename from src/landing/.web/reflex.install_frontend_packages.cached
rename to src/web/.web/reflex.install_frontend_packages.cached
diff --git a/src/landing/.web/reflex.json b/src/web/.web/reflex.json
similarity index 100%
rename from src/landing/.web/reflex.json
rename to src/web/.web/reflex.json
diff --git a/src/landing/.web/styles/styles.css b/src/web/.web/styles/styles.css
similarity index 100%
rename from src/landing/.web/styles/styles.css
rename to src/web/.web/styles/styles.css
diff --git a/src/about/.web/styles/tailwind.css b/src/web/.web/styles/tailwind.css
similarity index 100%
rename from src/about/.web/styles/tailwind.css
rename to src/web/.web/styles/tailwind.css
diff --git a/src/landing/.web/tailwind.config.js b/src/web/.web/tailwind.config.js
similarity index 100%
rename from src/landing/.web/tailwind.config.js
rename to src/web/.web/tailwind.config.js
diff --git a/src/about/.web/utils/client_side_routing.js b/src/web/.web/utils/client_side_routing.js
similarity index 100%
rename from src/about/.web/utils/client_side_routing.js
rename to src/web/.web/utils/client_side_routing.js
diff --git a/src/landing/.web/utils/components.js b/src/web/.web/utils/components.js
similarity index 100%
rename from src/landing/.web/utils/components.js
rename to src/web/.web/utils/components.js
diff --git a/src/landing/.web/utils/context.js b/src/web/.web/utils/context.js
similarity index 100%
rename from src/landing/.web/utils/context.js
rename to src/web/.web/utils/context.js
diff --git a/src/about/.web/utils/helpers/dataeditor.js b/src/web/.web/utils/helpers/dataeditor.js
similarity index 100%
rename from src/about/.web/utils/helpers/dataeditor.js
rename to src/web/.web/utils/helpers/dataeditor.js
diff --git a/src/about/.web/utils/helpers/range.js b/src/web/.web/utils/helpers/range.js
similarity index 100%
rename from src/about/.web/utils/helpers/range.js
rename to src/web/.web/utils/helpers/range.js
diff --git a/src/about/.web/utils/state.js b/src/web/.web/utils/state.js
similarity index 100%
rename from src/about/.web/utils/state.js
rename to src/web/.web/utils/state.js
diff --git a/src/landing/.web/utils/stateful_components.js b/src/web/.web/utils/stateful_components.js
similarity index 100%
rename from src/landing/.web/utils/stateful_components.js
rename to src/web/.web/utils/stateful_components.js
diff --git a/src/landing/.web/utils/theme.js b/src/web/.web/utils/theme.js
similarity index 100%
rename from src/landing/.web/utils/theme.js
rename to src/web/.web/utils/theme.js
diff --git a/src/landing/Dockerfile.dev b/src/web/Dockerfile.dev
similarity index 100%
rename from src/landing/Dockerfile.dev
rename to src/web/Dockerfile.dev
diff --git a/src/landing/assets/css/scrollbar.css b/src/web/assets/css/scrollbar.css
similarity index 100%
rename from src/landing/assets/css/scrollbar.css
rename to src/web/assets/css/scrollbar.css
diff --git a/src/landing/.web/public/favicon.ico b/src/web/assets/favicon.ico
similarity index 100%
rename from src/landing/.web/public/favicon.ico
rename to src/web/assets/favicon.ico
diff --git a/src/landing/assets/fonts/ComicCode-Bold.otf b/src/web/assets/fonts/ComicCode-Bold.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCode-Bold.otf
rename to src/web/assets/fonts/ComicCode-Bold.otf
diff --git a/src/landing/assets/fonts/ComicCode-BoldItalic.otf b/src/web/assets/fonts/ComicCode-BoldItalic.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCode-BoldItalic.otf
rename to src/web/assets/fonts/ComicCode-BoldItalic.otf
diff --git a/src/landing/assets/fonts/ComicCode-Italic.otf b/src/web/assets/fonts/ComicCode-Italic.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCode-Italic.otf
rename to src/web/assets/fonts/ComicCode-Italic.otf
diff --git a/src/landing/assets/fonts/ComicCode-Medium.otf b/src/web/assets/fonts/ComicCode-Medium.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCode-Medium.otf
rename to src/web/assets/fonts/ComicCode-Medium.otf
diff --git a/src/landing/assets/fonts/ComicCode-MediumItalic.otf b/src/web/assets/fonts/ComicCode-MediumItalic.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCode-MediumItalic.otf
rename to src/web/assets/fonts/ComicCode-MediumItalic.otf
diff --git a/src/landing/assets/fonts/ComicCode-Regular.otf b/src/web/assets/fonts/ComicCode-Regular.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCode-Regular.otf
rename to src/web/assets/fonts/ComicCode-Regular.otf
diff --git a/src/landing/assets/fonts/ComicCode-Regular.svg b/src/web/assets/fonts/ComicCode-Regular.svg
similarity index 100%
rename from src/landing/assets/fonts/ComicCode-Regular.svg
rename to src/web/assets/fonts/ComicCode-Regular.svg
diff --git a/src/landing/assets/fonts/ComicCodeLigatures-Bold.otf b/src/web/assets/fonts/ComicCodeLigatures-Bold.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCodeLigatures-Bold.otf
rename to src/web/assets/fonts/ComicCodeLigatures-Bold.otf
diff --git a/src/landing/assets/fonts/ComicCodeLigatures-BoldItalic.otf b/src/web/assets/fonts/ComicCodeLigatures-BoldItalic.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCodeLigatures-BoldItalic.otf
rename to src/web/assets/fonts/ComicCodeLigatures-BoldItalic.otf
diff --git a/src/landing/assets/fonts/ComicCodeLigatures-Italic.otf b/src/web/assets/fonts/ComicCodeLigatures-Italic.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCodeLigatures-Italic.otf
rename to src/web/assets/fonts/ComicCodeLigatures-Italic.otf
diff --git a/src/landing/assets/fonts/ComicCodeLigatures-Medium.otf b/src/web/assets/fonts/ComicCodeLigatures-Medium.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCodeLigatures-Medium.otf
rename to src/web/assets/fonts/ComicCodeLigatures-Medium.otf
diff --git a/src/landing/assets/fonts/ComicCodeLigatures-MediumItalic.otf b/src/web/assets/fonts/ComicCodeLigatures-MediumItalic.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCodeLigatures-MediumItalic.otf
rename to src/web/assets/fonts/ComicCodeLigatures-MediumItalic.otf
diff --git a/src/landing/assets/fonts/ComicCodeLigatures-Regular.otf b/src/web/assets/fonts/ComicCodeLigatures-Regular.otf
similarity index 100%
rename from src/landing/assets/fonts/ComicCodeLigatures-Regular.otf
rename to src/web/assets/fonts/ComicCodeLigatures-Regular.otf
diff --git a/src/landing/assets/fonts/fonts.css b/src/web/assets/fonts/fonts.css
similarity index 100%
rename from src/landing/assets/fonts/fonts.css
rename to src/web/assets/fonts/fonts.css
diff --git a/src/about/requirements.txt b/src/web/requirements.txt
similarity index 100%
rename from src/about/requirements.txt
rename to src/web/requirements.txt
diff --git a/src/landing/rxconfig.py b/src/web/rxconfig.py
similarity index 76%
rename from src/landing/rxconfig.py
rename to src/web/rxconfig.py
index 2a54299..537dfe5 100644
--- a/src/landing/rxconfig.py
+++ b/src/web/rxconfig.py
@@ -1,6 +1,6 @@
import reflex as rx
config = rx.Config(
- app_name="landing",
+ app_name="web",
api_url="http://localhost:8000",
)
diff --git a/src/about/about/__init__.py b/src/web/web/__init__.py
similarity index 100%
rename from src/about/about/__init__.py
rename to src/web/web/__init__.py
diff --git a/src/shared/components/__init__.py b/src/web/web/components/__init__.py
similarity index 50%
rename from src/shared/components/__init__.py
rename to src/web/web/components/__init__.py
index aa6cfd2..a830f66 100644
--- a/src/shared/components/__init__.py
+++ b/src/web/web/components/__init__.py
@@ -1 +1,2 @@
from .navbar import navbar
+from .footer import footer
diff --git a/src/landing/landing/components/footer.py b/src/web/web/components/footer.py
similarity index 92%
rename from src/landing/landing/components/footer.py
rename to src/web/web/components/footer.py
index dfbe77d..51e40d3 100644
--- a/src/landing/landing/components/footer.py
+++ b/src/web/web/components/footer.py
@@ -1,5 +1,5 @@
import reflex as rx
-from landing.style import *
+from web.style import *
def footer():
return rx.box(
diff --git a/src/shared/components/navbar.py b/src/web/web/components/navbar.py
similarity index 97%
rename from src/shared/components/navbar.py
rename to src/web/web/components/navbar.py
index a7a6bd7..578cd39 100644
--- a/src/shared/components/navbar.py
+++ b/src/web/web/components/navbar.py
@@ -1,5 +1,5 @@
import reflex as rx
-from landing.style import *
+from web.style import *
def navbar():
return rx.box(
diff --git a/src/landing/landing/pages/__init__.py b/src/web/web/pages/__init__.py
similarity index 65%
rename from src/landing/landing/pages/__init__.py
rename to src/web/web/pages/__init__.py
index fc95cdc..126ce4b 100644
--- a/src/landing/landing/pages/__init__.py
+++ b/src/web/web/pages/__init__.py
@@ -1,7 +1,7 @@
-from landing.route import Route
+from web.route import Route
from .index import index
-from landing.shared.pages import page404
+from .page404 import page404
routes = [
*[r for r in locals().values() if isinstance(r, Route)],
diff --git a/src/landing/landing/pages/index.py b/src/web/web/pages/index.py
similarity index 81%
rename from src/landing/landing/pages/index.py
rename to src/web/web/pages/index.py
index 76fafdd..54a38e9 100644
--- a/src/landing/landing/pages/index.py
+++ b/src/web/web/pages/index.py
@@ -1,6 +1,6 @@
import reflex as rx
-from landing.components import navbar
-from landing.templates import webpage
+from web.components import navbar
+from web.templates import webpage
@webpage(path="/", title="Timothy Pidashev")
def index() -> rx.Component:
diff --git a/src/shared/pages/page404.py b/src/web/web/pages/page404.py
similarity index 89%
rename from src/shared/pages/page404.py
rename to src/web/web/pages/page404.py
index 9e78b0c..2c18b77 100644
--- a/src/shared/pages/page404.py
+++ b/src/web/web/pages/page404.py
@@ -1,5 +1,5 @@
import reflex as rx
-from landing.templates import webpage
+from web.templates import webpage
# TODO: Add a go back here link
diff --git a/src/landing/landing/route.py b/src/web/web/route.py
similarity index 96%
rename from src/landing/landing/route.py
rename to src/web/web/route.py
index 89c2c6f..741a7d1 100644
--- a/src/landing/landing/route.py
+++ b/src/web/web/route.py
@@ -26,4 +26,4 @@ def get_path(component_function: Callable):
module = inspect.getmodule(component_function)
# Create a path based on the module name.
- return module.__name__.replace(".", "/").replace("_", "-").split("landing/pages")[1]
+ return module.__name__.replace(".", "/").replace("_", "-").split("web/pages")[1]
diff --git a/src/landing/landing/state/__init__.py b/src/web/web/state/__init__.py
similarity index 100%
rename from src/landing/landing/state/__init__.py
rename to src/web/web/state/__init__.py
diff --git a/src/landing/landing/state/state.py b/src/web/web/state/state.py
similarity index 100%
rename from src/landing/landing/state/state.py
rename to src/web/web/state/state.py
diff --git a/src/landing/landing/state/theme.py b/src/web/web/state/theme.py
similarity index 92%
rename from src/landing/landing/state/theme.py
rename to src/web/web/state/theme.py
index a17e9e5..fb9e517 100644
--- a/src/landing/landing/state/theme.py
+++ b/src/web/web/state/theme.py
@@ -1,6 +1,6 @@
import reflex as rx
from .state import State
-from landing.style import *
+from web.style import *
from typing import Dict, Any, List
diff --git a/src/landing/landing/style.py b/src/web/web/style.py
similarity index 100%
rename from src/landing/landing/style.py
rename to src/web/web/style.py
diff --git a/src/landing/landing/templates/__init__.py b/src/web/web/templates/__init__.py
similarity index 100%
rename from src/landing/landing/templates/__init__.py
rename to src/web/web/templates/__init__.py
diff --git a/src/landing/landing/templates/webpage.py b/src/web/web/templates/webpage.py
similarity index 90%
rename from src/landing/landing/templates/webpage.py
rename to src/web/web/templates/webpage.py
index 1c46e31..575e846 100644
--- a/src/landing/landing/templates/webpage.py
+++ b/src/web/web/templates/webpage.py
@@ -1,6 +1,6 @@
from typing import Callable
import reflex as rx
-from landing.route import Route
+from web.route import Route
def webpage(path: str, title: str = "Timothy Pidashev", props=None) -> Callable:
"""This template wraps the webpage with the navbar and footer.
@@ -36,8 +36,8 @@ def webpage(path: str, title: str = "Timothy Pidashev", props=None) -> Callable:
The component with the template applied.
"""
# Import here to avoid circular imports.
- from landing.shared.components.navbar import navbar
- from landing.components.footer import footer
+ from web.components.navbar import navbar
+ from web.components.footer import footer
# Wrap the component in the template.
return rx.box(
diff --git a/src/landing/landing/landing.py b/src/web/web/web.py
similarity index 81%
rename from src/landing/landing/landing.py
rename to src/web/web/web.py
index cd79a8e..15a5b8f 100644
--- a/src/landing/landing/landing.py
+++ b/src/web/web/web.py
@@ -1,8 +1,8 @@
import reflex as rx
from rxconfig import config
-from landing.state import *
-from landing.pages import *
-from landing.style import *
+from web.state import *
+from web.pages import *
+from web.style import *
# Create app instance and add index page.
app = rx.App(