0
docs/.nojekyll
Normal file
BIN
docs/assets/absolute-position.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
docs/assets/attribute change.gif
Normal file
|
After Width: | Height: | Size: 232 KiB |
BIN
docs/assets/basics.jpg
Normal file
|
After Width: | Height: | Size: 151 KiB |
BIN
docs/assets/delete.gif
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
docs/assets/drag-and-drop.gif
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
docs/assets/drop-down.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
docs/assets/flex-manager.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
docs/assets/grid-manager.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
docs/assets/label-image.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
docs/assets/layouts.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
docs/assets/plugins.png
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
docs/assets/radio-btn.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
docs/assets/widgetname.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
196
docs/index.html
Normal file
@@ -0,0 +1,196 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Document</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="description" content="Description">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
||||
<!-- <link rel="stylesheet" href="//cdn.jsdelivr.net/gh/LIGMATV/docsify-theme-github/github.css"> -->
|
||||
<!-- <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css"> -->
|
||||
<!-- <link rel="stylesheet" href="//unpkg.com/docsify/themes/dark.css"> -->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="//cdn.jsdelivr.net/npm/docsify-darklight-theme@latest/dist/style.min.css"
|
||||
title="docsify-darklight-theme"
|
||||
type="text/css"
|
||||
/>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.11.3/font/bootstrap-icons.min.css" integrity="sha512-dPXYcDub/aeb08c63jRq/k6GaKccl256JQy/AnOq7CAnEZ9FzSL9wSbcZkMp4R26vBsMLFYH4kQ67/bbV8XaCQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<a href="https://github.com/PaulleDemon/PyUIBuilder" target="_blank" rel="noopener noreferrer">
|
||||
<!-- Github page -->
|
||||
<i class="bi bi-github icon"></i>
|
||||
</a>
|
||||
</nav>
|
||||
<div id="app"></div>
|
||||
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: '',
|
||||
repo: '',
|
||||
homepage: 'intro.md', // You can set this to any file
|
||||
// loadSidebar: true, // Ensure _sidebar.md is loaded if you want to use it
|
||||
loadNavbar: true,
|
||||
search: {
|
||||
maxAge: 86400, // Expiration time, the default one day
|
||||
paths: 'auto',
|
||||
placeholder: 'Type to search',
|
||||
noData: 'No Results!',
|
||||
depth: 6,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<!-- Docsify v4 -->
|
||||
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
||||
<script src="//unpkg.com/docsify@4.13.1/lib/plugins/search.min.js"></script>
|
||||
<script
|
||||
src="//cdn.jsdelivr.net/npm/docsify-darklight-theme@latest/dist/index.min.js"
|
||||
type="text/javascript">
|
||||
</script>
|
||||
<style>
|
||||
|
||||
.icon{
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
img{
|
||||
max-width: 850px;
|
||||
}
|
||||
|
||||
body{
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em; /* H1 size */
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.75em; /* H2 size */
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.5em; /* H3 size */
|
||||
}
|
||||
|
||||
|
||||
/* Common styling for all alerts */
|
||||
.alert {
|
||||
padding: 15px;
|
||||
margin: 15px 0;
|
||||
border-radius: 4px;
|
||||
/* background-color: #f6f8fa; */
|
||||
border-left: 4px solid;
|
||||
}
|
||||
|
||||
/* NOTE style (info) */
|
||||
.alert-note {
|
||||
border-color: #0366d6;
|
||||
}
|
||||
.alert-note .alert-title {
|
||||
color: #0366d6;
|
||||
}
|
||||
|
||||
/* WARNING style */
|
||||
.alert-warning {
|
||||
border-color: #ffd33d;
|
||||
}
|
||||
.alert-warning .alert-title {
|
||||
color: #e36209;
|
||||
}
|
||||
|
||||
/* DANGER style */
|
||||
.alert-danger {
|
||||
border-color: #d73a49;
|
||||
}
|
||||
.alert-danger .alert-title {
|
||||
color: #d73a49;
|
||||
}
|
||||
|
||||
/* Title for each alert type */
|
||||
.alert-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* Ensure the text color is readable */
|
||||
.alert p {
|
||||
margin: 0;
|
||||
color: #24292e;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
|
||||
.app-nav {
|
||||
position: fixed;
|
||||
background-color: var(--background, transparent);
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
margin-right: 0 !important;
|
||||
padding: 12px;
|
||||
color: var(--textColor, #fff);
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.app-nav li {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.app-nav p img:nth-child(1) {
|
||||
width: 24px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.app-nav p:nth-child(2) {
|
||||
float: left;
|
||||
font-weight: 600;
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.app-nav li ul {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.app-nav .badge {
|
||||
min-width: 85px !important;
|
||||
max-width: 85px;
|
||||
float: right !important;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.search input, .search .clear-button {
|
||||
margin-top: 15%;
|
||||
}
|
||||
|
||||
section.cover img:first-child {
|
||||
margin-top: 4%;
|
||||
}
|
||||
|
||||
.markdown-section h1 {
|
||||
font-size: 2rem;
|
||||
padding: 40px 0 1rem;
|
||||
margin: 0 !important;
|
||||
}
|
||||
.markdown-section h2 {
|
||||
font-size: 1.75rem;
|
||||
padding: 45px 0 0.8rem;
|
||||
margin: 0 !important;
|
||||
}
|
||||
.markdown-section h3 {
|
||||
font-size: 1.5rem;
|
||||
padding: 40px 0 0.6rem;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 770px) {
|
||||
.search input, .search .clear-button {
|
||||
margin-top: 0%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
135
docs/intro.md
@@ -1,10 +1,37 @@
|
||||
# PyUIBuilder Documentation
|
||||
|
||||
>[!NOTE]
|
||||
This is a temporary documentation, the page will be updated as more features are added.
|
||||
<div class="alert alert-note">
|
||||
<div class="alert-title">NOTE ⚠️</div>
|
||||
Work in progress. This page will be updated from time to time. This contains the basic documentation for PYUIBuilder
|
||||
</div>
|
||||
|
||||
## UI Basics
|
||||
Let's start with the basics of UI
|
||||
|
||||

|
||||
|
||||
1. The sidebar on the left will have multiple buttons, each button will provide you with necessary tools.
|
||||
2. The Place where you drag and drop widgets is the canvas
|
||||
3. The toolbar will only appear if a widget is selected.
|
||||
|
||||
|
||||
## Basics Widgets understanding
|
||||
|
||||
## Canvas
|
||||
|
||||
Things you can do on canvas.
|
||||
|
||||
1. Add widgets from sidebar.
|
||||
2. Zoom and pan using mouse.
|
||||
3. zoom using `+`/`-` keys
|
||||
4. Delete widgets using `del` key or right clicking on the widget
|
||||
|
||||
## Project name
|
||||
By default all project's are named untitled project, you can change this from the header input next to export code.
|
||||
|
||||
## Selecting a UI library
|
||||
You can select the UI library from the header dropdown. Once selected changing the UI library in between your work, will erase the canvas.
|
||||
|
||||
## Widgets
|
||||
|
||||
Every widget has its own attributes, some of the attributes may be common.
|
||||
|
||||
@@ -20,3 +47,105 @@ Every widget has its own attributes, some of the attributes may be common.
|
||||
|
||||
The parents of the child widgets controls the layout. The layout properties such as grid position will be available to the child under the grid-manager/flex-manager section.
|
||||
|
||||
|
||||
All Widgets attributes are available on the toolbar.
|
||||
The toolbar contains collapsible, which can be opened to modify the widgets attributes such
|
||||
as foreground / background colors, themes and more.
|
||||
|
||||
|
||||
### Adding widgets
|
||||
|
||||
Adding widgets are as easy as dragging and dropping widgets from sidebar to canvas
|
||||
|
||||

|
||||
|
||||
### Deleting widgets
|
||||
|
||||
You can either delete the widget by selecting the widget and pressing the `del` button
|
||||
or right-click -> delete
|
||||
|
||||

|
||||
|
||||
### Variable names
|
||||
|
||||
To modify variable name, change the widget name attributes, if there are duplicate names,
|
||||
the code generation engine will automatically add a count to the the variable name, eg: var1, var2.
|
||||
|
||||
Every widget name will be converted
|
||||
to snake case.
|
||||
|
||||

|
||||
|
||||
### Modifying widget attributes
|
||||
|
||||
Widget attributes are available will selected on the toolbar.
|
||||
|
||||

|
||||
|
||||
### Adding images to label
|
||||
|
||||
To add image to label first go to sidebar -> uploads -> upload a image file.
|
||||
|
||||
Now under the label attributes you'll be able to see image upload option. Select the image from the dropdown
|
||||
|
||||

|
||||
|
||||
### Adding options to radio button
|
||||
|
||||
To add more option to radio button click on the radio button widget then on the toolbar ->
|
||||
under radio group -> add input
|
||||
|
||||

|
||||
|
||||
### Adding options to select dropdown.
|
||||
|
||||
Adding more options to select dropdown is similar to radio buttons as shown above.
|
||||
|
||||

|
||||
|
||||
|
||||
## Layouts
|
||||
|
||||
There are 3 main layouts. The layouts are set by the parents. Once a layout is set
|
||||
every child widget will use the same layout for positioning. The ony exception is if
|
||||
you have enabled absolute positioning from the child widgets toolbar.
|
||||
|
||||

|
||||
|
||||
Depending on the layout selected your child widgets will be provided with
|
||||
flex-manager / grid-manager.
|
||||
|
||||

|
||||
|
||||
### Flex
|
||||
Flex is similar to pack in tkinter, the widgets will be arranged horizontally/vertically
|
||||
depending on the flex-direction
|
||||
|
||||
### Grid
|
||||
Grid is a 2d layout manager, you can position each widget by clicking on widget -> toolbar -> grid-manager
|
||||
|
||||

|
||||
|
||||
|
||||
### Absolute positioning
|
||||
You can use position absolute for specific widget by checking the absolute positing attribute
|
||||
|
||||

|
||||
|
||||
|
||||
## Plugins
|
||||
|
||||
Plugins are third party UI libraries. You can drag and drop the plugins just like widgets onto the canvas. The plugin card on the sidebar contains information about the library, such as library repo and license.
|
||||
|
||||

|
||||
|
||||
|
||||
## Exporting code
|
||||
Once you are happy with the UI, you can click on export code from the header.
|
||||
|
||||
## Requirements.txt
|
||||
The requirements.txt files are auto generated, before running the code ensure you have installed the dependencies.
|
||||
|
||||
## Saving the file
|
||||
|
||||
Files are not saved or stored. However this is an upcoming feature for the [Premium users](https://github.com/PaulleDemon/PyUIBuilder?tab=readme-ov-file#license---fund-the-development)
|
||||
1361
package-lock.json
generated
@@ -34,9 +34,9 @@
|
||||
"build": "GENERATE_SOURCEMAP=false env-cmd -e production react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
|
||||
"start:tailwind": "cross-env NODE_ENV=development tailwindcss --postcss -i ./landingpages/tailwind/tailwind.css -o ./landingpages/tailwind/tailwind-runtime.css -w",
|
||||
"build:tailwind": "cross-env NODE_ENV=production tailwindcss --postcss -i ./landingpages/tailwind/tailwind.css -o ./landingpages/tailwind/tailwind-build.css --minify"
|
||||
"build:tailwind": "cross-env NODE_ENV=production tailwindcss --postcss -i ./landingpages/tailwind/tailwind.css -o ./landingpages/tailwind/tailwind-build.css --minify",
|
||||
"docs:serve": "docsify serve ./docs/"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
@@ -57,6 +57,7 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"ajv": "^7.2.4"
|
||||
"ajv": "^7.2.4",
|
||||
"docsify-cli": "^4.4.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ class Canvas extends React.Component {
|
||||
for (let [key, widget] of Object.entries(this.widgetRefs)) {
|
||||
// since the mouseUp event is not triggered inside the widget once its outside,
|
||||
// we'll need a global mouse up event to re-enable drag
|
||||
widget.current.enableDrag()
|
||||
widget.current?.enableDrag()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,6 +918,7 @@ class Canvas extends React.Component {
|
||||
|
||||
this.setState({
|
||||
toolbarAttrs: null,
|
||||
toolbarOpen: false,
|
||||
selectedWidget: null
|
||||
})
|
||||
|
||||
@@ -926,7 +927,7 @@ class Canvas extends React.Component {
|
||||
for (let widgetId of widgetIds) {
|
||||
this.removeWidget(widgetId)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -645,8 +645,8 @@ class Widget extends React.Component {
|
||||
*/
|
||||
setWidgetSize(width, height) {
|
||||
|
||||
const fitWidth = this.state.fitContent.width || true
|
||||
const fitHeight = this.state.fitContent.height || true
|
||||
const fitWidth = this.state.fitContent?.width
|
||||
const fitHeight = this.state.fitContent?.height
|
||||
|
||||
if (fitWidth && fitHeight){
|
||||
message.warning("both width and height are set to fit-content, unset it to start resizing")
|
||||
|
||||
@@ -39,10 +39,12 @@ class AnalogTimePicker extends TkinterBase{
|
||||
|
||||
this.timePickerRef = React.createRef()
|
||||
|
||||
this.minSize = {width: 100, height: 100}
|
||||
|
||||
this.state = {
|
||||
...this.state,
|
||||
widgetName: "Timepicker",
|
||||
size: { width: 'fit', height: 'fit' },
|
||||
size: { width: 250, height: 350 },
|
||||
attrs: {
|
||||
...newAttrs,
|
||||
styling: {
|
||||
@@ -118,7 +120,9 @@ class AnalogTimePicker extends TkinterBase{
|
||||
super.componentDidMount()
|
||||
this.timePicker = timePicker({
|
||||
element: this.timePickerRef.current,
|
||||
mode: "12"
|
||||
mode: "12",
|
||||
width: this.state.size.width,
|
||||
// height: this.state.size.height
|
||||
})
|
||||
|
||||
// used to remove ok and cancel buttons
|
||||
@@ -132,6 +136,11 @@ class AnalogTimePicker extends TkinterBase{
|
||||
this.timePicker.dispose()
|
||||
}
|
||||
|
||||
setResize(pos, size){
|
||||
super.setResize(pos, size)
|
||||
this.timePicker.setWidth(size.width)
|
||||
}
|
||||
|
||||
handleThemeChange(value){
|
||||
this.setAttrValue("styling.theme", value)
|
||||
|
||||
@@ -241,7 +250,7 @@ class AnalogTimePicker extends TkinterBase{
|
||||
return (
|
||||
<div className="tw-w-flex tw-flex-col tw-w-full tw-h-full tw-rounded-md
|
||||
tw-border tw-border-solid tw-border-gray-400 tw-overflow-hidden">
|
||||
<div className="tw-p-2 tw-w-full tw-h-full tw-content-start tw-pointer-events-none"
|
||||
<div className="tw-p-2 tw-w-full tw-h-full tw-flex tw-content-start tw-pointer-events-none"
|
||||
style={timePickerStyling}
|
||||
ref={this.timePickerRef}>
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ class VideoPlayer extends TkinterBase{
|
||||
|
||||
this.state = {
|
||||
...this.state,
|
||||
size: { width: 'fit', height: 'fit' },
|
||||
size: { width: 350, height: 200 },
|
||||
widgetName: "Video player",
|
||||
attrs: {
|
||||
...newAttrs,
|
||||
|
||||
@@ -93,9 +93,13 @@ export class TkinterBase extends Widget {
|
||||
parentLayout: layout,
|
||||
}
|
||||
|
||||
this.removeAttr("gridManager")
|
||||
this.removeAttr("flexManager")
|
||||
this.removeAttr("positioning")
|
||||
// this.removeAttr("gridManager")
|
||||
// this.removeAttr("flexManager")
|
||||
// this.removeAttr("positioning")
|
||||
|
||||
// remove gridManager, flexManager positioning
|
||||
const {gridManager, flexManager, positioning, ...restAttrs} = this.state.attrs
|
||||
|
||||
if (parentLayout === Layouts.FLEX || parentLayout === Layouts.GRID) {
|
||||
|
||||
updates = {
|
||||
@@ -104,7 +108,7 @@ export class TkinterBase extends Widget {
|
||||
}
|
||||
// Allow optional absolute positioning if the parent layout is flex or grid
|
||||
const updateAttrs = {
|
||||
...this.state.attrs,
|
||||
...restAttrs,
|
||||
positioning: {
|
||||
label: "Absolute positioning",
|
||||
tool: Tools.CHECK_BUTTON,
|
||||
|
||||