UCS2014 commited on
Commit
0691ec3
·
verified ·
1 Parent(s): a0856fd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -60
app.py CHANGED
@@ -1,13 +1,14 @@
1
  # -*- coding: utf-8 -*-
2
  from typing import Optional, Dict, Any
3
- import base64, mimetypes
 
4
  from html import escape
5
  from pathlib import Path
6
  import streamlit as st
7
 
8
  # ========= PATHS =========
9
  BASE_DIR = Path(__file__).parent
10
- ASSETS = BASE_DIR / "assets"
11
 
12
  # ========= META =========
13
  st.set_page_config(page_title="ST_GeoMech SUITE", layout="wide")
@@ -52,14 +53,14 @@ THEME: Dict[str, Any] = {
52
  "pad_h": 20,
53
  "border": "#0B1220",
54
  "border_hover": "#243447",
55
- "bg_top": "#FFFFFF",
56
- "bg_bot": "#FBFCFE",
57
  "title_color": "#0B1220",
58
  "blurb_color": "#566275",
59
  },
60
  "icon": {
61
  "diam": 118,
62
- "img": 106,
63
  "circle_bg": "#F1F5F9",
64
  "circle_border": "rgba(12,18,32,0.10)",
65
  },
@@ -79,51 +80,51 @@ CARDS = [
79
  {
80
  "title": " ST_GeoMEch_UCS",
81
  "blurb": "Real-time Uniconfined Compressive Strength Prediction.",
82
- "url": "https://smart-thinking-ucs.hf.space/",
83
- "icon": ASSETS / "UCS_logo.png",
84
- "style": {"bg_top":"#EAF7F1","bg_bot":"#F6FBF8","border":"#0F3D3E"},
85
  },
86
  {
87
  "title": " ST_GeoMEch_UCS",
88
  "blurb": "Real-time Uniconfined Compressive Strength Prediction.",
89
- "url": "https://smart-thinking-ucs.hf.space/",
90
- "icon": ASSETS / "UCS_logo.png",
91
- "style": {"bg_top":"#EAF7F1","bg_bot":"#F6FBF8","border":"#0F3D3E"},
92
  },
93
  {
94
  "title": " ST_GeoMEch_UCS",
95
  "blurb": "Real-time Uniconfined Compressive Strength Prediction.",
96
- "url": "https://smart-thinking-ucs.hf.space/",
97
- "icon": ASSETS / "UCS_logo.png",
98
- "style": {"bg_top":"#EAF7F1","bg_bot":"#F6FBF8","border":"#0F3D3E"},
99
  },
100
  {
101
  "title": " ST_GeoMEch_UCS",
102
  "blurb": "Real-time Uniconfined Compressive Strength Prediction.",
103
- "url": "https://smart-thinking-ucs.hf.space/",
104
- "icon": ASSETS / "UCS_logo.png",
105
- "style": {"bg_top":"#EAF7F1","bg_bot":"#F6FBF8","border":"#0F3D3E"},
106
  },
107
  {
108
  "title": " ST_GeoMEch_UCS",
109
  "blurb": "Real-time Uniconfined Compressive Strength Prediction.",
110
- "url": "https://smart-thinking-ucs.hf.space/",
111
- "icon": ASSETS / "UCS_logo.png",
112
- "style": {"bg_top":"#EAF7F1","bg_bot":"#F6FBF8","border":"#0F3D3E"},
113
  },
114
  {
115
  "title": " ST_GeoMech_Ym",
116
  "blurb": "Real-time Static Young's Modulus Prediction.",
117
- "url": "https://smart-thinking-ym.hf.space",
118
- "icon": ASSETS / "Ym_logo.png",
119
- "style": {"bg_top":"#EAF7FD","bg_bot":"#F5FBFF","border":"#0E4A6E"},
120
  },
121
  {
122
  "title": " ST_GeoMech_SMW",
123
  "blurb": "Real-Time Safe Mud Window Prediction",
124
- "url": "https://smart-thinking-smw.hf.space",
125
- "icon": ASSETS / "SMW_logo.png",
126
- "style": {"bg_top":"#EEF0FF","bg_bot":"#F7F8FF","border":"#3E4EB8"},
127
  },
128
  ]
129
 
