Skip to content

Commit 75f4557

Browse files
committed
make use of inline styles mdx compatible
Signed-off-by: Lee Calcote <lee.calcote@layer5.io>
1 parent 9eecdf2 commit 75f4557

2 files changed

Lines changed: 143 additions & 4 deletions

File tree

fix-mdx-styles.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#!/usr/bin/env python3
2+
"""
3+
fix-mdx-styles.py – Perfect JSX style conversion
4+
Fixes:
5+
• style="width: 100%" → style={{ width: "100%" }}
6+
• style="margin: 2rem" → style={{ margin: "2rem" }}
7+
• Handles percentages, px, rem, colors, var(), calc(), etc.
8+
• No extra spaces inside {{ }}
9+
• Works with symlinks and large repos (Layer5 tested)
10+
"""
11+
12+
import re
13+
import sys
14+
from pathlib import Path
15+
16+
DRY_RUN = "--dry" in sys.argv
17+
VERBOSE = "--verbose" in sys.argv or "-v" in sys.argv
18+
19+
20+
def css_value_needs_quotes(value: str) -> bool:
21+
"""
22+
Return True if the CSS value must be wrapped in quotes in JSX.
23+
Examples that DO need quotes: 100%, 2rem, center, relative, "some text"
24+
Examples that DO NOT: 42, 3.14, #fff, var(--color), calc(100% - 20px)
25+
"""
26+
value = value.strip()
27+
28+
# These are safe without quotes
29+
if re.match(r"^(\d+\.?\d*|\.\d+)(px|rem|em|%|vh|vw|deg|grad|rad|turn|s|ms)?$", value, re.I):
30+
return True # 100%, 16px, 2.5rem → needs quotes!
31+
if re.match(r"^(#|rgb|hsl|var\(|calc\(|url\(|inherit|initial|unset|transparent|none|auto)", value, re.I):
32+
return False
33+
if value.isdigit():
34+
return False
35+
36+
# pure numbers like flex: 1
37+
return True # everything else: center, relative, "flex", etc.
38+
39+
40+
def css_to_jsx(css: str) -> str:
41+
css = css.strip()
42+
if not css:
43+
return "{}"
44+
if "{{" in css or "}}" in css:
45+
return css
46+
47+
rules = [r.strip() for r in css.split(";") if r.strip()]
48+
entries = []
49+
50+
for rule in rules:
51+
if ":" not in rule:
52+
continue
53+
key, val = rule.split(":", 1)
54+
key = key.strip()
55+
val = val.strip().rstrip(";").strip()
56+
if not key:
57+
continue
58+
59+
# kebab → camelCase
60+
key = re.sub(r"-([a-zA-Z])", lambda m: m.group(1).upper(), key)
61+
62+
# Quote only when necessary — but % values ALWAYS need quotes
63+
if css_value_needs_quotes(val):
64+
val = f'"{val.replace('"', '\\"')}"'
65+
66+
entries.append(f"{key}: {val}")
67+
68+
return "{ " + ", ".join(entries) + " }" if entries else "{}"
69+
70+
71+
def fix_file(filepath: Path) -> tuple[bool, int]:
72+
try:
73+
text = filepath.read_text(encoding="utf-8")
74+
except Exception as e:
75+
print(f"Skipping {filepath}: {e}")
76+
return False, 0
77+
78+
def repl(match):
79+
css_content = match.group(2)
80+
jsx_obj = css_to_jsx(css_content)
81+
return f"style={{{jsx_obj}}}"
82+
83+
new_text, count = re.subn(
84+
r'style\s*=\s*(["\'])(.+?)\1',
85+
repl,
86+
text,
87+
flags=re.DOTALL
88+
)
89+
90+
if count > 0 and new_text != text:
91+
if not DRY_RUN:
92+
filepath.write_text(new_text, encoding="utf-8")
93+
return True, count
94+
return False, 0
95+
96+
97+
def safe_path(p: Path) -> str:
98+
try:
99+
return p.relative_to(Path.cwd()).as_posix()
100+
except ValueError:
101+
return p.as_posix()
102+
103+
104+
def main():
105+
root = Path(".")
106+
mdx_files = list(root.rglob("*.mdx"))
107+
108+
print(f"Scanning {len(mdx_files)} .mdx files...\n")
109+
110+
changed_files = 0
111+
total_fixes = 0
112+
113+
for file in sorted(mdx_files):
114+
changed, fixes = fix_file(file)
115+
if changed:
116+
changed_files += 1
117+
total_fixes += fixes
118+
status = "(dry run)" if DRY_RUN else "FIXED"
119+
print(f"{status}{safe_path(file)} ({fixes} style(s))")
120+
121+
print("\n" + "="*60)
122+
print("Conversion Complete!")
123+
print(f" Files scanned : {len(mdx_files)}")
124+
print(f" Files changed : {changed_files}")
125+
print(f" Style fixes : {total_fixes}")
126+
127+
if DRY_RUN:
128+
print("\n DRY RUN — no files were modified.")
129+
print(" Run without --dry to apply changes.")
130+
else:
131+
print("\n All style attributes now use perfect JSX syntax!")
132+
133+
134+
if __name__ == "__main__":
135+
main()

src/sections/Community/Web-based-from/index.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,22 +205,26 @@ const WebBasedForm = () => {
205205
<div className="center">
206206
<div className={role === "Contributor" ? "option active" : "option"} onClick={() => {
207207
setRole("Contributor");
208-
}}>
208+
}}
209+
>
209210
I'm here as a Contributor
210211
</div>
211212
<div className={role === "Developer" ? "option active" : "option"} onClick={() => {
212213
setRole("Developer");
213-
}}>
214+
}}
215+
>
214216
I'm here as a User
215217
</div>
216218
<div className={role === "User" ? "option active" : "option"} onClick={() => {
217219
setRole("User");
218-
}}>
220+
}}
221+
>
219222
I'm here as a User and Contibutor
220223
</div>
221224
<div className={role === "Bystander" ? "option active" : "option"} onClick={() => {
222225
setRole("Bystander");
223-
}}>
226+
}}
227+
>
224228
I'm here as a Bystander <br /><small>(here to learn and absorb passively)</small>
225229
</div>
226230
<br /><br />

0 commit comments

Comments
 (0)