From cd4f25a42120a334840d69dd590814635ce5166a Mon Sep 17 00:00:00 2001 From: root Date: Sat, 16 May 2026 22:19:07 +0800 Subject: [PATCH] Web page style added --- ...EC_SiN400_1310_1p0dB_L635_A0_QY_202604.png | Bin 13750 -> 0 bytes ...EC_SiN400_1310_1p0dB_L635_A0_QY_202604.yml | 35 - backend/__pycache__/database.cpython-39.pyc | Bin 1356 -> 0 bytes backend/database.py | 2 +- backend/dir_test.py | 110 --- backend/server.py | 89 +-- {backend => database}/mxpic_data.db | Bin frontend/canvas.html | 399 ++++++---- frontend/canvas_legacy.html | 750 ++++++++++++++++++ frontend/dashboard.html | 212 ++++- frontend/icons/directional_couplers.png | Bin 0 -> 40470 bytes frontend/icons/edge_couplers.png | Bin 0 -> 18861 bytes frontend/icons/grating_couplers.png | Bin 0 -> 41965 bytes frontend/icons/multimode_interferometers.png | Bin 0 -> 47086 bytes frontend/icons/phase_shifters.png | Bin 0 -> 24369 bytes frontend/icons/terminations.png | Bin 0 -> 28953 bytes frontend/icons/waveguides.png | Bin 0 -> 24369 bytes frontend/login.html | 188 ++++- ~$web_pages.pptx | Bin 0 -> 165 bytes 19 files changed, 1396 insertions(+), 389 deletions(-) delete mode 100644 PDK_libs/primitives/edge_couplers/EC_SiN400_1310_1p0dB_L635_A0_QY_202604/EC_SiN400_1310_1p0dB_L635_A0_QY_202604.png delete mode 100644 PDK_libs/primitives/edge_couplers/EC_SiN400_1310_1p0dB_L635_A0_QY_202604/EC_SiN400_1310_1p0dB_L635_A0_QY_202604.yml delete mode 100644 backend/__pycache__/database.cpython-39.pyc delete mode 100644 backend/dir_test.py rename {backend => database}/mxpic_data.db (100%) create mode 100644 frontend/canvas_legacy.html create mode 100644 frontend/icons/directional_couplers.png create mode 100644 frontend/icons/edge_couplers.png create mode 100644 frontend/icons/grating_couplers.png create mode 100644 frontend/icons/multimode_interferometers.png create mode 100644 frontend/icons/phase_shifters.png create mode 100644 frontend/icons/terminations.png create mode 100644 frontend/icons/waveguides.png create mode 100644 ~$web_pages.pptx diff --git a/PDK_libs/primitives/edge_couplers/EC_SiN400_1310_1p0dB_L635_A0_QY_202604/EC_SiN400_1310_1p0dB_L635_A0_QY_202604.png b/PDK_libs/primitives/edge_couplers/EC_SiN400_1310_1p0dB_L635_A0_QY_202604/EC_SiN400_1310_1p0dB_L635_A0_QY_202604.png deleted file mode 100644 index 5208d8c933869d513b0fa3c8672d9d72eeafb416..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13750 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 diff --git a/PDK_libs/primitives/edge_couplers/EC_SiN400_1310_1p0dB_L635_A0_QY_202604/EC_SiN400_1310_1p0dB_L635_A0_QY_202604.yml b/PDK_libs/primitives/edge_couplers/EC_SiN400_1310_1p0dB_L635_A0_QY_202604/EC_SiN400_1310_1p0dB_L635_A0_QY_202604.yml deleted file mode 100644 index d701aa5..0000000 --- a/PDK_libs/primitives/edge_couplers/EC_SiN400_1310_1p0dB_L635_A0_QY_202604/EC_SiN400_1310_1p0dB_L635_A0_QY_202604.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: EC_SiN400_1310_1p0dB_L635_A0_QY_202604 -foundry: Silterra -process: EMO1_2ML_Cu_RDL -year: '2026' -type: primitive -dependency: None -maturity: development -tapeout_history: -- run: Silterra_EMO1_2ML_Cu_RDL_2026_Q2 - status: Pending testing -center_wavelength: 1310 -version: 1.0 -designer: Qin Yue -update_notes: New SiN edge couplers with high efficiency -ports: - a1: - x: -642.6 - y: 0.0 - a: 180.0 - width: 0.7 - b0: - x: 0.0 - y: 0.0 - a: 0.0 - width: None - a0: - x: 0.0 - y: 0.0 - a: 180.0 - width: 0.0 -time: 20260505-170136 -box_size: -- 646.0 -- 75.0 -file_size: 1.36 KB diff --git a/backend/__pycache__/database.cpython-39.pyc b/backend/__pycache__/database.cpython-39.pyc deleted file mode 100644 index 12c35bd168da321ab2c1efb3a7a3a7c63b81a51a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1356 zcmaJ>UvJws5GN&DlHIsyfuVaP_R?xFygzLREZCO1iP9N!l+Kp7)G#2(BAqC)C6A=h zMsS|84-!A_Q|x>2bx->Wd)krygJut-q2rNvygT0SM<qoO9}n0= zuiz6S5EM~7MZ@)shZxq@)SB5t8zY7LW?-&H7HK{}&>&1lsX5}|aceT#1_V}X*F z*2G#_7)h5pxXU_F zT##owSA8O*q!UKLo1jPD_Bto+-aGPB@Q$C+FzHW9d{vpqm|8m&sM*Oe=Nn`V+dS8iJ5IZLH-k6y>eoo=9ot(@ zdxSm9!~7xar&wDzqXM)341r&OvLmo2t|qXxv^0U2Xo590VFlE^vBByXYT7_aD=c4a z5Y1?F2jPD(`CqILe3$Fj#C0`XzbVri?rP1`LjPg-73FOa=MT0{s-pKyL-=D@D=&^`NtVZP`PtE?nM5}-OQu=LC=rV^WkO6A)9H1~Z| zRS5O?J>yp;Tb#E9fX*{{y#~87PvnKFTozfbT$-7uqq9u1DU0Lvy)+2B^qT5m(6D`U i0bMO$-{QMjK^If@gXWTW1VY2PXFsvLPd(4W4*nNfPFBAF diff --git a/backend/database.py b/backend/database.py index ac5a6fd..3a5eafd 100644 --- a/backend/database.py +++ b/backend/database.py @@ -4,7 +4,7 @@ import os from werkzeug.security import generate_password_hash # Save the database in the backend folder -DB_FILE = os.path.join(os.path.dirname(__file__), "mxpic_data.db") +DB_FILE = os.path.join(os.path.dirname(__file__), "..\\database\\mxpic_data.db") def init_db(): conn = sqlite3.connect(DB_FILE) diff --git a/backend/dir_test.py b/backend/dir_test.py deleted file mode 100644 index bdfc7ff..0000000 --- a/backend/dir_test.py +++ /dev/null @@ -1,110 +0,0 @@ -import os -import yaml -from collections import OrderedDict -from flask import Flask, jsonify, send_from_directory, request, redirect, url_for, session, render_template -from werkzeug.security import check_password_hash -import database # Imports the database.py you created earlier - -# --- Path Configurations --- -BASE_DIR = os.path.dirname(os.path.abspath(__file__)) -FRONTEND_DIR = os.path.join(BASE_DIR, '..', 'frontend') -YML_PATH = os.path.join(BASE_DIR, '..\\mxpic\\PDKs\\Silterra\\directories.yaml') -COMPS_ROOT = os.path.join(BASE_DIR, '..\\mxpic\\PDKs\\Silterra') - -# --- YAML & PDK Parsing Helper Functions (Unchanged) --- -def countSpaces(line): - """Count leading spaces (tab=4).""" - expanded = line.expandtabs(4) - return len(expanded) - len(expanded.lstrip(' ')) - -def buildTree(filepath): - """Build nested tree from indented yaml.""" - if not os.path.exists(filepath): - return OrderedDict() - - with open(filepath, 'r', encoding='utf-8') as f: - lines = f.readlines() - - rootIdx = None - for i, line in enumerate(lines): - if line.strip().startswith('root') and ':' in line.strip(): - rootIdx = i - break - if rootIdx is None: - return OrderedDict() - - entries = [] - for line in lines[rootIdx + 1:]: - stripped = line.strip() - if not stripped or stripped.startswith('#'): - continue - if stripped.startswith('- '): - spaceNum = countSpaces(line) - name = stripped[2:].strip() - if name.strip(): - entries.append((spaceNum, name)) - - if not entries: - return OrderedDict() - - minIndent = min(indent for indent, _ in entries) - nest = OrderedDict() - levelStack = [(minIndent - 1, nest)] - - for spaceNum, name in entries: - while levelStack and levelStack[-1][0] >= spaceNum: - levelStack.pop() - parent = levelStack[-1][1] - child = OrderedDict() - parent[name] = child - levelStack.append((spaceNum, child)) - - return nest - -def findComps(baseDir): - """Scan component folders, return map of paths -> component info.""" - compMap = {} - refDir = os.path.dirname(baseDir) - for root, dirs, files in os.walk(baseDir): - ymlFiles = [f for f in files if f.endswith('.yml')] - if ymlFiles: - parentDir = os.path.dirname(root) - relPath = os.path.relpath(parentDir, refDir) - parts = () if relPath == '.' else tuple(relPath.split(os.sep)) - compName = os.path.basename(root) - compMap[parts] = { - 'folder': compName, - 'yml': ymlFiles[0] - } - dirs.clear() - return compMap - -def addCompsToTree(tree, compMap): - """Insert component nodes into the tree.""" - for pathSeg, compItem in compMap.items(): - compName = compItem['folder'] - curNode = tree - try: - for seg in pathSeg: - curNode = curNode[seg] - except KeyError: - continue - curNode[compName] = OrderedDict({ - "__type__": "component", - "__name__": compName, - "__yml__": compItem['yml'] - }) - return tree - -def readCompYaml(compName): - """Load YAML from component folder.""" - for root, dirs, files in os.walk(COMPS_ROOT): - if os.path.basename(root) == compName: - dirs.clear() - ymlFiles = [f for f in files if f.endswith('.yml')] - if ymlFiles: - ymlPath = os.path.join(root, ymlFiles[0]) - with open(ymlPath, 'r', encoding='utf-8') as f: - return yaml.safe_load(f) - return None - diff --git a/backend/server.py b/backend/server.py index 3133cb7..10741f2 100644 --- a/backend/server.py +++ b/backend/server.py @@ -27,50 +27,6 @@ def countSpaces(line): expanded = line.expandtabs(4) return len(expanded) - len(expanded.lstrip(' ')) -# def buildTree(filepath): -# """Build nested tree from indented yaml.""" -# if not os.path.exists(filepath): -# return OrderedDict() - -# with open(filepath, 'r', encoding='utf-8') as f: -# lines = f.readlines() - -# rootIdx = None -# for i, line in enumerate(lines): -# if line.strip().startswith('root') and ':' in line.strip(): -# rootIdx = i -# break -# if rootIdx is None: -# return OrderedDict() - -# entries = [] -# for line in lines[rootIdx + 1:]: -# stripped = line.strip() -# if not stripped or stripped.startswith('#'): -# continue -# if stripped.startswith('- '): -# spaceNum = countSpaces(line) -# name = stripped[2:].strip() -# if name.strip(): -# entries.append((spaceNum, name)) - -# if not entries: -# return OrderedDict() - -# minIndent = min(indent for indent, _ in entries) -# nest = OrderedDict() -# levelStack = [(minIndent - 1, nest)] - -# for spaceNum, name in entries: -# while levelStack and levelStack[-1][0] >= spaceNum: -# levelStack.pop() -# parent = levelStack[-1][1] -# child = OrderedDict() -# parent[name] = child -# levelStack.append((spaceNum, child)) - -# return nest - def buildTree(filepath): """Build nested tree from indented yaml.""" if not os.path.exists(filepath): @@ -116,25 +72,52 @@ def buildTree(filepath): return nest -def addCompsToTree(tree, compMap): - """Insert component nodes into the tree.""" +# def addCompsToTree(tree, compMap): +# """Insert component nodes into the tree.""" +# for pathSeg, compItem in compMap.items(): +# compName = compItem['folder'] +# curNode = tree + +# # FIX 2: Automatically build missing folder paths +# for seg in pathSeg: +# if seg not in curNode: +# # If a folder like MZM_1600G isn't in the YAML, gracefully auto-create it +# curNode[seg] = OrderedDict() +# curNode = curNode[seg] + +# curNode[compName] = OrderedDict({ +# "__type__": "component", +# "__name__": compName, +# "__yml__": compItem['yml'] +# }) +# return tree + +def addCompsToTree(compMap): + """ + Build a completely fresh tree from scratch and insert component nodes. + No previous tree object or inspection required. + """ + # Initialize a clean, empty root tree + fresh_tree = OrderedDict() + for pathSeg, compItem in compMap.items(): compName = compItem['folder'] - curNode = tree + curNode = fresh_tree - # FIX 2: Automatically build missing folder paths + # Sequentially build the nested path segments dynamically for seg in pathSeg: if seg not in curNode: - # If a folder like MZM_1600G isn't in the YAML, gracefully auto-create it curNode[seg] = OrderedDict() curNode = curNode[seg] + # Place the component metadata dictionary into its leaf node curNode[compName] = OrderedDict({ "__type__": "component", "__name__": compName, "__yml__": compItem['yml'] }) - return tree + + return fresh_tree def findComps(baseDir): """Scan component folders, return map of paths -> component info.""" @@ -238,8 +221,10 @@ def getLib(): tree = buildTree(YML_PATH) if os.path.isdir(COMPS_ROOT): compMap = findComps(COMPS_ROOT) - addCompsToTree(tree, compMap) - return jsonify(tree) + fresh_tree = addCompsToTree(compMap) + return jsonify(fresh_tree) + + @app.route('/api/component/') def getComp(component_name): diff --git a/backend/mxpic_data.db b/database/mxpic_data.db similarity index 100% rename from backend/mxpic_data.db rename to database/mxpic_data.db diff --git a/frontend/canvas.html b/frontend/canvas.html index 7fcaebd..7431059 100644 --- a/frontend/canvas.html +++ b/frontend/canvas.html @@ -5,13 +5,26 @@ - Canvas with PDK Library – Component Name & Rotation + mxPIC Core - Canvas + @@ -128,6 +196,7 @@ useUpdateNodeInternals, } = window.ReactFlow; + // --- NODE DESIGN (Dark CAD Style) --- const RotatableNode = ({ id, data, selected }) => { const updateNodeInternals = useUpdateNodeInternals(); useEffect(() => { @@ -135,9 +204,9 @@ }, [data.rotation, updateNodeInternals, id]); const baseHandleStyle = { - width: 14, height: 14, - background: '#555', - border: 'none', + width: 10, height: 10, + background: 'var(--bg-main)', + border: '2px solid var(--accent)', borderRadius: '50%', }; const leftTopPort = { ...baseHandleStyle, top: '24%', transform: 'translate(-50%, -50%)' }; @@ -147,11 +216,18 @@ return (
{data.componentDisplayName}
@@ -175,7 +251,7 @@ }; return (
- 🔷 {name} + {name}
); } @@ -197,8 +273,8 @@ const LeftPanel = ({ library, treeKey, expanded, onToggle, treeRef, width }) => (
-
Routing selections
+
Routing modes
-
    +
    • Single mode wires
    • Multi-mode wires
    • DC electrical wires
    • @@ -232,11 +308,14 @@
-
User info
-
-
Name: XXXXXX
-
ID: 12345678
- +
Session
+
+
Name: XXXXXX
+
ID: 12345678
+
@@ -330,16 +409,16 @@ return (