<h1 align="center">GingerJs</h1>
<h2 align="center">
✨ 🚀 Full-Stack Development Experience with Python and React ✨ 🚀 <br/>
</h2>
Unlike typical setups where Node.js serves as the backend for frontend applications, this project leverages Python to deliver a comprehensive full-stack solution.
### Install GingerJS
#### Python Environment and Requirements
Create a virtual environment to manage dependencies locally:
```shell
virtualenv env
```
Activate the virtual environment:
```shell
source env/bin/activate
```
Alternatively:
```shell
. env/bin/activate
```
Now, you need to install GingerJS using `pip`. Open your terminal or command prompt and run the following command:
```shell
pip install git+https://github.com/ginger-society/ginger-js.git
```
Alternatively:
```bash
pip install ginger-js
```
### Create your app
```bash
gingerjs create-app
```
### Run server
```bash
gingerjs runserver
```
The application will run on port 5001 by default.
If 5001 is already in use, You can change the default port by adding port in main.py
```python
app.run_app(debug=True, host="0.0.0.0", port=<PORT>)
```
## Main Features
Some of the main py-react features include:
Feature | Description
--- | ---
Routing | A file-system based router built on top of Flask and Server Components that supports layouts, nested routing, loading states, and more.
Rendering | Client-side and Server-side Rendering with Client and Server Components. Further optimized with Static and Dynamic Rendering on the server with py-react.
Styling | Support for your preferred styling methods, including CSS Modules, Tailwind CSS, and CSS-in-JS
## Pre-Requisite Knowledge
Although our docs are designed to be beginner-friendly, we need to establish a baseline so that the docs can stay focused on py-react functionality. We'll make sure to provide links to relevant documentation whenever we introduce a new concept.
To get the most out of our docs, it's recommended that you have a basic understanding of Flask,HTML, CSS, and React. If you need to brush up on your React skills, check out this [React Foundations Course](https://nextjs.org/learn/react-foundations) and [FLask](https://flask.palletsprojects.com/en/3.0.x/), which will introduce you to the fundamentals.
## Creating your First Page
### Layouts
A layout is UI that is shared between multiple routes. On navigation, layouts preserve state, remain interactive. Layouts can also be nested.
You can define a layout by default exporting a React component from a layout.jsx file. The component will be populated with a child layout (if it exists) or a page during rendering.
```jsx
import React from "react";
import Header from "../components/header";
import { Outlet } from "react-router-dom";
const Layout = (props) => {
return (
<div className="p-4">
<Header />
<Outlet />
</div>
);
};
export default Layout;
```
For example, the layout will be shared with the /dashboard and /dashboard/settings pages:

