solara-ui 1.39.0__py2.py3-none-any.whl → 1.40.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.
Files changed (67) hide show
  1. solara/__init__.py +1 -1
  2. solara/components/__init__.py +1 -0
  3. solara/components/input_text_area.py +86 -0
  4. solara/components/markdown.py +1 -1
  5. solara/hooks/use_thread.py +4 -4
  6. solara/lab/components/chat.py +8 -2
  7. solara/server/assets/style.css +2 -1
  8. solara/server/flask.py +1 -1
  9. solara/server/jupyter/server_extension.py +11 -1
  10. solara/server/jupyter/solara.py +91 -0
  11. solara/server/patch.py +1 -0
  12. solara/server/pyinstaller/__init__.py +9 -0
  13. solara/server/pyinstaller/hook-ipyreact.py +5 -0
  14. solara/server/pyinstaller/hook-ipyvuetify.py +5 -0
  15. solara/server/pyinstaller/hook-solara.py +9 -0
  16. solara/server/server.py +6 -1
  17. solara/server/starlette.py +18 -6
  18. solara/server/static/highlight-dark.css +1 -1
  19. solara/server/static/main-vuetify.js +1 -1
  20. solara/server/static/solara_bootstrap.py +1 -1
  21. solara/server/templates/solara.html.j2 +30 -6
  22. solara/website/assets/custom.css +20 -57
  23. solara/website/components/__init__.py +2 -2
  24. solara/website/components/algolia_api.vue +23 -6
  25. solara/website/components/breadcrumbs.py +28 -0
  26. solara/website/components/contact.py +144 -0
  27. solara/website/components/docs.py +11 -9
  28. solara/website/components/header.py +31 -20
  29. solara/website/components/markdown.py +12 -1
  30. solara/website/components/markdown_nav.vue +34 -0
  31. solara/website/components/sidebar.py +7 -1
  32. solara/website/pages/__init__.py +87 -254
  33. solara/website/pages/about/__init__.py +9 -0
  34. solara/website/pages/about/about.md +3 -0
  35. solara/website/pages/careers/__init__.py +27 -0
  36. solara/website/pages/changelog/__init__.py +2 -2
  37. solara/website/pages/changelog/changelog.md +12 -0
  38. solara/website/pages/contact/__init__.py +30 -6
  39. solara/website/pages/documentation/__init__.py +25 -33
  40. solara/website/pages/documentation/advanced/content/10-howto/40-embed.md +2 -1
  41. solara/website/pages/documentation/advanced/content/15-reference/41-asset-files.md +1 -1
  42. solara/website/pages/documentation/advanced/content/20-understanding/50-solara-server.md +2 -1
  43. solara/website/pages/documentation/advanced/content/30-enterprise/00-overview.md +1 -1
  44. solara/website/pages/documentation/advanced/content/30-enterprise/10-oauth.md +5 -2
  45. solara/website/pages/documentation/api/hooks/use_thread.md +6 -0
  46. solara/website/pages/documentation/components/data/pivot_table.py +2 -2
  47. solara/website/pages/documentation/components/input/input.py +2 -0
  48. solara/website/pages/documentation/components/output/sql_code.py +3 -3
  49. solara/website/pages/documentation/examples/__init__.py +2 -2
  50. solara/website/pages/documentation/getting_started/content/04-tutorials/_jupyter_dashboard_1.ipynb +2 -2
  51. solara/website/pages/documentation/getting_started/content/05-fundamentals/10-components.md +19 -14
  52. solara/website/pages/documentation/getting_started/content/05-fundamentals/50-state-management.md +205 -15
  53. solara/website/pages/documentation/getting_started/content/07-deploying/10-self-hosted.md +3 -1
  54. solara/website/pages/home.vue +1199 -0
  55. solara/website/pages/our_team/__init__.py +83 -0
  56. solara/website/pages/pricing/__init__.py +31 -0
  57. solara/website/pages/roadmap/__init__.py +11 -0
  58. solara/website/pages/roadmap/roadmap.md +41 -0
  59. solara/website/pages/scale_ipywidgets.py +45 -0
  60. {solara_ui-1.39.0.dist-info → solara_ui-1.40.0.dist-info}/METADATA +2 -2
  61. {solara_ui-1.39.0.dist-info → solara_ui-1.40.0.dist-info}/RECORD +65 -49
  62. solara/website/components/hero.py +0 -15
  63. solara/website/pages/contact/contact.md +0 -17
  64. {solara_ui-1.39.0.data → solara_ui-1.40.0.data}/data/etc/jupyter/jupyter_notebook_config.d/solara.json +0 -0
  65. {solara_ui-1.39.0.data → solara_ui-1.40.0.data}/data/etc/jupyter/jupyter_server_config.d/solara.json +0 -0
  66. {solara_ui-1.39.0.dist-info → solara_ui-1.40.0.dist-info}/WHEEL +0 -0
  67. {solara_ui-1.39.0.dist-info → solara_ui-1.40.0.dist-info}/licenses/LICENSE +0 -0
