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.
- {ipygraph-0.1.0/ipygraph.egg-info → ipygraph-0.1.1}/PKG-INFO +1 -1
- {ipygraph-0.1.0 → ipygraph-0.1.1}/ipygraph/__init__.py +1 -1
- ipygraph-0.1.1/ipygraph/app.py +108 -0
- ipygraph-0.1.1/ipygraph/static/app.js +68 -0
- ipygraph-0.1.1/ipygraph/static/index.html +23 -0
- ipygraph-0.1.1/ipygraph/static/style.css +41 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1/ipygraph.egg-info}/PKG-INFO +1 -1
- {ipygraph-0.1.0 → ipygraph-0.1.1}/ipygraph.egg-info/SOURCES.txt +3 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1}/pyproject.toml +1 -1
- ipygraph-0.1.0/ipygraph/app.py +0 -71
- {ipygraph-0.1.0 → ipygraph-0.1.1}/LICENSE +0 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1}/MANIFEST.in +0 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1}/README.md +0 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1}/ipygraph/__main__.py +0 -0
- /ipygraph-0.1.0/ipygraph/static/index.html → /ipygraph-0.1.1/ipygraph/static/index_.html +0 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1}/ipygraph/static/vendor/particles.min.js +0 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1}/ipygraph.egg-info/dependency_links.txt +0 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1}/ipygraph.egg-info/entry_points.txt +0 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1}/ipygraph.egg-info/requires.txt +0 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1}/ipygraph.egg-info/top_level.txt +0 -0
- {ipygraph-0.1.0 → ipygraph-0.1.1}/setup.cfg +0 -0
|
@@ -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
|
+
}
|
|
@@ -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.
|
|
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"}
|
ipygraph-0.1.0/ipygraph/app.py
DELETED
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|