If you were to combine the two layouts above, the root layout (app/layout.jsx) would wrap the dashboard layout (app/dashboard/layout.jsx), which would wrap route segments inside app/dashboard/*.
The two layouts would be nested as such:

## Linking and Navigating
There are currently two ways to navigate between routes in gingerJs:
- Using the Link Component (currently exported from libs)
- Using the useNavigate hook (currently exported from libs)
This page will go through how to use each of these options, and dive deeper into how navigation works.
## Dynamic Routes
When you don't know the exact segment names ahead of time and want to create routes from dynamic data, you can use Dynamic Segments that are filled in at request time.
### Convention
A Dynamic Segment can be created by wrapping a folder's name in square brackets: [folderName]. For example, [id] or [slug].
You can use useParam hook to get the values in component/pages
For ecample if your folder structure looks like `src/app/products/[productId]/index.jsx`
```jsx
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
function Product() {
const { productId } = useParams();
return (
<>
{productId}
</>
);
}
export default Product;
```
Alternatively:
```jsx
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
function Product({productId}) {
return (
<>
{productId}
</>
);
}
export default Product;
```
## Server-Side Props
In a Python environment, you can fetch data, interact with the database, and pass the data to your page.
### Convention
The server logic is placed alongside `index.jsx` and `layout.jsx` within the same folder and is named `index.py`.
### Example
#### Server Example
Path Example : `src/app/index.py`
```python
import requests
def index(request):
api_url = f'https://dummyjson.com/products/' # Replace this with the URL of the API you want to fetch data from
# ----or---
# productId = request.args.get("productId")
# api_url = f'https://dummyjson.com/products/
response = requests.get(api_url)
if response.status_code == 200:
data = response.json()
return {"products":{data}}
return {"products":{"data": None,"error":{"message":"Something went wrong! Please try again"}}}
```
#### Component Example
Path Example : src/app/products/[productId]/index.jsx
```jsx
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
function Products({products}) {
return (
<>
{JSON.stringify(products,null,4)}
</>
);
}
export default Products;
```
#### layout server Example
If you want to pass props to layout you just have to define a layout in your `index.py`
Path Example : `src/app/index.py`
```python
def layout(request):
return {"serverData":"some_data"}
```
#### layout client Example
Path Example : src/app/layout.jsx (will be visible to all subroute)
```jsx
function Layout({serverData}) {
return (
<>
<div className="p-0 m-0">
<Header data={serverData}/>
<Outlet />
</div>
</>
);
}
export default Layout;
```
#### Middleware Example
Or you want attach a middleware, Just define a middleware in `index.py`
Path Example : `src/app/index.py`
```python
def middleware(request,abort):
token = request.headers.get('X-Auth-Token')
if token != 'secret-token':
return abort(401,{"error":"No Auth"})
return
```
#### Api Example
Path Example : `src/app/api/product/index.py`
```python
def GET(request):
data = {}
for key,value in request.args.items():
data[key] = value
return {"query":data}
```
Enjoy your full-stack development experience with Python and React!
#### Using styled-components
Inside your root `layout.jsx` define getAppContext function
```jsx
import { ServerStyleSheet } from 'styled-components';
async getAppContext = (ctx)=>{
const sheet = new ServerStyleSheet();
ctx.renderApp:()=>({
enhanceApp:(App)=>App,
getStyles:(App)=>sheet.collectStyles(App),
styles:()=>sheet.getStyleTags(),
finally:()=>{
sheet.seal()
}
})
return ctx
}
```
#### Using Theme
Inside your root `layout.jsx`
```jsx
import React from "react";
import { Outlet } from "react-router-dom";
import { ThemeProvider } from "src/libs/theme-provider"
function Layout(props) {
return (
<ThemeProvider attribute="class" defaultTheme="light" enableSystem>
<div className="p-0 m-0 dark:bg-gray-800 dark:text-white">
{/* Layout component */}
<Outlet />
</div>
</ThemeProvider>
)
}
```
Add Meta Data
```python
# add the below in your index.py file
def meta_data():
return {
"title": "Ginger-Js",
"description": "Some Description",
"og:description": "Description Here",
"icon":"/static/images/favicon.ico"
}
```
## Using this project locally
Clone this repo and run
```bash
pip install absolute/relative/path/to/repo
```
Raw data
{
"_id": null,
"home_page": "https://github.com/ginger-society/ginger-js",
"name": "ginger-js",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11.0",
"maintainer_email": null,
"keywords": null,
"author": "py-react",
"author_email": "yksandeep08+reactpy@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/da/b7/715bd6f8352e69f763636f3da3ebe09e289709ecb72e3b5d1d3df27608ad/ginger_js-0.0.3.tar.gz",
"platform": null,
"description": "<h1 align=\"center\">GingerJs</h1>\n<h2 align=\"center\">\n \u2728 \ud83d\ude80 Full-Stack Development Experience with Python and React \u2728 \ud83d\ude80 <br/>\n</h2>\n\nUnlike typical setups where Node.js serves as the backend for frontend applications, this project leverages Python to deliver a comprehensive full-stack solution.\n\n### Install GingerJS\n\n#### Python Environment and Requirements\nCreate a virtual environment to manage dependencies locally:\n```shell\nvirtualenv env\n```\nActivate the virtual environment:\n```shell\nsource env/bin/activate\n```\nAlternatively:\n\n```shell\n. env/bin/activate\n```\n\n\nNow, you need to install GingerJS using `pip`. Open your terminal or command prompt and run the following command:\n\n\n```shell\npip install git+https://github.com/ginger-society/ginger-js.git\n```\nAlternatively:\n\n```bash\npip install ginger-js\n```\n\n\n### Create your app\n\n```bash\ngingerjs create-app\n```\n\n### Run server\n\n```bash\ngingerjs runserver\n```\n\n\nThe application will run on port 5001 by default.\nIf 5001 is already in use, You can change the default port by adding port in main.py \n```python\napp.run_app(debug=True, host=\"0.0.0.0\", port=<PORT>)\n```\n\n## Main Features\nSome of the main py-react features include:\n\nFeature | Description\n--- | --- \nRouting | A file-system based router built on top of Flask and Server Components that supports layouts, nested routing, loading states, and more. \nRendering | Client-side and Server-side Rendering with Client and Server Components. Further optimized with Static and Dynamic Rendering on the server with py-react.\nStyling | Support for your preferred styling methods, including CSS Modules, Tailwind CSS, and CSS-in-JS\n\n## Pre-Requisite Knowledge\nAlthough our docs are designed to be beginner-friendly, we need to establish a baseline so that the docs can stay focused on py-react functionality. We'll make sure to provide links to relevant documentation whenever we introduce a new concept.\n\nTo get the most out of our docs, it's recommended that you have a basic understanding of Flask,HTML, CSS, and React. If you need to brush up on your React skills, check out this [React Foundations Course](https://nextjs.org/learn/react-foundations) and [FLask](https://flask.palletsprojects.com/en/3.0.x/), which will introduce you to the fundamentals.\n\n\n## Creating your First Page\n\n### Layouts\nA layout is UI that is shared between multiple routes. On navigation, layouts preserve state, remain interactive. Layouts can also be nested.\n\nYou can define a layout by default exporting a React component from a layout.jsx file. The component will be populated with a child layout (if it exists) or a page during rendering.\n```jsx\nimport React from \"react\";\nimport Header from \"../components/header\";\nimport { Outlet } from \"react-router-dom\";\n\nconst Layout = (props) => {\n return (\n <div className=\"p-4\">\n <Header />\n <Outlet />\n </div>\n );\n};\n\nexport default Layout;\n\n```\n\nFor example, the layout will be shared with the /dashboard and /dashboard/settings pages:\n\n\nIf you were to combine the two layouts above, the root layout (app/layout.jsx) would wrap the dashboard layout (app/dashboard/layout.jsx), which would wrap route segments inside app/dashboard/*.\n\nThe two layouts would be nested as such:\n\n\n## Linking and Navigating\nThere are currently two ways to navigate between routes in gingerJs:\n\n- Using the Link Component (currently exported from libs)\n- Using the useNavigate hook (currently exported from libs)\n\nThis page will go through how to use each of these options, and dive deeper into how navigation works.\n\n## Dynamic Routes\nWhen you don't know the exact segment names ahead of time and want to create routes from dynamic data, you can use Dynamic Segments that are filled in at request time.\n\n### Convention\nA Dynamic Segment can be created by wrapping a folder's name in square brackets: [folderName]. For example, [id] or [slug].\n\nYou can use useParam hook to get the values in component/pages\nFor ecample if your folder structure looks like `src/app/products/[productId]/index.jsx`\n```jsx\nimport React, { useEffect, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\n\nfunction Product() {\n const { productId } = useParams();\n return (\n <>\n {productId}\n </>\n );\n}\n\nexport default Product;\n\n```\nAlternatively:\n```jsx\nimport React, { useEffect, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\n\nfunction Product({productId}) {\n return (\n <>\n {productId}\n </>\n );\n}\n\nexport default Product;\n\n```\n\n## Server-Side Props\n\nIn a Python environment, you can fetch data, interact with the database, and pass the data to your page.\n\n### Convention\n\nThe server logic is placed alongside `index.jsx` and `layout.jsx` within the same folder and is named `index.py`.\n\n### Example\n#### Server Example\nPath Example : `src/app/index.py`\n```python\nimport requests\n\ndef index(request):\n api_url = f'https://dummyjson.com/products/' # Replace this with the URL of the API you want to fetch data from\n # ----or---\n # productId = request.args.get(\"productId\")\n # api_url = f'https://dummyjson.com/products/\n \n response = requests.get(api_url)\n\n if response.status_code == 200:\n data = response.json()\n return {\"products\":{data}}\n return {\"products\":{\"data\": None,\"error\":{\"message\":\"Something went wrong! Please try again\"}}}\n\n```\n\n#### Component Example\nPath Example : src/app/products/[productId]/index.jsx\n```jsx\nimport React, { useEffect, useState } from \"react\";\nimport { useParams } from \"react-router-dom\";\n\nfunction Products({products}) {\n return (\n <>\n {JSON.stringify(products,null,4)}\n </>\n );\n}\n\nexport default Products;\n```\n\n#### layout server Example\nIf you want to pass props to layout you just have to define a layout in your `index.py`\n\nPath Example : `src/app/index.py`\n```python\n\ndef layout(request):\n return {\"serverData\":\"some_data\"}\n```\n\n\n#### layout client Example\nPath Example : src/app/layout.jsx (will be visible to all subroute)\n```jsx\nfunction Layout({serverData}) {\n return (\n <>\n <div className=\"p-0 m-0\">\n <Header data={serverData}/>\n <Outlet />\n </div>\n </>\n );\n}\n\nexport default Layout;\n```\n\n#### Middleware Example\n\nOr you want attach a middleware, Just define a middleware in `index.py`\n\nPath Example : `src/app/index.py`\n```python\ndef middleware(request,abort):\n token = request.headers.get('X-Auth-Token')\n if token != 'secret-token':\n return abort(401,{\"error\":\"No Auth\"})\n return\n\n```\n\n#### Api Example\nPath Example : `src/app/api/product/index.py`\n```python\n\ndef GET(request):\n data = {}\n for key,value in request.args.items():\n data[key] = value\n return {\"query\":data}\n\n```\n\nEnjoy your full-stack development experience with Python and React!\n\n#### Using styled-components\nInside your root `layout.jsx` define getAppContext function\n\n```jsx\nimport { ServerStyleSheet } from 'styled-components';\n\nasync getAppContext = (ctx)=>{\n const sheet = new ServerStyleSheet();\n ctx.renderApp:()=>({\n enhanceApp:(App)=>App,\n getStyles:(App)=>sheet.collectStyles(App),\n styles:()=>sheet.getStyleTags(),\n finally:()=>{\n sheet.seal()\n }\n })\n return ctx\n}\n\n```\n\n\n#### Using Theme\nInside your root `layout.jsx`\n\n```jsx\nimport React from \"react\";\nimport { Outlet } from \"react-router-dom\";\nimport { ThemeProvider } from \"src/libs/theme-provider\"\n\nfunction Layout(props) {\n return (\n <ThemeProvider attribute=\"class\" defaultTheme=\"light\" enableSystem>\n <div className=\"p-0 m-0 dark:bg-gray-800 dark:text-white\">\n {/* Layout component */}\n <Outlet />\n </div>\n </ThemeProvider>\n )\n}\n```\n\nAdd Meta Data \n```python\n# add the below in your index.py file\ndef meta_data():\n return {\n \"title\": \"Ginger-Js\",\n \"description\": \"Some Description\",\n \"og:description\": \"Description Here\",\n \"icon\":\"/static/images/favicon.ico\"\n }\n```\n\n\n## Using this project locally\n\nClone this repo and run\n\n```bash\npip install absolute/relative/path/to/repo\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "A Truly Full-Stack Development Experience with Python and React",
"version": "0.0.3",
"project_urls": {
"Homepage": "https://github.com/ginger-society/ginger-js"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d4508fee386d87549507c8e1771e385b6ea32e9d16eb8171e993ac1e79bc0e21",
"md5": "5e5efc19fc217cfe2a8a018ac2fa9986",
"sha256": "fd7fab728651255b2c616932cf39643a865a5bd5e7475e20907accae410359cf"
},
"downloads": -1,
"filename": "ginger_js-0.0.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5e5efc19fc217cfe2a8a018ac2fa9986",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11.0",
"size": 49273,
"upload_time": "2024-08-02T08:38:18",
"upload_time_iso_8601": "2024-08-02T08:38:18.320395Z",
"url": "https://files.pythonhosted.org/packages/d4/50/8fee386d87549507c8e1771e385b6ea32e9d16eb8171e993ac1e79bc0e21/ginger_js-0.0.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "dab7715bd6f8352e69f763636f3da3ebe09e289709ecb72e3b5d1d3df27608ad",
"md5": "81e37faf480fdcf3b9114244ccd35609",
"sha256": "c63465050fad816355d465ee62eaecea5658e7fa7a83a82ba13e0bd978f30338"
},
"downloads": -1,
"filename": "ginger_js-0.0.3.tar.gz",
"has_sig": false,
"md5_digest": "81e37faf480fdcf3b9114244ccd35609",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11.0",
"size": 40512,
"upload_time": "2024-08-02T08:38:20",
"upload_time_iso_8601": "2024-08-02T08:38:20.185546Z",
"url": "https://files.pythonhosted.org/packages/da/b7/715bd6f8352e69f763636f3da3ebe09e289709ecb72e3b5d1d3df27608ad/ginger_js-0.0.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-02 08:38:20",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ginger-society",
"github_project": "ginger-js",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [],
"lcname": "ginger-js"
}