@@ -34,6 +34,17 @@
34
34
  --docs-social-twitter: #000000;
35
35
  }
36
36
 
37
+ .theme--dark {
38
+ --color-border-appbar: hsla(0,0%,100%,.12);
39
+ --color-material-background: #1e1e1e;
40
+ --color-text-fade: hsla(0,0%,100%,.7);
41
+ }
42
+ .theme--light {
43
+ --color-border-appbar: rgba(0,0,0,.12);
44
+ --color-material-background: #fff;
45
+ --color-text-fade: rgba(0,0,0,.6);
46
+ }
47
+
37
48
  html,
38
49
  body,
39
50
  p,
@@ -199,9 +210,8 @@ blockquote p:last-child {
199
210
  }
200
211
  .v-sheet.docs-card-container{
201
212
  width: 100%;
202
- padding: 0 10%;
203
213
  justify-content: start;
204
- align-content: center;
214
+ align-content: stretch;
205
215
  flex-wrap: wrap !important;
206
216
  flex-grow: 1;
207
217
  row-gap: 20px;
@@ -211,11 +221,14 @@ blockquote p:last-child {
211
221
  }
212
222
  .v-sheet.docs-card-container > a > .docs-card{
213
223
  display: flex;
214
- width: 20rem;
215
- height: 12rem;
224
+ flex-grow: 1;
225
+ height: 4rem;
216
226
  border-radius: 16px !important;
217
227
  color: var(--color-grey-light);
218
228
  }
229
+ .v-sheet.docs-card-container > a > .docs-card > h2 {
230
+ padding: 0 24px;
231
+ }
219
232
  .v-sheet.docs-card-container > a .docs-card-icon{
220
233
  padding-right: 1.5rem;
221
234
  transition: ease padding 0.25s;
@@ -274,6 +287,8 @@ blockquote p:last-child {
274
287
  /* header */
275
288
  .header-logo {
276
289
  display: block;
290
+ height: 100%;
291
+ margin: 0;
277
292
  }
278
293
  .news {
279
294
  background-color: var(--color-primary);
@@ -289,46 +304,6 @@ blockquote p:last-child {
289
304
  color: white !important;
290
305
  }
291
306
 
292
- /* hero */
293
- .hero {
294
- background: var(--color-primary-lightest) url(https://dxhl76zpt6fap.cloudfront.net/public/hero.webp);
295
- background-size: cover;
296
- min-height: 660px;
297
- padding: 7rem 0;
298
- }
299
-
300
- .theme--dark .hero {
301
- background: var(--dark-color-primary-lightest) url(https://dxhl76zpt6fap.cloudfront.net/public/hero.webp);
302
- background-size: cover;
303
- }
304
-
305
- .hero h1 {
306
- font-size: 4.5rem;
307
- }
308
-
309
- .hero h2 {
310
- padding-left: 150px;
311
- padding-right: 150px;
312
- }
313
-
314
- .hero b {
315
- color: var(--color-primary);
316
- }
317
-
318
- .theme--dark .hero b {
319
- color: var(--dark-color-primary);
320
- }
321
-
322
- @media screen and (max-width: 960px) {
323
- .hero {
324
- padding: 4rem 0;
325
- min-height: auto;
326
- }
327
-
328
- .hero h1 {
329
- font-size: 3rem;
330
- }
331
- }
332
307
 
333
308
  /* fixes padding issue on drawer menu */
334
309
  .v-list-group__items {
@@ -362,7 +337,7 @@ blockquote p:last-child {
362
337
 
363
338
  .menu li a:link {
364
339
  display: block;
365
- padding: 1rem 2rem;
340
+ padding: 0.75rem;
366
341
  }
367
342
 
368
343
  .menu .active {
@@ -427,11 +402,6 @@ blockquote p:last-child {
427
402
  font-weight: bolder;
428
403
  }
429
404
 
430
- .solara-autorouter-content {
431
- padding-top: 2rem;
432
- max-width: 100%;
433
- }
434
-
435
405
  .jp-RenderedHTMLCommon {
436
406
  padding-right: 0;
437
407
  }
@@ -457,13 +427,6 @@ blockquote p:last-child {
457
427
  /* MOBILE */
458
428
 
459
429
  @media screen and (aspect-ratio < 1) {
460
- .hero{
461
- background-position-x: 29%;
462
- }
463
- .hero h2{
464
- padding-left: 0;
465
- padding-right: 0;
466
- }
467
430
  .container.fill-height > .ma-8.row{
468
431
  max-width: 80%;
469
432
  }
@@ -1,5 +1,5 @@
1
1
  from .docs import CategoryLayout, Gallery, NoPage, SubCategoryLayout, WithCode # noqa
2
2
  from .header import Header
3
- from .hero import Hero
3
+ from .markdown import MarkdownWithMetadata
4
4
 
5
- __all__ = ["Header", "Hero"]
5
+ __all__ = ["Header", "MarkdownWithMetadata", "CategoryLayout", "Gallery", "NoPage", "SubCategoryLayout", "WithCode"]
@@ -7,14 +7,19 @@
7
7
  v-model="query"
8
8
  prepend-inner-icon="mdi-magnify"
9
9
  hide-details
10
+ dense
10
11
  :placeholder="mac ? '⌘K to search' : 'Ctrl+K to search'"
12
+ filled
11
13
  outlined
12
- rounded
13
14
  clearable
14
15
  ref="search"
15
16
  style="flex-grow: 1; max-width: 650px;"
16
17
  @click="show($event, on);"
17
- @keyup.enter="item = 0"
18
+ @keyup.enter="hoverItem === null ? item = 0 : item = hoverItem"
19
+ @keyup.esc="close();"
20
+ @keyup.down="hoverItem = hoverItem == null ? 0 : Math.min(hoverItem + 1, results.hits.length - 1, 9)"
21
+ @keyup.up="hoverItem = hoverItem == null ? 9 : Math.max(hoverItem - 1, 0)"
22
+ @focus="selectText();"
18
23
  class="algolia"
19
24
  ></v-text-field>
20
25
  </template>
@@ -27,7 +32,7 @@
27
32
  </v-list>
28
33
  <v-list v-else :style="{width: menuWidth + 'px'}">
29
34
  <v-list-item-group v-model="item">
30
- <v-list-item v-for="(element, index) in this.results.hits" :key="element['url']">
35
+ <v-list-item v-for="(element, index) in this.results.hits" :key="element['url']" :input-value="index === hoverItem">
31
36
  <v-list-item-content>
32
37
  <v-list-item-title>
33
38
  {{ element.hierarchy.lvl1 }}
@@ -39,7 +44,7 @@
39
44
  </v-list-item-content>
40
45
  </v-list-item>
41
46
  </v-list-item-group>
42
- <v-list-item>
47
+ <v-list-item v-if="this.results.nbHits > 10">
43
48
  <v-list-item-content>
44
49
  <v-list-item-title>And {{ this.results.nbHits - 10}} More...</v-list-item-title>
45
50
  </v-list-item-content>
@@ -58,7 +63,6 @@ module.exports = {
58
63
  window.search = this;
59
64
  this.updateMenuWidth();
60
65
  window.addEventListener('resize', this.updateMenuWidth);
61
-
62
66
  },
63
67
  watch: {
64
68
  query ( value ) {
@@ -66,12 +70,17 @@ module.exports = {
66
70
  this.search();
67
71
  },
68
72
  item ( value ) {
69
- if ( this.results.hits != null && this.results.hits.length > 0 ) {
73
+ if ( value === null ) return;
74
+ if ( this.results.hits != null && this.results.hits.length >= value ) {
70
75
  let url = this.results.hits[value].url;
71
76
  if (url.startsWith("https://solara.dev")) {
72
77
  url = url.slice(18);
73
78
  }
74
79
  solara.router.push( url );
80
+ this.close();
81
+ // reset the search
82
+ this.item = null;
83
+ this.hoverItem = null;
75
84
  }
76
85
  },
77
86
  },
@@ -82,6 +91,10 @@ module.exports = {
82
91
  on.click( e )
83
92
  } );
84
93
  },
94
+ close() {
95
+ this.show_results = false;
96
+ this.$refs.search.blur();
97
+ },
85
98
  initSearch() {
86
99
  this.client = this.algoliasearch( '9KW9L7O5EQ', '647ca12ba642437cc40c2adee4a78d08' );
87
100
  this.index = this.client.initIndex( 'solara' );
@@ -107,6 +120,9 @@ module.exports = {
107
120
  this.$set(this.results, []);
108
121
  }
109
122
  },
123
+ selectText() {
124
+ this.$refs.search.$refs.input.select();
125
+ },
110
126
  getSnippet( element ) {
111
127
  if (element.type == "content") {
112
128
  return element._highlightResult.content.value;
@@ -176,6 +192,7 @@ module.exports = {
176
192
  query: '',
177
193
  results: [],
178
194
  item: null,
195
+ hoverItem: null,
179
196
  show_results: false,
180
197
  mac: false,
181
198
  menuWidth: 0,
@@ -0,0 +1,28 @@
1
+ from typing import List
2
+ import solara
3
+
4
+
5
+ @solara.component
6
+ def BreadCrumbs():
7
+ router = solara.use_router()
8
+ routes = router.path_routes
9
+
10
+ with solara.Row(style={"align-items": "center", "flex-wrap": "wrap"}) as main:
11
+ for i, route in enumerate(routes):
12
+ if i == len(routes) - 1:
13
+ solara.Text(route.label or route.path, style={"color": "var(--color-text-fade)"})
14
+ else:
15
+ with solara.Link(solara.resolve_path(route), style={"color": "var(--color-text-fade)"}):
16
+ solara.Text(route.label or route.path)
17
+ if i != len(routes) - 1:
18
+ solara.Text("/", style={"font-size": "1.5rem", "color": "var(--color-text-fade)"})
19
+ return main
20
+
21
+
22
+ def _resolve_path_to_route(path_to_find: List[str], all_routes: List[solara.Route], routes: List[solara.Route] = []):
23
+ if len(path_to_find) == 0:
24
+ return routes
25
+ for route in all_routes:
26
+ if path_to_find[0] == route.path:
27
+ routes += [route]
28
+ return _resolve_path_to_route(path_to_find[1:], route.children, routes)
@@ -0,0 +1,144 @@
1
+ import json
2
+ import os
3
+ import requests
4
+
5
+ from typing import Any, Dict, Optional
6
+ import solara
7
+
8
+
9
+ postmark_api_key = None
10
+ contact_email_address = None
11
+
12
+ try:
13
+ postmark_api_key = os.environ["POSTMARK_API_KEY"]
14
+ contact_email_address = os.environ["SOLARA_CONTACT_EMAIL_ADDRESS"]
15
+ except Exception:
16
+ pass
17
+
18
+
19
+ @solara.component
20
+ def Contact(
21
+ style: Dict[str, Any] = {},
22
+ title="Contact Us",
23
+ subtitle="We'd love to hear from you!",
24
+ submit_label="Submit",
25
+ email_subject="Contact Form Submission",
26
+ ):
27
+ first_name = solara.use_reactive("")
28
+ last_name = solara.use_reactive("")
29
+ email = solara.use_reactive("")
30
+ company = solara.use_reactive("")
31
+ message = solara.use_reactive("")
32
+ error: solara.Reactive[Optional[str]] = solara.use_reactive(None)
33
+ success = solara.use_reactive(False)
34
+
35
+ def send(*_ignore):
36
+ if postmark_api_key is None or contact_email_address is None:
37
+ error.set("Email service not properly configured. Please contact the site administrator at solara@widgetti.io.")
38
+ elif not first_name.value or not last_name.value or not email.value or not message.value:
39
+ error.set("Please fill out all required fields.")
40
+ else:
41
+ # Create the email content
42
+ msg = {}
43
+ msg["From"] = contact_email_address
44
+ msg["To"] = contact_email_address
45
+ msg["Subject"] = email_subject
46
+ msg["ReplyTo"] = email.value
47
+
48
+ # Email body
49
+ msg["HtmlBody"] = f"""
50
+ <b>First Name</b>: {first_name.value}<br />
51
+ <b>Last Name</b>: {last_name.value}<br />
52
+ <b>Email</b>: {email.value}<br />
53
+ <b>Company</b>: {company.value}<br />
54
+ <b>Message</b>: {message.value}<br />
55
+ """
56
+
57
+ # Send emails
58
+ try:
59
+ requests.post(
60
+ "https://api.postmarkapp.com/email",
61
+ headers={
62
+ "Accept": "application/json",
63
+ "Content-Type": "application/json",
64
+ "X-Postmark-Server-Token": postmark_api_key,
65
+ },
66
+ data=json.dumps(msg),
67
+ )
68
+ requests.post(
69
+ "https://api.postmarkapp.com/email",
70
+ headers={
71
+ "Accept": "application/json",
72
+ "Content-Type": "application/json",
73
+ "X-Postmark-Server-Token": postmark_api_key,
74
+ },
75
+ data=json.dumps(
76
+ {
77
+ "From": contact_email_address,
78
+ "To": email.value,
79
+ "Subject": "Thank you for contacting Solara",
80
+ "HtmlBody": f"""
81
+ <p>Hi {first_name.value},</p>
82
+ <p>Thank you for contacting us! We will get back to you as soon as possible.</p>
83
+ <p>Best regards,<br />The Solara Team</p>
84
+ """,
85
+ }
86
+ ),
87
+ )
88
+ except Exception as e:
89
+ error.set(f"Error sending email: {e}")
90
+ else:
91
+ success.set(True)
92
+ error.set(None)
93
+ first_name.set("")
94
+ last_name.set("")
95
+ email.set("")
96
+ company.set("")
97
+ message.set("")
98
+
99
+ with solara.Card(title=title, style={"width": "100%", "max-width": "1024px", **style}):
100
+ solara.Markdown(subtitle)
101
+ solara.Text("* Required fields")
102
+ with solara.Row():
103
+ solara.InputText(label="First Name *", value=first_name)
104
+ solara.InputText(label="Last Name *", value=last_name)
105
+ with solara.Row():
106
+ solara.InputText(label="Email *", value=email)
107
+ solara.InputText(label="Company", value=company)
108
+ solara.v.Textarea(placeholder="Message *", v_model=message.value, on_v_model=message.set)
109
+ with solara.CardActions():
110
+ solara.Button(label=submit_label, color="primary", on_click=send)
111
+ solara.Button(
112
+ label="Clear",
113
+ color="secondary",
114
+ text=True,
115
+ on_click=lambda: [first_name.set(""), last_name.set(""), email.set(""), company.set(""), message.set("")],
116
+ )
117
+
118
+ solara.Style(
119
+ """
120
+ .v-snack__wrapper {
121
+ box-shadow: none;
122
+ }
123
+ """
124
+ )
125
+
126
+ with solara.v.Snackbar(
127
+ v_model=error.value is not None,
128
+ timeout=5000,
129
+ on_v_model=lambda *_: error.set(None),
130
+ left=True,
131
+ color="error",
132
+ ):
133
+ solara.Markdown(error.value or "", style={"--dark-color-text": "white", "--color-text": "white"})
134
+ solara.Button(icon=True, icon_name="mdi-close", color="white", on_click=lambda: error.set(None))
135
+
136
+ with solara.v.Snackbar(
137
+ v_model=success.value,
138
+ timeout=5000,
139
+ on_v_model=lambda *_: success.set(False),
140
+ left=True,
141
+ color="success",
142
+ ):
143
+ solara.Markdown("Your message has been sent!", style={"--dark-color-text": "white", "--color-text": "white"})
144
+ solara.Button(icon=True, icon_name="mdi-close", color="white", on_click=lambda: success.set(False))
@@ -1,5 +1,6 @@
1
1
  import solara
2
- from solara.alias import rv
2
+ from .markdown import MarkdownWithMetadata
3
+ from .breadcrumbs import BreadCrumbs
3
4
 
4
5
 
5
6
  @solara.component
@@ -66,18 +67,19 @@ def NoPage():
66
67
 
67
68
 
68
69
  @solara.component
69
- def WithCode(module):
70
- component = getattr(module, "Page", None)
71
- with rv.Sheet() as main:
70
+ def WithCode(route_current):
71
+ component = getattr(route_current.module, "Page", None)
72
+ with solara.Column(style={"flex-grow": 1, "padding-top": "56px"}) as main:
73
+ BreadCrumbs()
72
74
  # It renders code better
73
- solara.Markdown(
74
- module.__doc__ or "# no docs yet",
75
+ MarkdownWithMetadata(
76
+ route_current.module.__doc__ or "# no docs yet",
75
77
  unsafe_solara_execute=True,
76
78
  )
77
79
  if component and component != NoPage:
78
80
  with solara.Card("Example", margin=0, classes=["mt-8"]):
79
81
  component()
80
- github_url = solara.util.github_url(module.__file__)
82
+ github_url = solara.util.github_url(route_current.module.__file__)
81
83
  solara.Button(
82
84
  label="View source",
83
85
  icon_name="mdi-github-circle",
@@ -97,7 +99,7 @@ def SubCategoryLayout(children=[]):
97
99
  elif route_current.path == "/":
98
100
  return solara.Error("Not supposed to be rendered")
99
101
  elif route_current.module:
100
- WithCode(route_current.module)
102
+ WithCode(route_current)
101
103
  else:
102
104
  with solara.Column(align="center", children=children, style={"flex-grow": 1, "padding": "0"}) as main:
103
105
  pass
@@ -113,6 +115,6 @@ def CategoryLayout(children=[]):
113
115
  if route_current.path == "/":
114
116
  return Gallery()
115
117
  else:
116
- with solara.Column(align="stretch", style={"width": "1024px", "flex-grow": 1}, children=children) as main:
118
+ with solara.Column(align="stretch", children=children, style={"max-width": "100%"}) as main:
117
119
  pass
118
120
  return main
@@ -20,34 +20,44 @@ def Header(
20
20
 
21
21
  # set states for menu
22
22
  with solara.Column(gap="0px"):
23
- with solara.Div(classes=["news"]):
24
- solara.HTML(
25
- "div",
26
- unsafe_innerHTML="<a href='https://github.com/widgetti/solara' target='_blank' >Star us on github 🤩</a>",
27
- )
28
- with solara.v.AppBar(tag="header", flat=True, class_="bg-primary-fade padding-40", height="auto", clipped_left=True):
29
- with rv.ToolbarTitle(class_="d-flex", style_="align-items:center"):
30
- if route_current is not None and route_current.module is not None and hasattr(route_current.module, "Sidebar"):
31
- with solara.Button(icon=True, class_="hidden-md-and-up", on_click=lambda: on_toggle_left_menu and on_toggle_left_menu()):
32
- rv.Icon(children=["mdi-menu"])
23
+ # with solara.Div(classes=["news"]):
24
+ # solara.HTML(
25
+ # "div",
26
+ # unsafe_innerHTML="<a href='https://github.com/widgetti/solara' target='_blank' >Star us on github 🤩</a>",
27
+ # )
28
+ with solara.v.AppBar(
29
+ tag="header", flat=True, clipped_left=True, style_="background-color: transparent; border-bottom: 1px solid var(--color-border-appbar);"
30
+ ):
31
+ if route_current is not None and route_current.module is not None and hasattr(route_current.module, "Sidebar"):
32
+ with solara.Button(icon=True, class_="hidden-md-and-up", on_click=lambda: on_toggle_left_menu and on_toggle_left_menu()):
33
+ rv.Icon(children=["mdi-menu"])
33
34
 
34
- with solara.Row(
35
- justify="start", classes=["header-logo-container"], style={"flex-grow": "1", "background-color": "transparent", "align-items": "center"}
35
+ display = " d-none d-sm-flex" if route_current is not None and route_current.path not in ["about", "pricing", "careers"] else " d-flex"
36
+ with solara.v.Html(
37
+ tag="div",
38
+ class_="header-logo-container" + display,
39
+ style_="""
40
+ background-color: transparent;
41
+ flex-grow: 1;
42
+ align-items: stretch;
43
+ max-height: 65%;
44
+ """,
36
45
  ):
37
- with solara.Link(path_or_route="/"):
46
+ with solara.Link(path_or_route="/", style={"display": "flex", "align-items": "center", "flex-direction": "row", "gap": "10px"}):
38
47
  solara.Image(router.root_path + f"/static/assets/images/logo{'_white' if dark_effective else ''}.svg", classes=["header-logo"])
48
+ solara.Text("API", style={"font-size": "20px", "font-weight": "600"})
39
49
 
40
- with rv.Html(tag="ul", class_="main-menu menu d-none d-md-flex", style_="flex-grow: 1;"):
50
+ if route_current is not None and route_current.path not in ["about", "pricing", "careers"]:
41
51
  if settings.search.enabled:
42
52
  from solara_enterprise.search.search import Search
43
53
 
44
54
  Search()
45
55
  else:
46
- with solara.Row(justify="end", style={"align-items": "center", "flex-grow": "1", "background-color": "transparent"}):
47
- Algolia()
56
+ Algolia()
48
57
 
58
+ with rv.Html(tag="ul", class_="main-menu menu d-none d-md-flex", style_="justify-content: flex-end;"):
49
59
  for route in all_routes:
50
- if route.path in ["apps", "contact", "changelog"]:
60
+ if route.path in ["apps", "contact", "changelog", "our_team", "about", "pricing", "roadmap", "careers"]:
51
61
  continue
52
62
  current = route_current == route
53
63
  with rv.Html(tag="li", class_="active" if current else None):
@@ -58,7 +68,8 @@ def Header(
58
68
  with rv.Btn(icon=True, tag="a", class_="d-none d-md-flex", attributes={"href": "https://discord.solara.dev", "target": "_blank"}):
59
69
  rv.Icon(children=["mdi-discord"])
60
70
 
61
- solara.lab.ThemeToggle()
71
+ with solara.v.Html(tag="div", class_="d-none d-md-flex"):
72
+ solara.lab.ThemeToggle()
62
73
 
63
- with solara.Button(icon=True, class_="hidden-md-and-up", on_click=lambda: on_toggle_right_menu and on_toggle_right_menu()):
64
- rv.Icon(children=["mdi-menu"])
74
+ # with solara.Button(icon=True, class_="hidden-md-and-up", on_click=lambda: on_toggle_right_menu and on_toggle_right_menu()):
75
+ # rv.Icon(children=["mdi-menu"])
@@ -27,4 +27,15 @@ def MarkdownWithMetadata(content: str, unsafe_solara_execute=True):
27
27
  solara.Meta(property=key, content=value)
28
28
  else:
29
29
  solara.Meta(name=key, content=value)
30
- solara.Markdown(content, unsafe_solara_execute=unsafe_solara_execute)
30
+ with solara.v.Html(
31
+ tag="div",
32
+ style_="display: flex; flex-direction: row; justify-content: center; gap: 15px; max-width: 90%; margin: 0 auto;",
33
+ attributes={"id": "markdown-to-navigate"},
34
+ ):
35
+ solara.Markdown(content, unsafe_solara_execute=unsafe_solara_execute, style="flex-grow: 1; max-width: min(100%, 1024px);")
36
+ MarkdownNavigation(id="markdown-to-navigate").key("markdown-nav" + str(hash(content)))
37
+
38
+
39
+ @solara.component_vue("markdown_nav.vue")
40
+ def MarkdownNavigation(id: str):
41
+ pass
@@ -0,0 +1,34 @@
1
+ <template>
2
+ <v-list dense :style="`margin: 40px 24px 0 24px; position: sticky; top: 88px; align-self: flex-start;`" class="d-none d-lg-inline-block">
3
+ <v-list-item
4
+ v-for="(element, index) in this.sections"
5
+ :key="index"
6
+ :href="'#' + element.id"
7
+ :style="'padding-left: ' + (16 + (element.nodeName[1] - 1) * 20) + 'px;'"
8
+ >
9
+ <v-list-item-content>
10
+ <v-list-item-title>
11
+ {{ element.innerText }}
12
+ </v-list-item-title>
13
+ </v-list-item-content>
14
+ </v-list-item>
15
+ </v-list>
16
+ </template>
17
+ <script>
18
+ module.exports = {
19
+ mounted() {
20
+ this.getSections();
21
+ },
22
+ methods: {
23
+ getSections() {
24
+ const parentToSearch = document.getElementById(this.id);
25
+ this.sections = parentToSearch.querySelectorAll('h1, h2, h3, h4');
26
+ },
27
+ },
28
+ data() {
29
+ return {
30
+ sections: []
31
+ }
32
+ }
33
+ }
34
+ </script>
@@ -14,7 +14,9 @@ def Sidebar():
14
14
  all_routes = route.children
15
15
  break
16
16
 
17
- with solara.v.List(expand=True, nav=True, style_="height: 100%; display: flex; flex-direction: column;") as main:
17
+ with solara.v.List(
18
+ expand=True, nav=True, style_="height: 100%; display: flex; flex-direction: column; background-color: var(--color-material-background);"
19
+ ) as main:
18
20
  with solara.v.ListItemGroup(v_model=router.path):
19
21
  # e.g. getting_started, examples, components, api, advanced, faq
20
22
  for route in all_routes:
@@ -93,5 +95,9 @@ def Sidebar():
93
95
  with solara.v.ListItem(value="/changelog"):
94
96
  solara.v.ListItemIcon(children=[solara.v.Icon(children=["mdi-history"])])
95
97
  solara.v.ListItemTitle(style_="padding: 0 20px;", children=["Changelog"])
98
+ with solara.Link("/roadmap"):
99
+ with solara.v.ListItem(value="/roadmap"):
100
+ solara.v.ListItemIcon(children=[solara.v.Icon(children=["mdi-road"])])
101
+ solara.v.ListItemTitle(style_="padding: 0 20px;", children=["Roadmap"])
96
102
 
97
103
  return main