@@ -137,6 +138,7 @@ def data_uri(path: Path) -> Optional[str]:
137
  b64 = base64.b64encode(path.read_bytes()).decode("utf-8")
138
  return f"data:{mime};base64,{b64}"
139
 
 
140
  def img_tag(path: Path, alt: str, cls: str = "", style: str = "") -> str:
141
  uri = data_uri(path)
142
  if not uri:
@@ -145,9 +147,15 @@ def img_tag(path: Path, alt: str, cls: str = "", style: str = "") -> str:
145
  style_attr = f' style="{style}"' if style else ""
146
  return f'<img{cls_attr}{style_attr} src="{uri}" alt="{escape(alt)}" />'
147
 
 
148
  # ========= CSS (driven from THEME) =========
149
- strip = THEME["strip"]; page = THEME["page"]; hero = THEME["hero"]
150
- grid = THEME["grid"]; card = THEME["card"]; icon = THEME["icon"]; button = THEME["button"]
 
 
 
 
 
151
 
152
  bg_radial_css = """
153
  background:
@@ -158,7 +166,8 @@ background:
158
  rgba(255,255,255,1) 100%);
159
  """ if page["bg_radial"] else "background: #fff;"
160
 
161
- st.markdown(f"""
 
162
  <style>
163
  :root {{
164
  --top-pad: {page["top_padding"]}px;
@@ -263,8 +272,8 @@ st.markdown(f"""
263
  /* ===== CARD ===== */
264
  .card {{
265
  position: relative;
266
- width: 100%; /* full width of its grid cell */
267
- max-width: var(--card-w); /* optional max width for nice measure */
268
  border-radius: var(--c-radius, var(--card-r));
269
  padding: var(--c-pv, var(--card-pv)) var(--c-ph, var(--card-ph));
270
  background: linear-gradient(180deg, var(--c-bg-top, {card["bg_top"]}) 0%, var(--c-bg-bot, {card["bg_bot"]}) 100%);
@@ -275,7 +284,7 @@ st.markdown(f"""
275
  0 -1px 6px rgba(255,255,255,0.18) inset;
276
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease, filter .18s ease;
277
  text-align:center; display:flex; flex-direction:column; gap:16px; align-items: center;
278
- margin: 0 auto; /* center within grid cell if narrower than cell */
279
  }}
280
  .card:hover {{
281
  transform: translateY(-6px) scale(1.01);
@@ -333,14 +342,16 @@ st.markdown(f"""
333
  .footer {{ text-align:center; color:#3f4a5a; font-size:0.96em; margin-top: 26px; }}
334
  .footer hr {{ margin: 12px 0; border-color: rgba(0,0,0,.08); }}
335
  </style>
336
- """, unsafe_allow_html=True)
 
 
337
 
338
  # ========= Strip (top-left) =========
339
  st.markdown(
340
- f"""
341
  <div class="suite-row">
342
- <span class="suite-pill">{"ST_GeoMech SUITE"}</span>
343
- <span class="suite-tagline">{"Predicting Rock Mechanical Behavious While Drilling"}</span>
344
  </div>
345
  """,
346
  unsafe_allow_html=True,
@@ -350,37 +361,63 @@ st.markdown(
350
  hero_html = img_tag(THEME["hero"]["logo"], "ST_GeoMech SUITE")
351
  st.markdown(f"<div class='hero'>{hero_html}</div>", unsafe_allow_html=True)
352
 
 
353
  def build_card_vars(style: Dict[str, Any]) -> str:
354
  s = []
355
- if "width" in style: s.append(f"--c-w:{int(style['width'])}px")
356
- if "radius" in style: s.append(f"--c-radius:{int(style['radius'])}px")
357
- if "pad_v" in style: s.append(f"--c-pv:{int(style['pad_v'])}px")
358
- if "pad_h" in style: s.append(f"--c-ph:{int(style['pad_h'])}px")
359
- if "bg_top" in style: s.append(f"--c-bg-top:{style['bg_top']}")
360
- if "bg_bot" in style: s.append(f"--c-bg-bot:{style['bg_bot']}")
361
- if "border" in style: s.append(f"--c-border:{style['border']}")
362
- if "border_width" in style: s.append(f"--c-bw:{int(style['border_width'])}px")
363
- if "title_color" in style: s.append(f"--c-title-color:{style['title_color']}")
364
- if "title_fs" in style: s.append(f"--c-title-fs:{int(style['title_fs'])}px")
365
- if "blurb_color" in style: s.append(f"--c-blurb-color:{style['blurb_color']}")
366
- if "blurb_fs" in style: s.append(f"--c-blurb-fs:{int(style['blurb_fs'])}px")
367
- if "btn_bg1" in style: s.append(f"--c-btn-bg1:{style['btn_bg1']}")
368
- if "btn_bg2" in style: s.append(f"--c-btn-bg2:{style['btn_bg2']}")
369
- if "btn_text" in style: s.append(f"--c-btn-text:{style['btn_text"]}")
370
- if "btn_border" in style: s.append(f"--c-btn-border:{style['btn_border"]}")
371
- if "btn_fs" in style: s.append(f"--c-btn-fs:{int(style['btn_fs'])}px")
372
- if "btn_pad_v" in style: s.append(f"--c-btn-pv:{int(style['btn_pad_v'])}px")
373
- if "btn_pad_h" in style: s.append(f"--c-btn-ph:{int(style['btn_pad_h'])}px")
374
- if "icon_diam" in style: s.append(f"--c-icon-d:{int(style['icon_diam'])}px")
375
- if "icon_img" in style: s.append(f"--c-icon-img:{int(style['icon_img"]) }px")
376
- if "icon_bg" in style: s.append(f"--c-icon-bg:{style['icon_bg"]}")
377
- if "icon_border" in style: s.append(f"--c-icon-border:{style['icon_border"]}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
  return "; ".join(s)
379
 
 
380
  def app_card(card_cfg: Dict[str, Any]) -> str:
381
  style = card_cfg.get("style", {})
382
  vars_inline = build_card_vars(style)
383
- icon_html = img_tag(card_cfg.get("icon"), "icon") if card_cfg.get("icon") and card_cfg["icon"].exists() else ""
 
384
  target = "_self"
385
  return (
386
  f"<div class='card' style='{vars_inline}'>"
@@ -391,6 +428,7 @@ def app_card(card_cfg: Dict[str, Any]) -> str:
391
  + "</div>"
392
  )
393
 
 
394
  st.markdown("<div class='grid'>" + "".join(app_card(c) for c in CARDS) + "</div>", unsafe_allow_html=True)
395
 
396
  # ========= Footer =========
 
1
  # -*- coding: utf-8 -*-
2
  from typing import Optional, Dict, Any
3
+ import base64
4
+ import mimetypes
5
  from html import escape
6
  from pathlib import Path
7
  import streamlit as st
8
 
9
  # ========= PATHS =========
10
  BASE_DIR = Path(__file__).parent
11
+ ASSETS = BASE_DIR / "assets"
12
 
13
  # ========= META =========
14
  st.set_page_config(page_title="ST_GeoMech SUITE", layout="wide")
 
53
  "pad_h": 20,
54
  "border": "#0B1220",
55
  "border_hover": "#243447",
56
+ "bg_top": "#FFFFFF",
57
+ "bg_bot": "#FBFCFE",
58
  "title_color": "#0B1220",
59
  "blurb_color": "#566275",
60
  },
61
  "icon": {
62
  "diam": 118,
63
+ "img": 106,
64
  "circle_bg": "#F1F5F9",
65
  "circle_border": "rgba(12,18,32,0.10)",
66
  },
 
80
  {
81
  "title": " ST_GeoMEch_UCS",
82
  "blurb": "Real-time Uniconfined Compressive Strength Prediction.",
83
+ "url": "https://smart-thinking-ucs.hf.space/",
84
+ "icon": ASSETS / "UCS_logo.png",
85
+ "style": {"bg_top": "#EAF7F1", "bg_bot": "#F6FBF8", "border": "#0F3D3E"},
86
  },
87
  {
88
  "title": " ST_GeoMEch_UCS",
89
  "blurb": "Real-time Uniconfined Compressive Strength Prediction.",
90
+ "url": "https://smart-thinking-ucs.hf.space/",
91
+ "icon": ASSETS / "UCS_logo.png",
92
+ "style": {"bg_top": "#EAF7F1", "bg_bot": "#F6FBF8", "border": "#0F3D3E"},
93
  },
94
  {
95
  "title": " ST_GeoMEch_UCS",
96
  "blurb": "Real-time Uniconfined Compressive Strength Prediction.",
97
+ "url": "https://smart-thinking-ucs.hf.space/",
98
+ "icon": ASSETS / "UCS_logo.png",
99
+ "style": {"bg_top": "#EAF7F1", "bg_bot": "#F6FBF8", "border": "#0F3D3E"},
100
  },
101
  {
102
  "title": " ST_GeoMEch_UCS",
103
  "blurb": "Real-time Uniconfined Compressive Strength Prediction.",
104
+ "url": "https://smart-thinking-ucs.hf.space/",
105
+ "icon": ASSETS / "UCS_logo.png",
106
+ "style": {"bg_top": "#EAF7F1", "bg_bot": "#F6FBF8", "border": "#0F3D3E"},
107
  },
108
  {
109
  "title": " ST_GeoMEch_UCS",
110
  "blurb": "Real-time Uniconfined Compressive Strength Prediction.",
111
+ "url": "https://smart-thinking-ucs.hf.space/",
112
+ "icon": ASSETS / "UCS_logo.png",
113
+ "style": {"bg_top": "#EAF7F1", "bg_bot": "#F6FBF8", "border": "#0F3D3E"},
114
  },
115
  {
116
  "title": " ST_GeoMech_Ym",
117
  "blurb": "Real-time Static Young's Modulus Prediction.",
118
+ "url": "https://smart-thinking-ym.hf.space",
119
+ "icon": ASSETS / "Ym_logo.png",
120
+ "style": {"bg_top": "#EAF7FD", "bg_bot": "#F5FBFF", "border": "#0E4A6E"},
121
  },
122
  {
123
  "title": " ST_GeoMech_SMW",
124
  "blurb": "Real-Time Safe Mud Window Prediction",
125
+ "url": "https://smart-thinking-smw.hf.space",
126
+ "icon": ASSETS / "SMW_logo.png",
127
+ "style": {"bg_top": "#EEF0FF", "bg_bot": "#F7F8FF", "border": "#3E4EB8"},
128
  },
129
  ]
130
 
 
138
  b64 = base64.b64encode(path.read_bytes()).decode("utf-8")
139
  return f"data:{mime};base64,{b64}"
140
 
141
+
142
  def img_tag(path: Path, alt: str, cls: str = "", style: str = "") -> str:
143
  uri = data_uri(path)
144
  if not uri:
 
147
  style_attr = f' style="{style}"' if style else ""
148
  return f'<img{cls_attr}{style_attr} src="{uri}" alt="{escape(alt)}" />'
149
 
150
+
151
  # ========= CSS (driven from THEME) =========
152
+ strip = THEME["strip"]
153
+ page = THEME["page"]
154
+ hero = THEME["hero"]
155
+ grid = THEME["grid"]
156
+ card = THEME["card"]
157
+ icon = THEME["icon"]
158
+ button = THEME["button"]
159
 
160
  bg_radial_css = """
161
  background:
 
166
  rgba(255,255,255,1) 100%);
167
  """ if page["bg_radial"] else "background: #fff;"
168
 
169
+ st.markdown(
170
+ f"""
171
  <style>
172
  :root {{
173
  --top-pad: {page["top_padding"]}px;
 
272
  /* ===== CARD ===== */
273
  .card {{
274
  position: relative;
275
+ width: 100%;
276
+ max-width: var(--card-w);
277
  border-radius: var(--c-radius, var(--card-r));
278
  padding: var(--c-pv, var(--card-pv)) var(--c-ph, var(--card-ph));
279
  background: linear-gradient(180deg, var(--c-bg-top, {card["bg_top"]}) 0%, var(--c-bg-bot, {card["bg_bot"]}) 100%);
 
284
  0 -1px 6px rgba(255,255,255,0.18) inset;
285
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease, filter .18s ease;
286
  text-align:center; display:flex; flex-direction:column; gap:16px; align-items: center;
287
+ margin: 0 auto;
288
  }}
289
  .card:hover {{
290
  transform: translateY(-6px) scale(1.01);
 
342
  .footer {{ text-align:center; color:#3f4a5a; font-size:0.96em; margin-top: 26px; }}
343
  .footer hr {{ margin: 12px 0; border-color: rgba(0,0,0,.08); }}
344
  </style>
345
+ """,
346
+ unsafe_allow_html=True,
347
+ )
348
 
349
  # ========= Strip (top-left) =========
350
  st.markdown(
351
+ """
352
  <div class="suite-row">
353
+ <span class="suite-pill">ST_GeoMech SUITE</span>
354
+ <span class="suite-tagline">Predicting Rock Mechanical Behavious While Drilling</span>
355
  </div>
356
  """,
357
  unsafe_allow_html=True,
 
361
  hero_html = img_tag(THEME["hero"]["logo"], "ST_GeoMech SUITE")
362
  st.markdown(f"<div class='hero'>{hero_html}</div>", unsafe_allow_html=True)
363
 
364
+
365
  def build_card_vars(style: Dict[str, Any]) -> str:
366
  s = []
367
+ if "width" in style:
368
+ s.append(f"--c-w:{int(style['width'])}px")
369
+ if "radius" in style:
370
+ s.append(f"--c-radius:{int(style['radius'])}px")
371
+ if "pad_v" in style:
372
+ s.append(f"--c-pv:{int(style['pad_v'])}px")
373
+ if "pad_h" in style:
374
+ s.append(f"--c-ph:{int(style['pad_h'])}px")
375
+ if "bg_top" in style:
376
+ s.append(f"--c-bg-top:{style['bg_top']}")
377
+ if "bg_bot" in style:
378
+ s.append(f"--c-bg-bot:{style['bg_bot']}")
379
+ if "border" in style:
380
+ s.append(f"--c-border:{style['border']}")
381
+ if "border_width" in style:
382
+ s.append(f"--c-bw:{int(style['border_width'])}px")
383
+ if "title_color" in style:
384
+ s.append(f"--c-title-color:{style['title_color']}")
385
+ if "title_fs" in style:
386
+ s.append(f"--c-title-fs:{int(style['title_fs'])}px")
387
+ if "blurb_color" in style:
388
+ s.append(f"--c-blurb-color:{style['blurb_color']}")
389
+ if "blurb_fs" in style:
390
+ s.append(f"--c-blurb-fs:{int(style['blurb_fs'])}px")
391
+ if "btn_bg1" in style:
392
+ s.append(f"--c-btn-bg1:{style['btn_bg1']}")
393
+ if "btn_bg2" in style:
394
+ s.append(f"--c-btn-bg2:{style['btn_bg2']}")
395
+ if "btn_text" in style:
396
+ s.append(f"--c-btn-text:{style['btn_text']}")
397
+ if "btn_border" in style:
398
+ s.append(f"--c-btn-border:{style['btn_border']}")
399
+ if "btn_fs" in style:
400
+ s.append(f"--c-btn-fs:{int(style['btn_fs'])}px")
401
+ if "btn_pad_v" in style:
402
+ s.append(f"--c-btn-pv:{int(style['btn_pad_v'])}px")
403
+ if "btn_pad_h" in style:
404
+ s.append(f"--c-btn-ph:{int(style['btn_pad_h'])}px")
405
+ if "icon_diam" in style:
406
+ s.append(f"--c-icon-d:{int(style['icon_diam'])}px")
407
+ if "icon_img" in style:
408
+ s.append(f"--c-icon-img:{int(style['icon_img'])}px")
409
+ if "icon_bg" in style:
410
+ s.append(f"--c-icon-bg:{style['icon_bg']}")
411
+ if "icon_border" in style:
412
+ s.append(f"--c-icon-border:{style['icon_border']}")
413
  return "; ".join(s)
414
 
415
+
416
  def app_card(card_cfg: Dict[str, Any]) -> str:
417
  style = card_cfg.get("style", {})
418
  vars_inline = build_card_vars(style)
419
+ icon_path = card_cfg.get("icon")
420
+ icon_html = img_tag(icon_path, "icon") if isinstance(icon_path, Path) and icon_path.exists() else ""
421
  target = "_self"
422
  return (
423
  f"<div class='card' style='{vars_inline}'>"
 
428
  + "</div>"
429
  )
430
 
431
+
432
  st.markdown("<div class='grid'>" + "".join(app_card(c) for c in CARDS) + "</div>", unsafe_allow_html=True)
433
 
434
  # ========= Footer =========