solara-ui 1.39.0__py2.py3-none-any.whl → 1.41.0__py2.py3-none-any.whl
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.
- solara/__init__.py +1 -1
- solara/__main__.py +23 -10
- solara/components/__init__.py +1 -0
- solara/components/component_vue.py +3 -2
- solara/components/input_text_area.py +86 -0
- solara/components/markdown.py +1 -1
- solara/hooks/use_thread.py +4 -4
- solara/lab/components/chat.py +8 -2
- solara/server/assets/style.css +4 -1
- solara/server/flask.py +1 -1
- solara/server/jupyter/server_extension.py +11 -1
- solara/server/jupyter/solara.py +91 -0
- solara/server/patch.py +1 -0
- solara/server/pyinstaller/__init__.py +9 -0
- solara/server/pyinstaller/hook-ipyreact.py +5 -0
- solara/server/pyinstaller/hook-ipyvuetify.py +5 -0
- solara/server/pyinstaller/hook-solara.py +9 -0
- solara/server/qt.py +113 -0
- solara/server/server.py +6 -1
- solara/server/settings.py +1 -0
- solara/server/starlette.py +18 -6
- solara/server/static/highlight-dark.css +1 -1
- solara/server/static/main-vuetify.js +11 -1
- solara/server/static/solara_bootstrap.py +1 -1
- solara/server/templates/loader-solara.html +1 -1
- solara/server/templates/solara.html.j2 +36 -7
- solara/website/assets/custom.css +20 -57
- solara/website/components/__init__.py +2 -2
- solara/website/components/algolia_api.vue +23 -6
- solara/website/components/breadcrumbs.py +28 -0
- solara/website/components/contact.py +144 -0
- solara/website/components/docs.py +11 -9
- solara/website/components/header.py +31 -20
- solara/website/components/markdown.py +12 -1
- solara/website/components/markdown_nav.vue +34 -0
- solara/website/components/sidebar.py +9 -1
- solara/website/pages/__init__.py +93 -254
- solara/website/pages/about/__init__.py +9 -0
- solara/website/pages/about/about.md +3 -0
- solara/website/pages/careers/__init__.py +27 -0
- solara/website/pages/changelog/__init__.py +2 -2
- solara/website/pages/changelog/changelog.md +12 -0
- solara/website/pages/contact/__init__.py +30 -6
- solara/website/pages/documentation/__init__.py +25 -33
- solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +2 -1
- solara/website/pages/documentation/advanced/content/15-reference/41-asset-files.md +1 -1
- solara/website/pages/documentation/advanced/content/20-understanding/40-routing.md +17 -1
- solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +2 -1
- solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +1 -1
- solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +5 -2
- solara/website/pages/documentation/api/hooks/use_thread.md +6 -0
- solara/website/pages/documentation/components/data/pivot_table.py +2 -2
- solara/website/pages/documentation/components/input/input.py +2 -0
- solara/website/pages/documentation/components/output/sql_code.py +3 -3
- solara/website/pages/documentation/examples/__init__.py +14 -22
- solara/website/pages/documentation/examples/ai/chatbot.py +1 -1
- solara/website/pages/documentation/examples/general/vue_component.py +1 -1
- solara/website/pages/documentation/examples/libraries/altair.py +1 -0
- solara/website/pages/documentation/examples/libraries/bqplot.py +1 -1
- solara/website/pages/documentation/examples/libraries/ipyleaflet.py +1 -1
- solara/website/pages/documentation/examples/libraries/ipyleaflet_advanced.py +1 -1
- solara/website/pages/documentation/examples/utilities/countdown_timer.py +18 -20
- solara/website/pages/documentation/examples/visualization/annotator.py +1 -3
- solara/website/pages/documentation/examples/visualization/linked_views.py +4 -4
- solara/website/pages/documentation/getting_started/content/00-quickstart.md +18 -0
- solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +2 -2
- solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +19 -14
- solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +205 -15
- solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +3 -1
- solara/website/pages/home.vue +1199 -0
- solara/website/pages/our_team/__init__.py +83 -0
- solara/website/pages/pricing/__init__.py +31 -0
- solara/website/pages/roadmap/__init__.py +11 -0
- solara/website/pages/roadmap/roadmap.md +41 -0
- solara/website/pages/scale_ipywidgets.py +45 -0
- solara/widgets/vue/navigator.vue +46 -16
- solara/widgets/vue/vegalite.vue +18 -0
- {solara_ui-1.39.0.dist-info → solara_ui-1.41.0.dist-info}/METADATA +2 -2
- {solara_ui-1.39.0.dist-info → solara_ui-1.41.0.dist-info}/RECORD +83 -66
- solara/website/components/hero.py +0 -15
- solara/website/pages/contact/contact.md +0 -17
- {solara_ui-1.39.0.data → solara_ui-1.41.0.data}/data/etc/jupyter/jupyter_notebook_config.d/solara.json +0 -0
- {solara_ui-1.39.0.data → solara_ui-1.41.0.data}/data/etc/jupyter/jupyter_server_config.d/solara.json +0 -0
- {solara_ui-1.39.0.dist-info → solara_ui-1.41.0.dist-info}/WHEEL +0 -0
- {solara_ui-1.39.0.dist-info → solara_ui-1.41.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import solara
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@solara.component
|
|
5
|
+
def Page():
|
|
6
|
+
with solara.Column(gap="40px", style={"max-width": "90%"}):
|
|
7
|
+
solara.Markdown("""
|
|
8
|
+
# Our Team
|
|
9
|
+
|
|
10
|
+
Solara is primarily developed by [Widgetti](https://widgetti.io/), a software development company specializing in the front-end side of the jupyter ecosystem. Widgetti was founded by Maarten Breddels and Mario Buikhuizen in 2023, and is based in the Netherlands.
|
|
11
|
+
|
|
12
|
+
## Core Team
|
|
13
|
+
""")
|
|
14
|
+
DevCard(
|
|
15
|
+
"Maarten Breddels",
|
|
16
|
+
"Co-Founder of Widgetti, Creator of Solara",
|
|
17
|
+
"https://github.com/maartenbreddels",
|
|
18
|
+
"Maarten is the creator of Solara, ipyvolume, and a founder of Widgetti. He is a core developer of the [Vaex](https://vaex.io/) project, and has a background in working with large datasets in astronomy.",
|
|
19
|
+
image="https://dxhl76zpt6fap.cloudfront.net/public/avatar/maarten-breddels.jpeg",
|
|
20
|
+
linkedin="https://www.linkedin.com/in/maartenbreddels/",
|
|
21
|
+
twitter="https://twitter.com/maartenbreddels",
|
|
22
|
+
email="maartenbreddels@widgetti.io",
|
|
23
|
+
)
|
|
24
|
+
DevCard(
|
|
25
|
+
"Mario Buikhuizen",
|
|
26
|
+
"Co-Founder of Widgetti",
|
|
27
|
+
"https://github.com/mariobuikhuizen",
|
|
28
|
+
"Mario is a co-founder of Widgetti and has a background in software development and data engineering. He is the creator of [ipyvuetify](https://github.com/widgetti/ipyvuetify) and [ipyvue](https://github.com/widgetti/ipyvue).",
|
|
29
|
+
image="https://dxhl76zpt6fap.cloudfront.net/public/avatar/mario-buikhuizen.jpeg",
|
|
30
|
+
linkedin="https://www.linkedin.com/in/mariobuikhuizen/",
|
|
31
|
+
twitter="https://twitter.com/mariobuikhuizen",
|
|
32
|
+
email="mariobuikhuizen@widgetti.io",
|
|
33
|
+
)
|
|
34
|
+
DevCard(
|
|
35
|
+
"Iisakki Rotko",
|
|
36
|
+
"Medior Software Engineer",
|
|
37
|
+
"https://github.com/iisakkirotko",
|
|
38
|
+
"Iisakki is a medior software engineer at Widgetti, working primarily on Solara. He has a background in physics and web development.",
|
|
39
|
+
image="https://dxhl76zpt6fap.cloudfront.net/public/avatar/iisakki-rotko.jpg",
|
|
40
|
+
linkedin="https://www.linkedin.com/in/iisakkirotko/",
|
|
41
|
+
email="iisakki.rotko@widgetti.io",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@solara.component
|
|
46
|
+
def DevCard(
|
|
47
|
+
name,
|
|
48
|
+
role,
|
|
49
|
+
github,
|
|
50
|
+
bio,
|
|
51
|
+
image=None,
|
|
52
|
+
linkedin=None,
|
|
53
|
+
twitter=None,
|
|
54
|
+
website=None,
|
|
55
|
+
email=None,
|
|
56
|
+
):
|
|
57
|
+
with solara.Row(gap="40px", style={"align-items": "stretch", "max-height": "300px", "flex": "1 1 auto"}):
|
|
58
|
+
with solara.Div(style={"flex": "0 1 300px", "border-radius": "15px", "overflow": "hidden", "aspect-ratio": "1/1"}):
|
|
59
|
+
solara.v.Html(
|
|
60
|
+
tag="img",
|
|
61
|
+
attributes={"src": image or "https://dxhl76zpt6fap.cloudfront.net/public/logo.svg", "alt": name},
|
|
62
|
+
style_="height: 100%; aspect-ratio: 1; object-fit: cover;",
|
|
63
|
+
)
|
|
64
|
+
with solara.Column():
|
|
65
|
+
solara.HTML(tag="h2", unsafe_innerHTML=name)
|
|
66
|
+
solara.HTML(tag="h3", unsafe_innerHTML=role)
|
|
67
|
+
solara.Markdown(bio)
|
|
68
|
+
with solara.Row(gap="10px"):
|
|
69
|
+
if linkedin:
|
|
70
|
+
with solara.v.Html(tag="a", attributes={"href": linkedin, "target": "_blank"}):
|
|
71
|
+
solara.v.Icon(children=["mdi-linkedin"], color="var(--color-grey-light)")
|
|
72
|
+
if twitter:
|
|
73
|
+
with solara.v.Html(tag="a", attributes={"href": twitter, "target": "_blank"}):
|
|
74
|
+
solara.v.Icon(children=["mdi-twitter"], color="var(--color-grey-light)")
|
|
75
|
+
if website:
|
|
76
|
+
with solara.v.Html(tag="a", attributes={"href": website, "target": "_blank"}):
|
|
77
|
+
solara.v.Icon(children=["mdi-web"], color="var(--color-grey-light)")
|
|
78
|
+
if email:
|
|
79
|
+
with solara.v.Html(tag="a", attributes={"href": f"mailto:{email}"}):
|
|
80
|
+
solara.v.Icon(children=["mdi-email"], color="var(--color-grey-light)")
|
|
81
|
+
if github:
|
|
82
|
+
with solara.v.Html(tag="a", attributes={"href": github, "target": "_blank"}):
|
|
83
|
+
solara.v.Icon(children=["mdi-github"], color="var(--color-grey-light)")
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import solara
|
|
2
|
+
from solara.website.components.contact import Contact
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@solara.component
|
|
6
|
+
def Page():
|
|
7
|
+
with solara.Column(gap="40px", align="stretch", style={"width": "100%"}):
|
|
8
|
+
solara.Markdown("""
|
|
9
|
+
# Pricing
|
|
10
|
+
|
|
11
|
+
The main Solara package is free for both personal and commercial use. There are additional components and functionality available in the `solara-enterprise` package, which is free for personal use, but requires a license for commercial use.
|
|
12
|
+
""")
|
|
13
|
+
solara.Markdown("""
|
|
14
|
+
## Enterprise License
|
|
15
|
+
|
|
16
|
+
As stated before, the `solara-enterprise` package is free for personal use, but requires a license for commercial use. The license includes the following benefits:
|
|
17
|
+
|
|
18
|
+
- Access to all `solara-enterprise` components and functionality
|
|
19
|
+
- Priority support from the Solara team, including bug fixes and questions
|
|
20
|
+
- Potential for custom components and functionality as agreed separately
|
|
21
|
+
- Trainings and workshops for your team
|
|
22
|
+
- Regular code reviews and/or design consultation
|
|
23
|
+
|
|
24
|
+
All enterprise licenses are custom and are priced based on the needs of the organization. Please contact us below for more information.
|
|
25
|
+
""")
|
|
26
|
+
|
|
27
|
+
Contact(
|
|
28
|
+
title="Get In Touch",
|
|
29
|
+
subtitle="Please fill out the form below and we will get back to you as soon as possible.",
|
|
30
|
+
email_subject="Enterprise License Inquiry",
|
|
31
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from solara.website.components.markdown import MarkdownWithMetadata
|
|
4
|
+
from solara.website.components.sidebar import Sidebar
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
title = "Roadmap"
|
|
8
|
+
HERE = Path(__file__)
|
|
9
|
+
Sidebar = Sidebar
|
|
10
|
+
|
|
11
|
+
Page = MarkdownWithMetadata(Path(HERE.parent / "roadmap.md").read_text())
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Roadmap for Solara
|
|
2
|
+
|
|
3
|
+
This roadmap is a living document that outlines the future direction of Solara. It is informed by community feedback, shaped by our vision for the project, and influenced by real-world problems we've solved for customers. If you're interested in getting involved or becoming a design partner, [contact us here](https://solara.dev/contact).
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Solara 2.0
|
|
7
|
+
|
|
8
|
+
Exciting news! We aim to release Solara 2.0 by the end of the year. For the 2.0 release, we want to focus on a few things:
|
|
9
|
+
|
|
10
|
+
- Improvements to reactive state management, closely following the principles of [Javascript Signals](https://github.com/tc39/proposal-signals) and its hybrid push-pull model. This will include glitch-free computed values and (side) effects triggered by signals.
|
|
11
|
+
|
|
12
|
+
- Elimination of common mistakes, such as detecting state mutations and avoiding misuse of hooks (e.g., using hooks in loops).
|
|
13
|
+
|
|
14
|
+
- [See more details in the 2.0 milestone on GitHub.](https://github.com/widgetti/solara/milestone/1)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Solara 3.0
|
|
18
|
+
|
|
19
|
+
For version 3.0 we plan to switch to using ipyvue and ipyvuetify 3.0, which will be based on vue version 3.x and ipyvuetify 3.x. For the time being ipyvue and ipyvuetify 3.0 are released as alpha versions, so users of Solara do not pick these versions up. Although Solara 1.x is compatible with ipyvue 3.0, not all components are compatible with ipyvuetify 3.0. The release date for Solara 3.0 is not yet set.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## Medium Term
|
|
23
|
+
|
|
24
|
+
### Blog
|
|
25
|
+
|
|
26
|
+
In the medium term, we plan to add a blog section to the solara.dev website, where we'll discuss design decisions and the philosophy behind Solara.
|
|
27
|
+
|
|
28
|
+
### Documentation
|
|
29
|
+
|
|
30
|
+
We plan to improve the documentation by streamlining beginner tutorials and adding coverage for internal features that are currently undocumented.
|
|
31
|
+
|
|
32
|
+
### Third-Party Solara Components
|
|
33
|
+
|
|
34
|
+
While it is already possible to make custom components for Solara, there isn't an established way to distribute them. We hope to support the development efforts of the community by providing a platform for sharing custom components easily.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## Long Term
|
|
38
|
+
|
|
39
|
+
### Different Looks
|
|
40
|
+
|
|
41
|
+
Our objective is to provide users with a robust, yet flexible front-end framework they can access directly from Python. To provide flexibility we hope to make available different front-end frameworks for users to choose from - should the user want to, `solara-ui` could be replaced completely with some other Solara compatible front-end implementation. As some users may already know, Solara is built on top of `ipyvuetify`, which provides a Python interface to the Vuetify javascript framework. However, users shouldn't be locked to that choice. We hope to one day provide similar interfaces for other front-end frameworks to fully benefit from the rich javascript ecosystem. Some efforts have already been taken towards this goal - `ipyreact` provides an easy way to integrate with React from Python, making it possible to making bindings to [Ant Design](https://ant.design) for Solara via [ipyantd](https://github.com/widgetti/ipyantd)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import solara
|
|
2
|
+
from solara.website.components.contact import Contact
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@solara.component
|
|
6
|
+
def Page():
|
|
7
|
+
with solara.Column(gap="40px", align="stretch", style={"width": "100%", "padding-bottom": "140px"}):
|
|
8
|
+
with solara.Div(style={"display": "none"}):
|
|
9
|
+
title = "Scaling up your ipywidgets apps"
|
|
10
|
+
solara.Meta(property="og:title", content=title)
|
|
11
|
+
solara.Meta(name="twitter:title", content=title)
|
|
12
|
+
solara.Title(title)
|
|
13
|
+
|
|
14
|
+
description = "Learn how to transform your ipywidget app or prototype into a production ready high quality app."
|
|
15
|
+
solara.Meta(name="description", property="og:description", content=description)
|
|
16
|
+
solara.Meta(name="twitter:description", content=description)
|
|
17
|
+
|
|
18
|
+
solara.Markdown("""
|
|
19
|
+
# Scaling up your ipywidgets app
|
|
20
|
+
|
|
21
|
+
## The problem
|
|
22
|
+
We at Widgetti, the creators of Solara, have regularly seen companies struggle trying to scale up their ipywidgets apps.
|
|
23
|
+
|
|
24
|
+
These app often start as a prototype or a small app in the Jupyter notebook, and become important internal apps. Together with Voila
|
|
25
|
+
it allows companies to quickly deploy an app internally. However, as the app grows, the complexity of the app grows as well and the app
|
|
26
|
+
becomes harder to maintain and scale, and extend and testing is often an afterthought.
|
|
27
|
+
|
|
28
|
+
## Our solution
|
|
29
|
+
If you are in this position, you are not alone. We have seen this happen many times and we have helped many companies to scale up their ipywidgets apps.
|
|
30
|
+
This can go from small improvements to the app, to a complete rewrite of the app. We often recomment an incremental approach, where we make sure the app
|
|
31
|
+
gets tested properly, and gradually introduce best practices to the app and your team as well as introducing modern state management techniques.
|
|
32
|
+
|
|
33
|
+
We continuously do code review and assist your team in making the app more maintainable and scalable. We can also help with the deployment of the app.
|
|
34
|
+
|
|
35
|
+
Over time, we phase out our involvement and make sure your team is able to maintain and extend the app themselves. We can also provide training and workshops
|
|
36
|
+
if needed.
|
|
37
|
+
|
|
38
|
+
Please contact us below for a free consultation where we can discuss your needs and how we can help you, or send us an email at [contact@solara.dev](mailto:contact@solara.dev).
|
|
39
|
+
|
|
40
|
+
""")
|
|
41
|
+
Contact(
|
|
42
|
+
title="Get In Touch",
|
|
43
|
+
subtitle="Please fill out the form below and we will get back to you as soon as possible.",
|
|
44
|
+
email_subject="Scaling up your ipywidgets app",
|
|
45
|
+
)
|
solara/widgets/vue/navigator.vue
CHANGED
|
@@ -14,43 +14,37 @@ modules.export = {
|
|
|
14
14
|
}
|
|
15
15
|
window.solara.router.push = (href) => {
|
|
16
16
|
console.log("external router push", href);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
this.location = href;
|
|
17
|
+
const url = new URL(href, window.location.origin + solara.rootPath);
|
|
18
|
+
this.location = url.pathname + url.search;
|
|
19
|
+
this.hash = url.hash;
|
|
22
20
|
};
|
|
23
21
|
let location = window.location.pathname.slice(solara.rootPath.length);
|
|
24
|
-
// take of the anchor
|
|
25
|
-
if (location.indexOf("#") !== -1) {
|
|
26
|
-
location = location.slice(0, location.indexOf("#"));
|
|
27
|
-
}
|
|
28
22
|
this.location = location + window.location.search;
|
|
23
|
+
this.hash = window.location.hash;
|
|
29
24
|
window.addEventListener("popstate", this.onPopState);
|
|
30
25
|
window.addEventListener("scroll", this.onScroll);
|
|
26
|
+
window.addEventListener("hashchange", this.onHashChange);
|
|
27
|
+
window.addEventListener("solara.pageReady", this.onPageLoad);
|
|
31
28
|
},
|
|
32
29
|
destroyed() {
|
|
33
30
|
window.removeEventListener("popstate", this.onPopState);
|
|
34
31
|
window.removeEventListener("scroll", this.onScroll);
|
|
32
|
+
window.removeEventListener("hashchange", this.onHashChange);
|
|
33
|
+
window.removeEventListener("solara.pageReady", this.onPageLoad);
|
|
35
34
|
},
|
|
36
35
|
methods: {
|
|
37
36
|
onScroll() {
|
|
38
37
|
window.history.replaceState(
|
|
39
38
|
{ top: document.documentElement.scrollTop },
|
|
40
39
|
null,
|
|
41
|
-
|
|
40
|
+
window.location.href
|
|
42
41
|
);
|
|
43
42
|
},
|
|
44
43
|
onPopState(event) {
|
|
45
|
-
console.log("pop state!", event.state, window.location.href);
|
|
46
44
|
if (!window.location.pathname.startsWith(solara.rootPath)) {
|
|
47
45
|
throw `window.location.pathname = ${window.location.pathname}, but it should start with the solara.rootPath = ${solara.rootPath}`;
|
|
48
46
|
}
|
|
49
47
|
let newLocation = window.location.pathname.slice(solara.rootPath.length);
|
|
50
|
-
// the router/server shouldn't care about the hash, that's for the frontend
|
|
51
|
-
if (newLocation.indexOf("#") !== -1) {
|
|
52
|
-
newLocation = newLocation.slice(0, newLocation.indexOf("#"));
|
|
53
|
-
}
|
|
54
48
|
this.location = newLocation + window.location.search;
|
|
55
49
|
if (event.state) {
|
|
56
50
|
const top = event.state.top;
|
|
@@ -63,6 +57,32 @@ modules.export = {
|
|
|
63
57
|
*/
|
|
64
58
|
}
|
|
65
59
|
},
|
|
60
|
+
onHashChange(event) {
|
|
61
|
+
if (!window.location.pathname.startsWith(solara.rootPath)) {
|
|
62
|
+
throw `window.location.pathname = ${window.location.pathname}, but it should start with the solara.rootPath = ${solara.rootPath}`;
|
|
63
|
+
}
|
|
64
|
+
this.hash = window.location.hash;
|
|
65
|
+
},
|
|
66
|
+
onPageLoad(event) {
|
|
67
|
+
if (!window.location.pathname.startsWith(solara.rootPath)) {
|
|
68
|
+
throw `window.location.pathname = ${window.location.pathname}, but it should start with the solara.rootPath = ${solara.rootPath}`;
|
|
69
|
+
}
|
|
70
|
+
// If we've navigated to a hash with the same name on a different page the watch on hash won't trigger
|
|
71
|
+
if (this.hash && this.hash === window.location.hash) {
|
|
72
|
+
this.navigateToHash(this.hash);
|
|
73
|
+
}
|
|
74
|
+
this.hash = window.location.hash;
|
|
75
|
+
},
|
|
76
|
+
makeFullRelativeUrl() {
|
|
77
|
+
const url = new URL(this.location, window.location.origin + solara.rootPath);
|
|
78
|
+
return url.pathname + this.hash + url.search;
|
|
79
|
+
},
|
|
80
|
+
navigateToHash(hash) {
|
|
81
|
+
const targetEl = document.getElementById(hash.slice(1));
|
|
82
|
+
if (targetEl) {
|
|
83
|
+
targetEl.scrollIntoView();
|
|
84
|
+
}
|
|
85
|
+
},
|
|
66
86
|
},
|
|
67
87
|
watch: {
|
|
68
88
|
location(value) {
|
|
@@ -89,7 +109,7 @@ modules.export = {
|
|
|
89
109
|
document.documentElement.scrollTop
|
|
90
110
|
);
|
|
91
111
|
if (oldLocation != this.location) {
|
|
92
|
-
window.history.pushState({ top: 0 }, null,
|
|
112
|
+
window.history.pushState({ top: 0 }, null, this.makeFullRelativeUrl());
|
|
93
113
|
if (pathnameNew != pathnameOld) {
|
|
94
114
|
// we scroll to the top only when we change page, not when we change
|
|
95
115
|
// the search string
|
|
@@ -99,6 +119,16 @@ modules.export = {
|
|
|
99
119
|
window.dispatchEvent(event);
|
|
100
120
|
}
|
|
101
121
|
},
|
|
122
|
+
hash(value) {
|
|
123
|
+
if (value) {
|
|
124
|
+
this.navigateToHash(value);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
data() {
|
|
129
|
+
return {
|
|
130
|
+
hash: "",
|
|
131
|
+
};
|
|
102
132
|
},
|
|
103
133
|
};
|
|
104
134
|
</script>
|
solara/widgets/vue/vegalite.vue
CHANGED
|
@@ -15,6 +15,11 @@ module.exports = {
|
|
|
15
15
|
mounted() {
|
|
16
16
|
this.do_plot_debounced();
|
|
17
17
|
},
|
|
18
|
+
destroyed() {
|
|
19
|
+
if (this.observer) {
|
|
20
|
+
this.observer.disconnect();
|
|
21
|
+
}
|
|
22
|
+
},
|
|
18
23
|
watch: {
|
|
19
24
|
spec() {
|
|
20
25
|
this.do_plot_debounced();
|
|
@@ -29,7 +34,15 @@ module.exports = {
|
|
|
29
34
|
(async () => {
|
|
30
35
|
const spec = {
|
|
31
36
|
...this.spec,
|
|
37
|
+
"renderer": "svg",
|
|
32
38
|
};
|
|
39
|
+
if (spec.width === "container") {
|
|
40
|
+
this.$refs.plotElement.classList.add("width-container")
|
|
41
|
+
this.observer = new ResizeObserver(() => {
|
|
42
|
+
view.resize();
|
|
43
|
+
});
|
|
44
|
+
this.observer.observe(this.$refs.plotElement);
|
|
45
|
+
}
|
|
33
46
|
const { view } = await vegaEmbed(this.$refs.plotElement, spec);
|
|
34
47
|
// events https://github.com/vega/vega-view#event-handling
|
|
35
48
|
if (this.listen_to_click) {
|
|
@@ -110,3 +123,8 @@ module.exports = {
|
|
|
110
123
|
},
|
|
111
124
|
}
|
|
112
125
|
</script>
|
|
126
|
+
<style id="vega-embed-container-width">
|
|
127
|
+
.width-container.vega-embed {
|
|
128
|
+
width: 100%;
|
|
129
|
+
}
|
|
130
|
+
</style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: solara-ui
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.41.0
|
|
4
4
|
Dynamic: Summary
|
|
5
5
|
Project-URL: Home, https://www.github.com/widgetti/solara
|
|
6
6
|
Project-URL: Documentation, https://solara.dev
|
|
@@ -129,7 +129,7 @@ See this snippet run live at https://solara.dev/documentation/getting_started
|
|
|
129
129
|
|
|
130
130
|
## Demo
|
|
131
131
|
|
|
132
|
-
The following demo app can be used to explore a dataset (
|
|
132
|
+
The following demo app can be used to explore a dataset (build in or upload yourself) using
|
|
133
133
|
a scatter plot. The plot can be interacted with to filter the dataset, and the filtered dataset can
|
|
134
134
|
be downloaded.
|
|
135
135
|
|