Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env-example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HATCH_ENV=development
5 changes: 4 additions & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
bun test
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

bun run format
Binary file modified bun.lockb
Binary file not shown.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@
"packages/*"
],
"scripts": {
"prepare": "husky",
"start:frontend": "bun run --cwd packages/frontend dev",
"build:frontend": "bun run --cwd packages/frontend build",
"lint:frontend": "bun run --cwd packages/frontend lint",
"preview:frontend": "bun run --cwd packages/frontend preview",
"prepare": "husky",
"format": "bun run format:frontend && bun run format:api",
"format:frontend": "prettier --write 'packages/frontend/**/*.{js,ts,tsx,json,md,scss,css}'",
"format:api": "prettier --write 'packages/api/**/*.{js,ts,tsx,json,md,scss,css}'"
},
"devDependencies": {
"husky": "^9.1.7",
"prettier": "3.5.1"
},
"packageManager": "bun@latest"
Expand Down
2 changes: 2 additions & 0 deletions packages/frontend/.env-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VITE_API_BASE_URL=http://127.0.0.1:8000
NODE_ENV=development
8 changes: 7 additions & 1 deletion packages/frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ dist-ssr
*.njsproj
*.sln
*.sw?
/stats.html
/stats.html


.env
.env.local

.vscode
1 change: 0 additions & 1 deletion packages/frontend/.husky/pre-commit

This file was deleted.

