ipygraph 0.1.0__tar.gz → 0.1.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipygraph
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Desktop landing page for ipygraph – PyWebview + React with particles.js
5
5
  Author-email: Your Name <you@example.com>
6
6
  License: MIT
@@ -19,4 +19,4 @@ __all__ = ["run", "__version__"]
19
19
  try:
20
20
  __version__: str = _pkg_version(__name__)
21
21
  except Exception: # local editable install or missing metadata
22
- __version__ = "0.0.0"
22
+ __version__ = "0.1.1"
@@ -0,0 +1,108 @@
1
+ """
2
+ Launch the ipygraph landing-page window.
3
+
4
+ • Prefers Qt (fewest external deps) but gracefully falls back to GTK, etc.
5
+ • Frozen-binary friendly: detects PyInstaller's _MEIPASS.
6
+ • Forces software OpenGL so it runs even on headless/old GPUs.
7
+
8
+ Run python -m ipygraph --debug (or ipygraph --debug) to open DevTools.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ # ---------------------------------------------------------------------------#
14
+ # Environment tweaks — MUST come before importing Qt/Webview
15
+ # ---------------------------------------------------------------------------#
16
+ # import os
17
+
18
+ # # 1) Tell Qt to use Mesa/llvmpipe software renderer
19
+ # os.environ.setdefault("QT_OPENGL", "software")
20
+
21
+ # # 2) Tell QtWebEngine (Chromium) not to rely on GPU
22
+ # os.environ.setdefault(
23
+ # "QTWEBENGINE_CHROMIUM_FLAGS",
24
+ # "--disable-gpu --disable-software-rasterizer",
25
+ # )
26
+
27
+ import os
28
+ os.environ["QT_OPENGL"] = "software"
29
+ os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--disable-gpu --disable-software-rasterizer"
30
+ os.environ["LIBGL_ALWAYS_SOFTWARE"] = "1"
31
+ os.environ["QT_XCB_GL_INTEGRATION"] = "none"
32
+
33
+
34
+ # ---------------------------------------------------------------------------#
35
+ # Standard libs
36
+ # ---------------------------------------------------------------------------#
37
+ import pathlib
38
+ import sys
39
+ from typing import Tuple
40
+ import importlib.resources as pkg_resources
41
+
42
+ # Third-party
43
+ import webview
44
+
45
+
46
+ # ---------------------------------------------------------------------------#
47
+ # Helper functions
48
+ # ---------------------------------------------------------------------------#
49
+ def _locate_index_html() -> pathlib.Path:
50
+ """
51
+ Return the absolute path to static/index.html whether running:
52
+ • from site-packages (pip install)
53
+ • from source tree (editable install)
54
+ • inside a PyInstaller bundle (sys._MEIPASS).
55
+ """
56
+ if hasattr(sys, "_MEIPASS"):
57
+ # PyInstaller extracts package to this temp dir
58
+ base = pathlib.Path(sys._MEIPASS) / "ipygraph" / "static"
59
+ return base / "index.html"
60
+
61
+ # Non-frozen import; importlib.resources is fine
62
+ return pkg_resources.files("ipygraph") / "static" / "index.html"
63
+
64
+
65
+ def _choose_gui_order() -> Tuple[str, ...]:
66
+ """Try Qt first, then GTK, then let PyWebview auto-detect."""
67
+ return ("qt", "gtk", "") # "" → default search order
68
+
69
+
70
+ # ---------------------------------------------------------------------------#
71
+ # Main entry point
72
+ # ---------------------------------------------------------------------------#
73
+ def run() -> None:
74
+ debug = "--debug" in sys.argv
75
+
76
+ html_uri = _locate_index_html().as_uri()
77
+
78
+ # Create the window object once; reused by webview.start()
79
+ webview.create_window(
80
+ title="ipygraph – Coming Soon",
81
+ url=html_uri,
82
+ width=1024,
83
+ height=768,
84
+ resizable=True,
85
+ zoomable=True,
86
+ )
87
+
88
+ for gui in _choose_gui_order():
89
+ try:
90
+ webview.start(debug=debug, gui=gui, http_server=False)
91
+ backend = gui or webview.platform.name
92
+ print(f"[ipygraph] Using GUI backend: {backend}")
93
+ break
94
+ except (webview.exceptions.UnsupportedGUI, ModuleNotFoundError) as exc:
95
+ print(f"[ipygraph] GUI '{gui or 'auto'}' failed: {exc}")
96
+ continue
97
+ else:
98
+ raise RuntimeError(
99
+ "ipygraph could not find a working GUI backend.\n"
100
+ "Install one of:\n"
101
+ " • Qt → conda install pyqt pyqtwebengine -c conda-forge\n"
102
+ " • GTK → conda install pygobject gtk3 -c conda-forge"
103
+ )
104
+
105
+
106
+ # Enables: python -m ipygraph.app
107
+ if __name__ == "__main__":
108
+ run()
@@ -0,0 +1,68 @@
1
+ /* Animated subtitle component */
2
+ function ComingSoon({ text }) {
3
+ return (
4
+ <span className="subtitle">
5
+ {text.split("").map((ch, i) => (
6
+ <span
7
+ key={i}
8
+ className="letter"
9
+ style={{ animationDelay: `${i * 0.12}s` }}
10
+ >
11
+ {ch}
12
+ </span>
13
+ ))}
14
+ </span>
15
+ );
16
+ }
17
+
18
+ /* Root component */
19
+ function App() {
20
+ return (
21
+ <div className="center-text">
22
+ <h1 className="title">ipyGraph</h1>
23
+ <ComingSoon text="coming soon" />
24
+ </div>
25
+ );
26
+ }
27
+
28
+ ReactDOM.createRoot(document.getElementById("root")).render(<App />);
29
+
30
+ /* ---------- Particles background ---------- */
31
+ function initParticles() {
32
+ particlesJS("particles-js", {
33
+ particles: {
34
+ number: { value: 80, density: { enable: true, value_area: 800 } },
35
+ color: { value: "#ffffff" },
36
+ shape: { type: "circle" },
37
+ opacity:{ value: 0.5 },
38
+ size: { value: 3 },
39
+ line_linked: {
40
+ enable: true,
41
+ distance: 150,
42
+ color: "#ffffff",
43
+ opacity: 0.4,
44
+ width: 1
45
+ },
46
+ move: { enable: true, speed: 2 }
47
+ },
48
+ interactivity: {
49
+ detect_on: "canvas",
50
+ events: {
51
+ onhover: { enable: true, mode: "repulse" },
52
+ onclick: { enable: true, mode: "push" }
53
+ },
54
+ modes: {
55
+ repulse: { distance: 100, duration: 0.4 },
56
+ push: { particles_nb: 4 }
57
+ }
58
+ },
59
+ retina_detect: true
60
+ });
61
+ }
62
+
63
+ /* If the HTML is still loading, wait; otherwise run now. */
64
+ if (document.readyState === "loading") {
65
+ window.addEventListener("DOMContentLoaded", initParticles);
66
+ } else {
67
+ initParticles();
68
+ }
@@ -0,0 +1,23 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>ipygraph | Coming Soon</title>
6
+
7
+ <link rel="stylesheet" href="style.css" />
8
+ </head>
9
+ <body>
10
+ <div id="particles-js"></div> <!-- particle canvas -->
11
+ <div id="root"></div> <!-- React mount -->
12
+
13
+ <!-- libraries -->
14
+ <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
15
+ <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
16
+ <script src="https://unpkg.com/@babel/standalone/babel.min.js"
17
+ data-presets="env,react"></script>
18
+ <script src="vendor/particles.min.js"></script>
19
+
20
+ <!-- your code -->
21
+ <script type="text/babel" src="app.js"></script>
22
+ </body>
23
+ </html>
@@ -0,0 +1,41 @@
1
+ /* ========== global layout & backdrop ========== */
2
+ html, body {
3
+ margin: 0;
4
+ width: 100%;
5
+ height: 100%;
6
+ overflow: hidden;
7
+ background: #000;
8
+ }
9
+ #root { width: 100%; height: 100%; position: relative; }
10
+ #particles-js { position: fixed; inset: 0; z-index: 0; width: 100%; height: 100%;}
11
+
12
+ /* ========== centred text ========== */
13
+ .center-text {
14
+ position: absolute;
15
+ top: 50%; left: 50%;
16
+ transform: translate(-50%, -50%);
17
+ text-align: center;
18
+ z-index: 1;
19
+ user-select: none;
20
+ }
21
+ .title {
22
+ margin: 0;
23
+ font: 900 5rem/1 "Segoe UI", sans-serif;
24
+ letter-spacing: .05em;
25
+ color: #fff;
26
+ text-shadow: 0 0 10px rgba(0,0,0,.6);
27
+ }
28
+ .subtitle {
29
+ font: 600 2rem/1.2 "Segoe UI", sans-serif;
30
+ color: #fff;
31
+ }
32
+
33
+ /* ========== animated letters ========== */
34
+ @keyframes pulse {
35
+ 0%,100% { transform: scale(1); }
36
+ 50% { transform: scale(1.35); }
37
+ }
38
+ .letter {
39
+ display: inline-block;
40
+ animation: pulse 1s ease-in-out infinite;
41
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipygraph
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Desktop landing page for ipygraph – PyWebview + React with particles.js
5
5
  Author-email: Your Name <you@example.com>
6
6
  License: MIT
@@ -11,5 +11,8 @@ ipygraph.egg-info/dependency_links.txt
11
11
  ipygraph.egg-info/entry_points.txt
12
12
  ipygraph.egg-info/requires.txt
13
13
  ipygraph.egg-info/top_level.txt
14
+ ipygraph/static/app.js
14
15
  ipygraph/static/index.html
16
+ ipygraph/static/index_.html
17
+ ipygraph/static/style.css
15
18
  ipygraph/static/vendor/particles.min.js
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ipygraph" # ← new package name
7
- version = "0.1.0"
7
+ version = "0.1.1"
8
8
  description = "Desktop landing page for ipygraph – PyWebview + React with particles.js"
9
9
  authors = [{name = "Your Name", email = "you@example.com"}]
10
10
  license = {text = "MIT"}
@@ -1,71 +0,0 @@
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()
File without changes
File without changes
File without changes
File without changes
File without changes