ipygraph 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ipygraph-0.1.0/LICENSE ADDED
@@ -0,0 +1,87 @@
1
+ IPYGRAPH COMMUNITY & COMMERCIAL LICENSE (NO-MODIFICATION)
2
+ Version 1.1 — 22 June 2025
3
+ © 2025 Your Name. All rights reserved.
4
+
5
+ ──────────────────────────────────────────────────────────────────────────────
6
+ Preamble
7
+ This license grants two sets of rights:
8
+ ▸ “Personal Use” — free of charge for natural persons, strictly
9
+ non-commercial, **without the right to modify** the Software.
10
+ ▸ “Commercial Use” — requires a paid agreement for any organizational
11
+ or revenue-generating use, also **without the right to modify** the
12
+ Software unless expressly permitted in that separate contract.
13
+ ──────────────────────────────────────────────────────────────────────────────
14
+
15
+ DEFINITIONS
16
+ -----------
17
+ “Software” means all source code, binaries, assets, and documentation
18
+ contained in the ‘ipygraph’ package and any derivative
19
+ distribution of it made by the Licensor.
20
+
21
+ “Personal Use” means use by an individual natural person exclusively for
22
+ private, non-commercial purposes and **not** on behalf of
23
+ any Commercial Entity.
24
+
25
+ “Commercial Entity” means any corporation, partnership, sole trader,
26
+ government agency, non-profit, academic institution,
27
+ or any individual using the Software in connection
28
+ with goods or services offered for monetary or other
29
+ consideration.
30
+
31
+ ──────────────────────────────────────────────────────────────────────────────
32
+ SECTION 1 — PERSONAL USE LICENSE (FREE, NO MODIFICATION)
33
+ ──────────────────────────────────────────────────────────────────────────────
34
+ 1.1 Grant. Subject to compliance with this License, the Licensor grants any
35
+ natural person (“User”) a worldwide, royalty-free, non-exclusive,
36
+ revocable license to **install and run** the unmodified Software on an
37
+ unlimited number of devices for Personal Use.
38
+
39
+ 1.2 Restrictions. The User SHALL NOT:
40
+ (a) modify, translate, reverse-engineer, decompile, or disassemble the
41
+ Software, in whole or in part;
42
+ (b) redistribute, sublicense, sell, rent, lease, lend, or otherwise
43
+ make the Software available to third parties;
44
+ (c) use the Software for any commercial, professional, or revenue-
45
+ generating activity.
46
+
47
+ Any breach of 1.2 immediately terminates this Personal Use License.
48
+
49
+ ──────────────────────────────────────────────────────────────────────────────
50
+ SECTION 2 — COMMERCIAL USE (PAID LICENSE REQUIRED)
51
+ ──────────────────────────────────────────────────────────────────────────────
52
+ 2.1 No rights are granted for Commercial Use under this document. A
53
+ separate written Commercial License agreement with the Licensor and
54
+ full payment of the applicable fee are required **before** any
55
+ commercial, organizational, or revenue-generating use.
56
+
57
+ 2.2 The Commercial License may, at the Licensor’s discretion, grant limited
58
+ rights to modify the Software; any such rights must be explicitly
59
+ stated in that separate agreement.
60
+
61
+ For inquiries: <you@example.com>
62
+
63
+ ──────────────────────────────────────────────────────────────────────────────
64
+ SECTION 3 — NO SURRENDER OF RIGHTS
65
+ ──────────────────────────────────────────────────────────────────────────────
66
+ All rights not expressly granted herein are reserved by the Licensor.
67
+
68
+ ──────────────────────────────────────────────────────────────────────────────
69
+ SECTION 4 — DISCLAIMER OF WARRANTY
70
+ ──────────────────────────────────────────────────────────────────────────────
71
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
72
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
73
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
74
+ LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
75
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
76
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
77
+
78
+ ──────────────────────────────────────────────────────────────────────────────
79
+ SECTION 5 — TERMINATION
80
+ ──────────────────────────────────────────────────────────────────────────────
81
+ Violation of any term of this License automatically terminates all rights
82
+ granted. Upon termination, the Licensee must cease using and destroy all
83
+ copies of the Software.
84
+
85
+ ──────────────────────────────────────────────────────────────────────────────
86
+ END OF LICENSE
87
+ ──────────────────────────────────────────────────────────────────────────────
@@ -0,0 +1 @@
1
+ include README.md LICENSE
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: ipygraph
3
+ Version: 0.1.0
4
+ Summary: Desktop landing page for ipygraph – PyWebview + React with particles.js
5
+ Author-email: Your Name <you@example.com>
6
+ License: MIT
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: pywebview
11
+ Dynamic: license-file
12
+
13
+ # ipygraph
14
+
15
+ > **A tiny desktop “coming soon” splash for the future *ipygraph* app,
16
+ > built with PyWebview, React 18, and a subtle particles.js background.**
17
+
18
+ ![screenshot](https://raw.githubusercontent.com/your-repo/ipygraph/main/.github/preview.gif)
19
+
20
+ ---
21
+
22
+ ## Features
23
+
24
+ * **Single-file front-end** – React & particles.js are pulled from CDNs; no local web-server needed.
25
+ * **Native window** – Ships as a PyPI package that opens a real desktop window (`chromium-embedded`).
26
+ * **One-liner launch** – `pip install ipygraph && ipygraph` (or `python -m ipygraph`).
27
+ * **Hack-friendly** – Pass `--debug` to open Chromium DevTools and live-edit the UI.
28
+
29
+ ---
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install ipygraph
35
+
36
+ ## License
37
+
38
+ | Audience | Cost | Modification Allowed? | Notes |
39
+ |----------|------|-----------------------|-------|
40
+ | **Individual (personal / hobby)** | **Free** | **No** | Private, non-commercial use only |
41
+ | **Commercial / organizational** | **Paid** | Only if expressly granted in a separate contract | Contact <you@example.com> |
42
+
43
+ Full terms in [LICENSE](LICENSE).
@@ -0,0 +1,31 @@
1
+ # ipygraph
2
+
3
+ > **A tiny desktop “coming soon” splash for the future *ipygraph* app,
4
+ > built with PyWebview, React 18, and a subtle particles.js background.**
5
+
6
+ ![screenshot](https://raw.githubusercontent.com/your-repo/ipygraph/main/.github/preview.gif)
7
+
8
+ ---
9
+
10
+ ## Features
11
+
12
+ * **Single-file front-end** – React & particles.js are pulled from CDNs; no local web-server needed.
13
+ * **Native window** – Ships as a PyPI package that opens a real desktop window (`chromium-embedded`).
14
+ * **One-liner launch** – `pip install ipygraph && ipygraph` (or `python -m ipygraph`).
15
+ * **Hack-friendly** – Pass `--debug` to open Chromium DevTools and live-edit the UI.
16
+
17
+ ---
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pip install ipygraph
23
+
24
+ ## License
25
+
26
+ | Audience | Cost | Modification Allowed? | Notes |
27
+ |----------|------|-----------------------|-------|
28
+ | **Individual (personal / hobby)** | **Free** | **No** | Private, non-commercial use only |
29
+ | **Commercial / organizational** | **Paid** | Only if expressly granted in a separate contract | Contact <you@example.com> |
30
+
31
+ Full terms in [LICENSE](LICENSE).
@@ -0,0 +1,22 @@
1
+ """
2
+ ipygraph
3
+ ~~~~~~~~
4
+ A tiny desktop landing page (PyWebview + React + particles.js).
5
+
6
+ Import and call :pyfunc:`ipygraph.run` to open the window, or just
7
+ execute ``python -m ipygraph`` / run the ``ipygraph`` console-script.
8
+
9
+ :copyright: 2025 Your Name
10
+ :license: MIT, see LICENSE for details.
11
+ """
12
+
13
+ from importlib.metadata import version as _pkg_version
14
+
15
+ from .app import run # re-export for convenience
16
+
17
+ __all__ = ["run", "__version__"]
18
+
19
+ try:
20
+ __version__: str = _pkg_version(__name__)
21
+ except Exception: # local editable install or missing metadata
22
+ __version__ = "0.0.0"
@@ -0,0 +1,3 @@
1
+ from .app import run
2
+
3
+ run()
@@ -0,0 +1,71 @@
1
+ # ipygraph/app.py
2
+ """
3
+ Launch the ipygraph landing-page window.
4
+
5
+ ▫ Prefers Qt (fastest, fewest external deps) but gracefully falls back to
6
+ other back-ends if Qt isn’t available.
7
+ ▫ Use python -m ipygraph --debug to keep Chromium DevTools open.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import importlib.resources as pkg_resources
13
+ import pathlib
14
+ import sys
15
+ from typing import Tuple
16
+
17
+ import webview
18
+
19
+
20
+ def _locate_index_html() -> pathlib.Path:
21
+ """Return the absolute path to static/index.html shipped in this package."""
22
+ return pkg_resources.files(__package__) / "static" / "index.html"
23
+
24
+
25
+ def _choose_gui_order() -> Tuple[str, ...]:
26
+ """
27
+ Return a tuple of back-ends to try in order.
28
+ First Qt, then GTK, then let pywebview decide.
29
+ """
30
+ return ("qt", "gtk", "") # empty string → pywebview default search order
31
+
32
+
33
+ def run() -> None:
34
+ debug = "--debug" in sys.argv
35
+
36
+ html_uri = _locate_index_html().as_uri()
37
+
38
+ # Build the window once; we’ll re-use it for each backend attempt.
39
+ window = webview.create_window(
40
+ title="ipygraph – Coming Soon",
41
+ url=html_uri,
42
+ width=1024,
43
+ height=768,
44
+ resizable=True,
45
+ zoomable=True,
46
+ )
47
+
48
+ for gui in _choose_gui_order():
49
+ try:
50
+ webview.start(debug=debug, gui=gui, http_server=False)
51
+ # If we get here, that GUI worked → announce and exit the loop
52
+ backend = gui or webview.platform.name # name resolved by pywebview
53
+ print(f"[ipygraph] Using GUI backend: {backend}")
54
+ break
55
+ except (webview.exceptions.UnsupportedGUI, ModuleNotFoundError) as e:
56
+ print(f"[ipygraph] GUI '{gui or 'default'}' failed: {e}")
57
+ continue
58
+ else:
59
+ # If every backend fails, raise a helpful error
60
+ raise RuntimeError(
61
+ "ipygraph could not find a working GUI backend.\n"
62
+ "Install one of:\n"
63
+ " • Qt → conda install pyqt pyqtwebengine -c conda-forge\n"
64
+ " • GTK → conda install pygobject gtk3 -c conda-forge\n"
65
+ "or switch to a platform that bundles a backend."
66
+ )
67
+
68
+
69
+ # Enables: python -m ipygraph.app
70
+ if __name__ == "__main__":
71
+ run()
@@ -0,0 +1,142 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>ipygraph | Coming Soon</title>
6
+
7
+ <!-- ============ Global layout & backdrop ============ -->
8
+ <style>
9
+ html, body {
10
+ margin: 0;
11
+ width: 100%;
12
+ height: 100%;
13
+ overflow: hidden;
14
+ background: #000; /* fallback behind canvas */
15
+ }
16
+ #root {
17
+ width: 100%;
18
+ height: 100%;
19
+ position: relative; /* context for centered text */
20
+ }
21
+ #particles-js {
22
+ position: fixed;
23
+ inset: 0;
24
+ z-index: 0; /* behind everything except body */
25
+ }
26
+
27
+ /* ============ Centered text styles ============ */
28
+ .center-text {
29
+ position: absolute;
30
+ top: 50%;
31
+ left: 50%;
32
+ transform: translate(-50%, -50%);
33
+ text-align: center;
34
+ z-index: 1; /* above canvas */
35
+ user-select: none;
36
+ }
37
+ .title {
38
+ margin: 0;
39
+ font: 900 5rem/1 "Segoe UI", sans-serif;
40
+ letter-spacing: .05em;
41
+ color: #fff;
42
+ text-shadow: 0 0 10px rgba(0,0,0,.6);
43
+ }
44
+ .subtitle {
45
+ font: 600 2rem/1.2 "Segoe UI", sans-serif;
46
+ color: #fff;
47
+ }
48
+
49
+ /* ============ Animated letters ============ */
50
+ @keyframes pulse {
51
+ 0%,100% { transform: scale(1); }
52
+ 50% { transform: scale(1.35); }
53
+ }
54
+ .letter {
55
+ display: inline-block;
56
+ animation: pulse 1s ease-in-out infinite;
57
+ }
58
+ </style>
59
+ </head>
60
+
61
+ <body>
62
+ <!-- Particle canvas -->
63
+ <div id="particles-js"></div>
64
+
65
+ <!-- React mount-point -->
66
+ <div id="root"></div>
67
+
68
+ <!-- ============ Libraries ============ -->
69
+ <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
70
+ <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
71
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
72
+ <!-- local copy of particles.js lives in static/vendor/ -->
73
+ <script src="vendor/particles.min.js"></script>
74
+
75
+ <!-- ============ React UI ============ -->
76
+ <script type="text/babel">
77
+ /* Animated subtitle component */
78
+ function ComingSoon({ text }) {
79
+ return (
80
+ <span className="subtitle">
81
+ {text.split("").map((ch, i) => (
82
+ <span
83
+ key={i}
84
+ className="letter"
85
+ style={{ animationDelay: `${i * 0.12}s` }}
86
+ >
87
+ {ch}
88
+ </span>
89
+ ))}
90
+ </span>
91
+ );
92
+ }
93
+
94
+ /* Root component */
95
+ function App() {
96
+ return (
97
+ <div className="center-text">
98
+ <h1 className="title">ipyGraph</h1>
99
+ <ComingSoon text="coming soon" />
100
+ </div>
101
+ );
102
+ }
103
+
104
+ ReactDOM.createRoot(document.getElementById("root")).render(<App />);
105
+ </script>
106
+
107
+ <!-- ============ Particles init ============ -->
108
+ <script>
109
+ window.addEventListener('load', () => {
110
+ particlesJS('particles-js', {
111
+ particles: {
112
+ number: { value: 80, density: { enable: true, value_area: 800 } },
113
+ color: { value: '#ffffff' },
114
+ shape: { type: 'circle' },
115
+ opacity:{ value: 0.5 },
116
+ size: { value: 3 },
117
+ line_linked: {
118
+ enable: true,
119
+ distance: 150,
120
+ color: '#ffffff',
121
+ opacity: 0.4,
122
+ width: 1
123
+ },
124
+ move: { enable: true, speed: 2 }
125
+ },
126
+ interactivity: {
127
+ detect_on: 'canvas',
128
+ events: {
129
+ onhover: { enable: true, mode: 'repulse' },
130
+ onclick: { enable: true, mode: 'push' }
131
+ },
132
+ modes: {
133
+ repulse: { distance: 100, duration: 0.4 },
134
+ push: { particles_nb: 4 }
135
+ }
136
+ },
137
+ retina_detect: true
138
+ });
139
+ });
140
+ </script>
141
+ </body>
142
+ </html>
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Minified by jsDelivr using Terser v5.19.2.
3
+ * Original file: /npm/particles.js@2.0.0/particles.js
4
+ *
5
+ * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
6
+ */
7
+ var pJS=function(e,a){var t=document.querySelector("#"+e+" > .particles-js-canvas-el");this.pJS={canvas:{el:t,w:t.offsetWidth,h:t.offsetHeight},particles:{number:{value:400,density:{enable:!0,value_area:800}},color:{value:"#fff"},shape:{type:"circle",stroke:{width:0,color:"#ff0000"},polygon:{nb_sides:5},image:{src:"",width:100,height:100}},opacity:{value:1,random:!1,anim:{enable:!1,speed:2,opacity_min:0,sync:!1}},size:{value:20,random:!1,anim:{enable:!1,speed:20,size_min:0,sync:!1}},line_linked:{enable:!0,distance:100,color:"#fff",opacity:1,width:1},move:{enable:!0,speed:2,direction:"none",random:!1,straight:!1,out_mode:"out",bounce:!1,attract:{enable:!1,rotateX:3e3,rotateY:3e3}},array:[]},interactivity:{detect_on:"canvas",events:{onhover:{enable:!0,mode:"grab"},onclick:{enable:!0,mode:"push"},resize:!0},modes:{grab:{distance:100,line_linked:{opacity:1}},bubble:{distance:200,size:80,duration:.4},repulse:{distance:200,duration:.4},push:{particles_nb:4},remove:{particles_nb:2}},mouse:{}},retina_detect:!1,fn:{interact:{},modes:{},vendors:{}},tmp:{}};var i=this.pJS;a&&Object.deepExtend(i,a),i.tmp.obj={size_value:i.particles.size.value,size_anim_speed:i.particles.size.anim.speed,move_speed:i.particles.move.speed,line_linked_distance:i.particles.line_linked.distance,line_linked_width:i.particles.line_linked.width,mode_grab_distance:i.interactivity.modes.grab.distance,mode_bubble_distance:i.interactivity.modes.bubble.distance,mode_bubble_size:i.interactivity.modes.bubble.size,mode_repulse_distance:i.interactivity.modes.repulse.distance},i.fn.retinaInit=function(){i.retina_detect&&window.devicePixelRatio>1?(i.canvas.pxratio=window.devicePixelRatio,i.tmp.retina=!0):(i.canvas.pxratio=1,i.tmp.retina=!1),i.canvas.w=i.canvas.el.offsetWidth*i.canvas.pxratio,i.canvas.h=i.canvas.el.offsetHeight*i.canvas.pxratio,i.particles.size.value=i.tmp.obj.size_value*i.canvas.pxratio,i.particles.size.anim.speed=i.tmp.obj.size_anim_speed*i.canvas.pxratio,i.particles.move.speed=i.tmp.obj.move_speed*i.canvas.pxratio,i.particles.line_linked.distance=i.tmp.obj.line_linked_distance*i.canvas.pxratio,i.interactivity.modes.grab.distance=i.tmp.obj.mode_grab_distance*i.canvas.pxratio,i.interactivity.modes.bubble.distance=i.tmp.obj.mode_bubble_distance*i.canvas.pxratio,i.particles.line_linked.width=i.tmp.obj.line_linked_width*i.canvas.pxratio,i.interactivity.modes.bubble.size=i.tmp.obj.mode_bubble_size*i.canvas.pxratio,i.interactivity.modes.repulse.distance=i.tmp.obj.mode_repulse_distance*i.canvas.pxratio},i.fn.canvasInit=function(){i.canvas.ctx=i.canvas.el.getContext("2d")},i.fn.canvasSize=function(){i.canvas.el.width=i.canvas.w,i.canvas.el.height=i.canvas.h,i&&i.interactivity.events.resize&&window.addEventListener("resize",(function(){i.canvas.w=i.canvas.el.offsetWidth,i.canvas.h=i.canvas.el.offsetHeight,i.tmp.retina&&(i.canvas.w*=i.canvas.pxratio,i.canvas.h*=i.canvas.pxratio),i.canvas.el.width=i.canvas.w,i.canvas.el.height=i.canvas.h,i.particles.move.enable||(i.fn.particlesEmpty(),i.fn.particlesCreate(),i.fn.particlesDraw(),i.fn.vendors.densityAutoParticles()),i.fn.vendors.densityAutoParticles()}))},i.fn.canvasPaint=function(){i.canvas.ctx.fillRect(0,0,i.canvas.w,i.canvas.h)},i.fn.canvasClear=function(){i.canvas.ctx.clearRect(0,0,i.canvas.w,i.canvas.h)},i.fn.particle=function(e,a,t){if(this.radius=(i.particles.size.random?Math.random():1)*i.particles.size.value,i.particles.size.anim.enable&&(this.size_status=!1,this.vs=i.particles.size.anim.speed/100,i.particles.size.anim.sync||(this.vs=this.vs*Math.random())),this.x=t?t.x:Math.random()*i.canvas.w,this.y=t?t.y:Math.random()*i.canvas.h,this.x>i.canvas.w-2*this.radius?this.x=this.x-this.radius:this.x<2*this.radius&&(this.x=this.x+this.radius),this.y>i.canvas.h-2*this.radius?this.y=this.y-this.radius:this.y<2*this.radius&&(this.y=this.y+this.radius),i.particles.move.bounce&&i.fn.vendors.checkOverlap(this,t),this.color={},"object"==typeof e.value)if(e.value instanceof Array){var n=e.value[Math.floor(Math.random()*i.particles.color.value.length)];this.color.rgb=hexToRgb(n)}else null!=e.value.r&&null!=e.value.g&&null!=e.value.b&&(this.color.rgb={r:e.value.r,g:e.value.g,b:e.value.b}),null!=e.value.h&&null!=e.value.s&&null!=e.value.l&&(this.color.hsl={h:e.value.h,s:e.value.s,l:e.value.l});else"random"==e.value?this.color.rgb={r:Math.floor(256*Math.random())+0,g:Math.floor(256*Math.random())+0,b:Math.floor(256*Math.random())+0}:"string"==typeof e.value&&(this.color=e,this.color.rgb=hexToRgb(this.color.value));this.opacity=(i.particles.opacity.random?Math.random():1)*i.particles.opacity.value,i.particles.opacity.anim.enable&&(this.opacity_status=!1,this.vo=i.particles.opacity.anim.speed/100,i.particles.opacity.anim.sync||(this.vo=this.vo*Math.random()));var s={};switch(i.particles.move.direction){case"top":s={x:0,y:-1};break;case"top-right":s={x:.5,y:-.5};break;case"right":s={x:1,y:-0};break;case"bottom-right":s={x:.5,y:.5};break;case"bottom":s={x:0,y:1};break;case"bottom-left":s={x:-.5,y:1};break;case"left":s={x:-1,y:0};break;case"top-left":s={x:-.5,y:-.5};break;default:s={x:0,y:0}}i.particles.move.straight?(this.vx=s.x,this.vy=s.y,i.particles.move.random&&(this.vx=this.vx*Math.random(),this.vy=this.vy*Math.random())):(this.vx=s.x+Math.random()-.5,this.vy=s.y+Math.random()-.5),this.vx_i=this.vx,this.vy_i=this.vy;var r=i.particles.shape.type;if("object"==typeof r){if(r instanceof Array){var c=r[Math.floor(Math.random()*r.length)];this.shape=c}}else this.shape=r;if("image"==this.shape){var o=i.particles.shape;this.img={src:o.image.src,ratio:o.image.width/o.image.height},this.img.ratio||(this.img.ratio=1),"svg"==i.tmp.img_type&&null!=i.tmp.source_svg&&(i.fn.vendors.createSvgImg(this),i.tmp.pushing&&(this.img.loaded=!1))}},i.fn.particle.prototype.draw=function(){var e=this;if(null!=e.radius_bubble)var a=e.radius_bubble;else a=e.radius;if(null!=e.opacity_bubble)var t=e.opacity_bubble;else t=e.opacity;if(e.color.rgb)var n="rgba("+e.color.rgb.r+","+e.color.rgb.g+","+e.color.rgb.b+","+t+")";else n="hsla("+e.color.hsl.h+","+e.color.hsl.s+"%,"+e.color.hsl.l+"%,"+t+")";switch(i.canvas.ctx.fillStyle=n,i.canvas.ctx.beginPath(),e.shape){case"circle":i.canvas.ctx.arc(e.x,e.y,a,0,2*Math.PI,!1);break;case"edge":i.canvas.ctx.rect(e.x-a,e.y-a,2*a,2*a);break;case"triangle":i.fn.vendors.drawShape(i.canvas.ctx,e.x-a,e.y+a/1.66,2*a,3,2);break;case"polygon":i.fn.vendors.drawShape(i.canvas.ctx,e.x-a/(i.particles.shape.polygon.nb_sides/3.5),e.y-a/.76,2.66*a/(i.particles.shape.polygon.nb_sides/3),i.particles.shape.polygon.nb_sides,1);break;case"star":i.fn.vendors.drawShape(i.canvas.ctx,e.x-2*a/(i.particles.shape.polygon.nb_sides/4),e.y-a/1.52,2*a*2.66/(i.particles.shape.polygon.nb_sides/3),i.particles.shape.polygon.nb_sides,2);break;case"image":if("svg"==i.tmp.img_type)var s=e.img.obj;else s=i.tmp.img_obj;s&&i.canvas.ctx.drawImage(s,e.x-a,e.y-a,2*a,2*a/e.img.ratio)}i.canvas.ctx.closePath(),i.particles.shape.stroke.width>0&&(i.canvas.ctx.strokeStyle=i.particles.shape.stroke.color,i.canvas.ctx.lineWidth=i.particles.shape.stroke.width,i.canvas.ctx.stroke()),i.canvas.ctx.fill()},i.fn.particlesCreate=function(){for(var e=0;e<i.particles.number.value;e++)i.particles.array.push(new i.fn.particle(i.particles.color,i.particles.opacity.value))},i.fn.particlesUpdate=function(){for(var e=0;e<i.particles.array.length;e++){var a=i.particles.array[e];if(i.particles.move.enable){var t=i.particles.move.speed/2;a.x+=a.vx*t,a.y+=a.vy*t}if(i.particles.opacity.anim.enable&&(1==a.opacity_status?(a.opacity>=i.particles.opacity.value&&(a.opacity_status=!1),a.opacity+=a.vo):(a.opacity<=i.particles.opacity.anim.opacity_min&&(a.opacity_status=!0),a.opacity-=a.vo),a.opacity<0&&(a.opacity=0)),i.particles.size.anim.enable&&(1==a.size_status?(a.radius>=i.particles.size.value&&(a.size_status=!1),a.radius+=a.vs):(a.radius<=i.particles.size.anim.size_min&&(a.size_status=!0),a.radius-=a.vs),a.radius<0&&(a.radius=0)),"bounce"==i.particles.move.out_mode)var n={x_left:a.radius,x_right:i.canvas.w,y_top:a.radius,y_bottom:i.canvas.h};else n={x_left:-a.radius,x_right:i.canvas.w+a.radius,y_top:-a.radius,y_bottom:i.canvas.h+a.radius};if(a.x-a.radius>i.canvas.w?(a.x=n.x_left,a.y=Math.random()*i.canvas.h):a.x+a.radius<0&&(a.x=n.x_right,a.y=Math.random()*i.canvas.h),a.y-a.radius>i.canvas.h?(a.y=n.y_top,a.x=Math.random()*i.canvas.w):a.y+a.radius<0&&(a.y=n.y_bottom,a.x=Math.random()*i.canvas.w),"bounce"===i.particles.move.out_mode)(a.x+a.radius>i.canvas.w||a.x-a.radius<0)&&(a.vx=-a.vx),(a.y+a.radius>i.canvas.h||a.y-a.radius<0)&&(a.vy=-a.vy);if(isInArray("grab",i.interactivity.events.onhover.mode)&&i.fn.modes.grabParticle(a),(isInArray("bubble",i.interactivity.events.onhover.mode)||isInArray("bubble",i.interactivity.events.onclick.mode))&&i.fn.modes.bubbleParticle(a),(isInArray("repulse",i.interactivity.events.onhover.mode)||isInArray("repulse",i.interactivity.events.onclick.mode))&&i.fn.modes.repulseParticle(a),i.particles.line_linked.enable||i.particles.move.attract.enable)for(var s=e+1;s<i.particles.array.length;s++){var r=i.particles.array[s];i.particles.line_linked.enable&&i.fn.interact.linkParticles(a,r),i.particles.move.attract.enable&&i.fn.interact.attractParticles(a,r),i.particles.move.bounce&&i.fn.interact.bounceParticles(a,r)}}},i.fn.particlesDraw=function(){i.canvas.ctx.clearRect(0,0,i.canvas.w,i.canvas.h),i.fn.particlesUpdate();for(var e=0;e<i.particles.array.length;e++){i.particles.array[e].draw()}},i.fn.particlesEmpty=function(){i.particles.array=[]},i.fn.particlesRefresh=function(){cancelRequestAnimFrame(i.fn.checkAnimFrame),cancelRequestAnimFrame(i.fn.drawAnimFrame),i.tmp.source_svg=void 0,i.tmp.img_obj=void 0,i.tmp.count_svg=0,i.fn.particlesEmpty(),i.fn.canvasClear(),i.fn.vendors.start()},i.fn.interact.linkParticles=function(e,a){var t=e.x-a.x,n=e.y-a.y,s=Math.sqrt(t*t+n*n);if(s<=i.particles.line_linked.distance){var r=i.particles.line_linked.opacity-s/(1/i.particles.line_linked.opacity)/i.particles.line_linked.distance;if(r>0){var c=i.particles.line_linked.color_rgb_line;i.canvas.ctx.strokeStyle="rgba("+c.r+","+c.g+","+c.b+","+r+")",i.canvas.ctx.lineWidth=i.particles.line_linked.width,i.canvas.ctx.beginPath(),i.canvas.ctx.moveTo(e.x,e.y),i.canvas.ctx.lineTo(a.x,a.y),i.canvas.ctx.stroke(),i.canvas.ctx.closePath()}}},i.fn.interact.attractParticles=function(e,a){var t=e.x-a.x,n=e.y-a.y;if(Math.sqrt(t*t+n*n)<=i.particles.line_linked.distance){var s=t/(1e3*i.particles.move.attract.rotateX),r=n/(1e3*i.particles.move.attract.rotateY);e.vx-=s,e.vy-=r,a.vx+=s,a.vy+=r}},i.fn.interact.bounceParticles=function(e,a){var t=e.x-a.x,i=e.y-a.y;Math.sqrt(t*t+i*i)<=e.radius+a.radius&&(e.vx=-e.vx,e.vy=-e.vy,a.vx=-a.vx,a.vy=-a.vy)},i.fn.modes.pushParticles=function(e,a){i.tmp.pushing=!0;for(var t=0;t<e;t++)i.particles.array.push(new i.fn.particle(i.particles.color,i.particles.opacity.value,{x:a?a.pos_x:Math.random()*i.canvas.w,y:a?a.pos_y:Math.random()*i.canvas.h})),t==e-1&&(i.particles.move.enable||i.fn.particlesDraw(),i.tmp.pushing=!1)},i.fn.modes.removeParticles=function(e){i.particles.array.splice(0,e),i.particles.move.enable||i.fn.particlesDraw()},i.fn.modes.bubbleParticle=function(e){if(i.interactivity.events.onhover.enable&&isInArray("bubble",i.interactivity.events.onhover.mode)){var a=e.x-i.interactivity.mouse.pos_x,t=e.y-i.interactivity.mouse.pos_y,n=1-(l=Math.sqrt(a*a+t*t))/i.interactivity.modes.bubble.distance;function s(){e.opacity_bubble=e.opacity,e.radius_bubble=e.radius}if(l<=i.interactivity.modes.bubble.distance){if(n>=0&&"mousemove"==i.interactivity.status){if(i.interactivity.modes.bubble.size!=i.particles.size.value)if(i.interactivity.modes.bubble.size>i.particles.size.value){(c=e.radius+i.interactivity.modes.bubble.size*n)>=0&&(e.radius_bubble=c)}else{var r=e.radius-i.interactivity.modes.bubble.size,c=e.radius-r*n;e.radius_bubble=c>0?c:0}var o;if(i.interactivity.modes.bubble.opacity!=i.particles.opacity.value)if(i.interactivity.modes.bubble.opacity>i.particles.opacity.value)(o=i.interactivity.modes.bubble.opacity*n)>e.opacity&&o<=i.interactivity.modes.bubble.opacity&&(e.opacity_bubble=o);else(o=e.opacity-(i.particles.opacity.value-i.interactivity.modes.bubble.opacity)*n)<e.opacity&&o>=i.interactivity.modes.bubble.opacity&&(e.opacity_bubble=o)}}else s();"mouseleave"==i.interactivity.status&&s()}else if(i.interactivity.events.onclick.enable&&isInArray("bubble",i.interactivity.events.onclick.mode)){if(i.tmp.bubble_clicking){a=e.x-i.interactivity.mouse.click_pos_x,t=e.y-i.interactivity.mouse.click_pos_y;var l=Math.sqrt(a*a+t*t),v=((new Date).getTime()-i.interactivity.mouse.click_time)/1e3;v>i.interactivity.modes.bubble.duration&&(i.tmp.bubble_duration_end=!0),v>2*i.interactivity.modes.bubble.duration&&(i.tmp.bubble_clicking=!1,i.tmp.bubble_duration_end=!1)}function p(a,t,n,s,r){if(a!=t)if(i.tmp.bubble_duration_end)null!=n&&(o=a+(a-(s-v*(s-a)/i.interactivity.modes.bubble.duration)),"size"==r&&(e.radius_bubble=o),"opacity"==r&&(e.opacity_bubble=o));else if(l<=i.interactivity.modes.bubble.distance){if(null!=n)var c=n;else c=s;if(c!=a){var o=s-v*(s-a)/i.interactivity.modes.bubble.duration;"size"==r&&(e.radius_bubble=o),"opacity"==r&&(e.opacity_bubble=o)}}else"size"==r&&(e.radius_bubble=void 0),"opacity"==r&&(e.opacity_bubble=void 0)}i.tmp.bubble_clicking&&(p(i.interactivity.modes.bubble.size,i.particles.size.value,e.radius_bubble,e.radius,"size"),p(i.interactivity.modes.bubble.opacity,i.particles.opacity.value,e.opacity_bubble,e.opacity,"opacity"))}},i.fn.modes.repulseParticle=function(e){if(i.interactivity.events.onhover.enable&&isInArray("repulse",i.interactivity.events.onhover.mode)&&"mousemove"==i.interactivity.status){var a=e.x-i.interactivity.mouse.pos_x,t=e.y-i.interactivity.mouse.pos_y,n=Math.sqrt(a*a+t*t),s={x:a/n,y:t/n},r=clamp(1/(o=i.interactivity.modes.repulse.distance)*(-1*Math.pow(n/o,2)+1)*o*100,0,50),c={x:e.x+s.x*r,y:e.y+s.y*r};"bounce"==i.particles.move.out_mode?(c.x-e.radius>0&&c.x+e.radius<i.canvas.w&&(e.x=c.x),c.y-e.radius>0&&c.y+e.radius<i.canvas.h&&(e.y=c.y)):(e.x=c.x,e.y=c.y)}else if(i.interactivity.events.onclick.enable&&isInArray("repulse",i.interactivity.events.onclick.mode))if(i.tmp.repulse_finish||(i.tmp.repulse_count++,i.tmp.repulse_count==i.particles.array.length&&(i.tmp.repulse_finish=!0)),i.tmp.repulse_clicking){var o=Math.pow(i.interactivity.modes.repulse.distance/6,3),l=i.interactivity.mouse.click_pos_x-e.x,v=i.interactivity.mouse.click_pos_y-e.y,p=l*l+v*v,d=-o/p*1;p<=o&&function(){var a=Math.atan2(v,l);if(e.vx=d*Math.cos(a),e.vy=d*Math.sin(a),"bounce"==i.particles.move.out_mode){var t={x:e.x+e.vx,y:e.y+e.vy};(t.x+e.radius>i.canvas.w||t.x-e.radius<0)&&(e.vx=-e.vx),(t.y+e.radius>i.canvas.h||t.y-e.radius<0)&&(e.vy=-e.vy)}}()}else 0==i.tmp.repulse_clicking&&(e.vx=e.vx_i,e.vy=e.vy_i)},i.fn.modes.grabParticle=function(e){if(i.interactivity.events.onhover.enable&&"mousemove"==i.interactivity.status){var a=e.x-i.interactivity.mouse.pos_x,t=e.y-i.interactivity.mouse.pos_y,n=Math.sqrt(a*a+t*t);if(n<=i.interactivity.modes.grab.distance){var s=i.interactivity.modes.grab.line_linked.opacity-n/(1/i.interactivity.modes.grab.line_linked.opacity)/i.interactivity.modes.grab.distance;if(s>0){var r=i.particles.line_linked.color_rgb_line;i.canvas.ctx.strokeStyle="rgba("+r.r+","+r.g+","+r.b+","+s+")",i.canvas.ctx.lineWidth=i.particles.line_linked.width,i.canvas.ctx.beginPath(),i.canvas.ctx.moveTo(e.x,e.y),i.canvas.ctx.lineTo(i.interactivity.mouse.pos_x,i.interactivity.mouse.pos_y),i.canvas.ctx.stroke(),i.canvas.ctx.closePath()}}}},i.fn.vendors.eventsListeners=function(){"window"==i.interactivity.detect_on?i.interactivity.el=window:i.interactivity.el=i.canvas.el,(i.interactivity.events.onhover.enable||i.interactivity.events.onclick.enable)&&(i.interactivity.el.addEventListener("mousemove",(function(e){if(i.interactivity.el==window)var a=e.clientX,t=e.clientY;else a=e.offsetX||e.clientX,t=e.offsetY||e.clientY;i.interactivity.mouse.pos_x=a,i.interactivity.mouse.pos_y=t,i.tmp.retina&&(i.interactivity.mouse.pos_x*=i.canvas.pxratio,i.interactivity.mouse.pos_y*=i.canvas.pxratio),i.interactivity.status="mousemove"})),i.interactivity.el.addEventListener("mouseleave",(function(e){i.interactivity.mouse.pos_x=null,i.interactivity.mouse.pos_y=null,i.interactivity.status="mouseleave"}))),i.interactivity.events.onclick.enable&&i.interactivity.el.addEventListener("click",(function(){if(i.interactivity.mouse.click_pos_x=i.interactivity.mouse.pos_x,i.interactivity.mouse.click_pos_y=i.interactivity.mouse.pos_y,i.interactivity.mouse.click_time=(new Date).getTime(),i.interactivity.events.onclick.enable)switch(i.interactivity.events.onclick.mode){case"push":i.particles.move.enable||1==i.interactivity.modes.push.particles_nb?i.fn.modes.pushParticles(i.interactivity.modes.push.particles_nb,i.interactivity.mouse):i.interactivity.modes.push.particles_nb>1&&i.fn.modes.pushParticles(i.interactivity.modes.push.particles_nb);break;case"remove":i.fn.modes.removeParticles(i.interactivity.modes.remove.particles_nb);break;case"bubble":i.tmp.bubble_clicking=!0;break;case"repulse":i.tmp.repulse_clicking=!0,i.tmp.repulse_count=0,i.tmp.repulse_finish=!1,setTimeout((function(){i.tmp.repulse_clicking=!1}),1e3*i.interactivity.modes.repulse.duration)}}))},i.fn.vendors.densityAutoParticles=function(){if(i.particles.number.density.enable){var e=i.canvas.el.width*i.canvas.el.height/1e3;i.tmp.retina&&(e/=2*i.canvas.pxratio);var a=e*i.particles.number.value/i.particles.number.density.value_area,t=i.particles.array.length-a;t<0?i.fn.modes.pushParticles(Math.abs(t)):i.fn.modes.removeParticles(t)}},i.fn.vendors.checkOverlap=function(e,a){for(var t=0;t<i.particles.array.length;t++){var n=i.particles.array[t],s=e.x-n.x,r=e.y-n.y;Math.sqrt(s*s+r*r)<=e.radius+n.radius&&(e.x=a?a.x:Math.random()*i.canvas.w,e.y=a?a.y:Math.random()*i.canvas.h,i.fn.vendors.checkOverlap(e))}},i.fn.vendors.createSvgImg=function(e){var a=i.tmp.source_svg.replace(/#([0-9A-F]{3,6})/gi,(function(a,t,i,n){if(e.color.rgb)var s="rgba("+e.color.rgb.r+","+e.color.rgb.g+","+e.color.rgb.b+","+e.opacity+")";else s="hsla("+e.color.hsl.h+","+e.color.hsl.s+"%,"+e.color.hsl.l+"%,"+e.opacity+")";return s})),t=new Blob([a],{type:"image/svg+xml;charset=utf-8"}),n=window.URL||window.webkitURL||window,s=n.createObjectURL(t),r=new Image;r.addEventListener("load",(function(){e.img.obj=r,e.img.loaded=!0,n.revokeObjectURL(s),i.tmp.count_svg++})),r.src=s},i.fn.vendors.destroypJS=function(){cancelAnimationFrame(i.fn.drawAnimFrame),t.remove(),pJSDom=null},i.fn.vendors.drawShape=function(e,a,t,i,n,s){var r=n*s,c=n/s,o=180*(c-2)/c,l=Math.PI-Math.PI*o/180;e.save(),e.beginPath(),e.translate(a,t),e.moveTo(0,0);for(var v=0;v<r;v++)e.lineTo(i,0),e.translate(i,0),e.rotate(l);e.fill(),e.restore()},i.fn.vendors.exportImg=function(){window.open(i.canvas.el.toDataURL("image/png"),"_blank")},i.fn.vendors.loadImg=function(e){if(i.tmp.img_error=void 0,""!=i.particles.shape.image.src)if("svg"==e){var a=new XMLHttpRequest;a.open("GET",i.particles.shape.image.src),a.onreadystatechange=function(e){4==a.readyState&&(200==a.status?(i.tmp.source_svg=e.currentTarget.response,i.fn.vendors.checkBeforeDraw()):(console.log("Error pJS - Image not found"),i.tmp.img_error=!0))},a.send()}else{var t=new Image;t.addEventListener("load",(function(){i.tmp.img_obj=t,i.fn.vendors.checkBeforeDraw()})),t.src=i.particles.shape.image.src}else console.log("Error pJS - No image.src"),i.tmp.img_error=!0},i.fn.vendors.draw=function(){"image"==i.particles.shape.type?"svg"==i.tmp.img_type?i.tmp.count_svg>=i.particles.number.value?(i.fn.particlesDraw(),i.particles.move.enable?i.fn.drawAnimFrame=requestAnimFrame(i.fn.vendors.draw):cancelRequestAnimFrame(i.fn.drawAnimFrame)):i.tmp.img_error||(i.fn.drawAnimFrame=requestAnimFrame(i.fn.vendors.draw)):null!=i.tmp.img_obj?(i.fn.particlesDraw(),i.particles.move.enable?i.fn.drawAnimFrame=requestAnimFrame(i.fn.vendors.draw):cancelRequestAnimFrame(i.fn.drawAnimFrame)):i.tmp.img_error||(i.fn.drawAnimFrame=requestAnimFrame(i.fn.vendors.draw)):(i.fn.particlesDraw(),i.particles.move.enable?i.fn.drawAnimFrame=requestAnimFrame(i.fn.vendors.draw):cancelRequestAnimFrame(i.fn.drawAnimFrame))},i.fn.vendors.checkBeforeDraw=function(){"image"==i.particles.shape.type?"svg"==i.tmp.img_type&&null==i.tmp.source_svg?i.tmp.checkAnimFrame=requestAnimFrame(check):(cancelRequestAnimFrame(i.tmp.checkAnimFrame),i.tmp.img_error||(i.fn.vendors.init(),i.fn.vendors.draw())):(i.fn.vendors.init(),i.fn.vendors.draw())},i.fn.vendors.init=function(){i.fn.retinaInit(),i.fn.canvasInit(),i.fn.canvasSize(),i.fn.canvasPaint(),i.fn.particlesCreate(),i.fn.vendors.densityAutoParticles(),i.particles.line_linked.color_rgb_line=hexToRgb(i.particles.line_linked.color)},i.fn.vendors.start=function(){isInArray("image",i.particles.shape.type)?(i.tmp.img_type=i.particles.shape.image.src.substr(i.particles.shape.image.src.length-3),i.fn.vendors.loadImg(i.tmp.img_type)):i.fn.vendors.checkBeforeDraw()},i.fn.vendors.eventsListeners(),i.fn.vendors.start()};function hexToRgb(e){e=e.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,(function(e,a,t,i){return a+a+t+t+i+i}));var a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return a?{r:parseInt(a[1],16),g:parseInt(a[2],16),b:parseInt(a[3],16)}:null}function clamp(e,a,t){return Math.min(Math.max(e,a),t)}function isInArray(e,a){return a.indexOf(e)>-1}Object.deepExtend=function(e,a){for(var t in a)a[t]&&a[t].constructor&&a[t].constructor===Object?(e[t]=e[t]||{},arguments.callee(e[t],a[t])):e[t]=a[t];return e},window.requestAnimFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){window.setTimeout(e,1e3/60)},window.cancelRequestAnimFrame=window.cancelAnimationFrame||window.webkitCancelRequestAnimationFrame||window.mozCancelRequestAnimationFrame||window.oCancelRequestAnimationFrame||window.msCancelRequestAnimationFrame||clearTimeout,window.pJSDom=[],window.particlesJS=function(e,a){"string"!=typeof e&&(a=e,e="particles-js"),e||(e="particles-js");var t=document.getElementById(e),i="particles-js-canvas-el",n=t.getElementsByClassName(i);if(n.length)for(;n.length>0;)t.removeChild(n[0]);var s=document.createElement("canvas");s.className=i,s.style.width="100%",s.style.height="100%",null!=document.getElementById(e).appendChild(s)&&pJSDom.push(new pJS(e,a))},window.particlesJS.load=function(e,a,t){var i=new XMLHttpRequest;i.open("GET",a),i.onreadystatechange=function(a){if(4==i.readyState)if(200==i.status){var n=JSON.parse(a.currentTarget.response);window.particlesJS(e,n),t&&t()}else console.log("Error pJS - XMLHttpRequest status: "+i.status),console.log("Error pJS - File config not found")},i.send()};
8
+ //# sourceMappingURL=/sm/989ad3d344a46ad94354c16dc2512d23ddb937054ab7980adb822f74145374a7.map
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: ipygraph
3
+ Version: 0.1.0
4
+ Summary: Desktop landing page for ipygraph – PyWebview + React with particles.js
5
+ Author-email: Your Name <you@example.com>
6
+ License: MIT
7
+ Requires-Python: >=3.8
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: pywebview
11
+ Dynamic: license-file
12
+
13
+ # ipygraph
14
+
15
+ > **A tiny desktop “coming soon” splash for the future *ipygraph* app,
16
+ > built with PyWebview, React 18, and a subtle particles.js background.**
17
+
18
+ ![screenshot](https://raw.githubusercontent.com/your-repo/ipygraph/main/.github/preview.gif)
19
+
20
+ ---
21
+
22
+ ## Features
23
+
24
+ * **Single-file front-end** – React & particles.js are pulled from CDNs; no local web-server needed.
25
+ * **Native window** – Ships as a PyPI package that opens a real desktop window (`chromium-embedded`).
26
+ * **One-liner launch** – `pip install ipygraph && ipygraph` (or `python -m ipygraph`).
27
+ * **Hack-friendly** – Pass `--debug` to open Chromium DevTools and live-edit the UI.
28
+
29
+ ---
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ pip install ipygraph
35
+
36
+ ## License
37
+
38
+ | Audience | Cost | Modification Allowed? | Notes |
39
+ |----------|------|-----------------------|-------|
40
+ | **Individual (personal / hobby)** | **Free** | **No** | Private, non-commercial use only |
41
+ | **Commercial / organizational** | **Paid** | Only if expressly granted in a separate contract | Contact <you@example.com> |
42
+
43
+ Full terms in [LICENSE](LICENSE).
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ ipygraph/__init__.py
6
+ ipygraph/__main__.py
7
+ ipygraph/app.py
8
+ ipygraph.egg-info/PKG-INFO
9
+ ipygraph.egg-info/SOURCES.txt
10
+ ipygraph.egg-info/dependency_links.txt
11
+ ipygraph.egg-info/entry_points.txt
12
+ ipygraph.egg-info/requires.txt
13
+ ipygraph.egg-info/top_level.txt
14
+ ipygraph/static/index.html
15
+ ipygraph/static/vendor/particles.min.js
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ipygraph = ipygraph.app:run
@@ -0,0 +1 @@
1
+ pywebview
@@ -0,0 +1 @@
1
+ ipygraph
@@ -0,0 +1,19 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ipygraph" # ← new package name
7
+ version = "0.1.0"
8
+ description = "Desktop landing page for ipygraph – PyWebview + React with particles.js"
9
+ authors = [{name = "Your Name", email = "you@example.com"}]
10
+ license = {text = "MIT"}
11
+ readme = "README.md"
12
+ requires-python = ">=3.8"
13
+ dependencies = ["pywebview"]
14
+
15
+ [project.scripts]
16
+ ipygraph = "ipygraph.app:run" # ← installs the console command “ipygraph”
17
+
18
+ [tool.setuptools.package-data]
19
+ "ipygraph" = ["static/**/*"] # include all front-end files
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+