64 changes: 33 additions & 31 deletions packages/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@
"prepare": "husky"
},
"dependencies": {
"@mantine/carousel": "^7.17.0",
"@mantine/charts": "^7.17.0",
"@mantine/code-highlight": "^7.17.0",
"@mantine/core": "^7.17.0",
"@mantine/dates": "^7.17.0",
"@mantine/dropzone": "^7.17.0",
"@mantine/form": "^7.17.0",
"@mantine/hooks": "^7.17.0",
"@mantine/modals": "^7.17.0",
"@mantine/notifications": "^7.17.0",
"@mantine/nprogress": "^7.17.0",
"@mantine/spotlight": "^7.17.0",
"@mantine/tiptap": "^7.17.0",
"@mantine/carousel": "^7.17.1",
"@mantine/charts": "^7.17.1",
"@mantine/code-highlight": "^7.17.1",
"@mantine/core": "^7.17.1",
"@mantine/dates": "^7.17.1",
"@mantine/dropzone": "^7.17.1",
"@mantine/form": "^7.17.1",
"@mantine/hooks": "^7.17.1",
"@mantine/modals": "^7.17.1",
"@mantine/notifications": "^7.17.1",
"@mantine/nprogress": "^7.17.1",
"@mantine/spotlight": "^7.17.1",
"@mantine/tiptap": "^7.17.1",
"@pywebflow/api": "workspace:*",
"@radix-ui/react-dialog": "^1.1.6",
"@radix-ui/react-navigation-menu": "^1.2.5",
Expand All @@ -37,22 +37,24 @@
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-toast": "^1.2.6",
"@radix-ui/react-tooltip": "^1.1.8",
"@radix-ui/themes": "^3.2.0",
"@radix-ui/themes": "^3.2.1",
"@tabler/icons-react": "^3.30.0",
"@tailwindcss/postcss": "^4.0.7",
"@tailwindcss/vite": "^4.0.7",
"@tailwindcss/postcss": "^4.0.9",
"@tailwindcss/vite": "^4.0.9",
"@tiptap/extension-link": "^2.11.5",
"@tiptap/pm": "^2.11.5",
"@tiptap/react": "^2.11.5",
"@tiptap/starter-kit": "^2.11.5",
"@xyflow/react": "^12.4.3",
"@xyflow/react": "^12.4.4",
"autoprefixer": "^10.4.20",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"dayjs": "^1.11.13",
"dompurify": "^3.2.4",
"embla-carousel-react": "^8.5.2",
"framer-motion": "^12.4.7",
"lucide-react": "^0.475.0",
"html-react-parser": "^5.2.2",
"lucide-react": "^0.477.0",
"next-themes": "^0.4.4",
"postcss": "^8.5.3",
"react": "^19.0.0",
Expand All @@ -62,30 +64,30 @@
"react-remark": "^2.1.0",
"react-router-dom": "^7.2.0",
"recharts": "^2.15.1",
"sass": "^1.85.0",
"tailwind-merge": "^3.0.1",
"tailwindcss": "^4.0.7",
"sass": "^1.85.1",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.9",
"tailwindcss-animate": "^1.0.7"
},
"license": "apache-2.0",
"devDependencies": {
"eslint-config-prettier": "^10.0.1",
"eslint-plugin-prettier": "^5.2.3",
"@types/node": "^22.13.4",
"@types/node": "^22.13.8",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@typescript-eslint/eslint-plugin": "^8.24.1",
"@typescript-eslint/parser": "^8.24.1",
"@typescript-eslint/eslint-plugin": "^8.25.0",
"@typescript-eslint/parser": "^8.25.0",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.20.1",
"eslint-plugin-react-hooks": "^5.1.0",
"@vitejs/plugin-react-swc": "^3.8.0",
"eslint": "^9.21.0",
"eslint-config-prettier": "^10.0.2",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"husky": "^9.1.7",
"postcss-preset-mantine": "^1.17.0",
"postcss-simple-vars": "^7.0.1",
"rollup-plugin-visualizer": "^5.14.0",
"typescript": "^5.7.3",
"vite": "^6.1.1"
"typescript": "^5.8.2",
"vite": "^6.2.0"
},
"keywords": [
"pywebflow",
Expand Down
32 changes: 24 additions & 8 deletions packages/frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,26 @@ export function App() {
const [sidebarVisible, setSidebarVisible] = useState<boolean>(false);
const [sidebarLabel, setSidebarLabel] = useState<string>('');
const [defaultOpen, setDefaultOpen] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);

useEffect(() => {
const fetchSidebarItems = async () => {
const response: SidebarResponse = await getSidebarItems();
setSidebarItems(response.items);
setSidebarVisible(response.visible);
setSidebarLabel(response.label);
setDefaultOpen(response.default_open);
try {
setLoading(true);
setError(null);

const response: SidebarResponse = await getSidebarItems();
setSidebarItems(response.items);
setSidebarVisible(response.visible);
setSidebarLabel(response.label);
setDefaultOpen(response.default_open);
} catch (err) {
console.error('Error fetching sidebar items:', err);
setError('Failed to load sidebar');
} finally {
setLoading(false);
}
};

fetchSidebarItems();
Expand All @@ -35,16 +47,20 @@ export function App() {
<div className="App h-screen overflow-hidden">
<SidebarProvider defaultOpen={defaultOpen}>
<div className="flex h-full">
{sidebarVisible && (
{loading && <p className="p-4 text-gray-500">Loading sidebar...</p>}
{error && <p className="p-4 text-red-500">{error}</p>}

{!loading && !error && sidebarVisible && (
<AppSidebar items={sidebarItems} label={sidebarLabel} />
)}
{sidebarVisible && <SidebarTrigger />}
{!loading && !error && sidebarVisible && <SidebarTrigger />}

<div className="flex-1 overflow-auto">
<Status />
<ControlsComp />
<MinimapComp />
<BackgroundWrapper />
<InjectedHtml /> {/* Add the InjectedHtml component here */}
<InjectedHtml />
</div>
</div>
</SidebarProvider>
Expand Down
12 changes: 9 additions & 3 deletions packages/frontend/src/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,18 @@ export default function Layout() {
const loadInitialConfig = async () => {
try {
const fetchedConfig = await getConfig();
if (fetchedConfig[0].colorMode) {
setTheme(fetchedConfig[0].colorMode);

if (Array.isArray(fetchedConfig) && fetchedConfig.length > 0) {
if (fetchedConfig[0]?.colorMode) {
setTheme(fetchedConfig[0].colorMode);
}
setConfig(fetchedConfig[0]);
} else {
setConfig({});
}
setConfig(fetchedConfig[0]);
} catch (error) {
console.error('Error fetching initial config:', error);
setConfig({}); // Fallback to empty object on error
}
};

Expand Down
15 changes: 3 additions & 12 deletions packages/frontend/src/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import './styles.ts';
import React, { Suspense, useEffect, useState } from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { MantineProvider } from '@mantine/core';
import { ThemeProvider } from 'next-themes';
import { Theme } from '@radix-ui/themes';
import { HelmetProvider } from 'react-helmet-async';
import './styles/index.scss';
import '@xyflow/react/dist/style.css';
import '@radix-ui/themes/styles.css';
import '@mantine/core/styles.css';
import { loadAndInjectAssets } from './hooks/assets.ts';
import { getConfig } from '@pywebflow/api/src/config';

// Lazy load components with preloading
Expand All @@ -33,22 +29,17 @@ const Root = () => {
);

useEffect(() => {
// Load assets dynamically
loadAndInjectAssets();

// Fetch config data
const fetchConfig = async () => {
try {
const fetchedConfig = await getConfig();
const config = fetchedConfig.data[0];
if (config.colorMode) {
setDefaultTheme(config.colorMode);
if (fetchedConfig?.data?.length > 0) {
setDefaultTheme(fetchedConfig.data[0].colorMode || 'system');
}
} catch (error) {
console.error('Error fetching config:', error);
}
};

fetchConfig();
}, []);

Expand Down
10 changes: 4 additions & 6 deletions packages/frontend/src/components/InjectedHtml.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React, { useEffect, useState } from 'react';
import { fetchHtmlContent } from '@pywebflow/api/src/html';
import DOMPurify from 'dompurify';
import parse from 'html-react-parser';

const InjectedHtml: React.FC = () => {
const [htmlContents, setHtmlContents] = useState<string[]>([]);
Expand All @@ -14,13 +16,9 @@ const InjectedHtml: React.FC = () => {
}, []);

return (
<div className="injected-html-container">
<div>
{htmlContents.map((htmlContent, index) => (
<div
key={index}
className="injected-html"
dangerouslySetInnerHTML={{ __html: htmlContent }}
/>
<div key={index}>{parse(DOMPurify.sanitize(htmlContent))}</div>
))}
</div>
);
Expand Down
8 changes: 6 additions & 2 deletions packages/frontend/src/components/Metadata.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import React, { useEffect, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import getMetadata, { Metadata } from '@pywebflow/api/src/metadata.ts';
import { injectAssets } from '../hooks/assets.ts';

const MetaData: React.FC = () => {
const [metadata, setMetadata] = useState<Metadata>({
title: 'PyWebflow',
description: 'Webflow application',
});

useEffect(() => {
const fetchMetadata = async () => {
const loadMetadataAndAssets = async () => {
await injectAssets(); // Load CSS & JS before fetching metadata

try {
const data = await getMetadata();
setMetadata((prevMetadata) => ({
Expand All @@ -20,7 +24,7 @@ const MetaData: React.FC = () => {
}
};

fetchMetadata();
loadMetadataAndAssets();
}, []);

return (
Expand Down
Loading