初步实现 netlist 保存

This commit is contained in:
锦恢 2025-01-03 20:40:29 +08:00
parent 3a7e0987bd
commit 5d579ba82a
20 changed files with 345 additions and 15 deletions

56
package-lock.json generated
View File

@ -8,6 +8,7 @@
"name": "digital-netlist-render",
"version": "0.1.0",
"dependencies": {
"axios": "^1.7.9",
"core-js": "^3.8.3",
"d3": "^7.9.0",
"d3-drag": "^3.0.0",
@ -3498,6 +3499,11 @@
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz",
@ -3544,6 +3550,16 @@
"postcss": "^8.1.0"
}
},
"node_modules/axios": {
"version": "1.7.9",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/babel-loader": {
"version": "8.4.1",
"resolved": "https://registry.npmmirror.com/babel-loader/-/babel-loader-8.4.1.tgz",
@ -4174,6 +4190,17 @@
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"dev": true
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/commander": {
"version": "8.3.0",
"resolved": "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz",
@ -5343,6 +5370,14 @@
"robust-predicates": "^3.0.2"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz",
@ -6571,7 +6606,6 @@
"version": "1.15.9",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
"dev": true,
"funding": [
{
"type": "individual",
@ -6587,6 +6621,19 @@
}
}
},
"node_modules/form-data": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz",
@ -8097,7 +8144,6 @@
"version": "1.52.0",
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"engines": {
"node": ">= 0.6"
}
@ -8106,7 +8152,6 @@
"version": "2.1.35",
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"dependencies": {
"mime-db": "1.52.0"
},
@ -9641,6 +9686,11 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/pseudomap/-/pseudomap-1.0.2.tgz",

View File

@ -8,6 +8,7 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"axios": "^1.7.9",
"core-js": "^3.8.3",
"d3": "^7.9.0",
"d3-drag": "^3.0.0",

View File

@ -13,7 +13,7 @@ exclude_folders = [
os.system('npm run build')
for file in os.listdir('dist'):
if file in exclude_files or file.endswith('.json'):
if file in exclude_files or file.endswith('.json') or file.endswith('.v'):
os.remove('dist/' + file)

View File

@ -1,4 +1,6 @@
<template>
<!-- 顶部工具栏 -->
<ToolBar></ToolBar>
<!-- 渲染区域 -->
<Render></Render>
<!-- 右侧工具合集 -->
@ -7,6 +9,7 @@
<script setup>
import Render from '@/components/render';
import ToolBar from '@/components/toolbar';
import RightNav from '@/components/right-nav.vue';
import { onMounted, watch } from 'vue';
import { setDefaultCss } from './hook/css';

16
src/api/index.js Normal file
View File

@ -0,0 +1,16 @@
import { globalLookup } from "@/hook/global";
import { pinkLog } from "@/hook/utils";
const mode = window.acquireVsCodeApi === undefined ? 'debug' : 'release';
pinkLog('digital-netlist-render mode: ' + mode);
let vscode = window.acquireVsCodeApi === undefined ? undefined : acquireVsCodeApi();
export async function saveAsSvg() {
const selection = globalLookup.netlistRender.selection;
}
export async function saveAsPdf() {
}

View File

@ -0,0 +1,5 @@
import { reactive } from "vue";
export const fileMenuContext = reactive({
show: false,
});

View File

@ -0,0 +1,101 @@
<template>
<div class="file-menu" :style="btnStyle">
<div
class="btn"
@click.stop="fileMenuContext.show = !fileMenuContext.show"
>
<span class="iconfont icon-menu"></span>
</div>
<!-- 菜单列表 -->
<transition name="collapse-from-top" mode="out-in">
<div class="list" v-show="fileMenuContext.show">
<SaveAsSvg></SaveAsSvg>
<SaveAsPdf></SaveAsPdf>
</div>
</transition>
</div>
</template>
<script setup>
import { computed, defineComponent } from 'vue';
import { fileMenuContext } from './control';
import SaveAsSvg from './save-as-svg.vue';
import SaveAsPdf from './save-as-pdf.vue';
defineComponent({ name: 'file-menu' });
const btnStyle = computed(() => ({
borderRadius: fileMenuContext.show ? '99em': '.5em'
}));
</script>
<style>
:root {
--menu-btn-width: calc(var(--toolbar-item-height) + 3px);
}
.file-menu {
height: var(--menu-btn-width);
width: var(--menu-btn-width);
background-color: var(--sidebar);
position: relative;
}
/* 这是按钮主体的 css */
.file-menu .btn {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
cursor: pointer;
}
.file-menu .list {
position: absolute;
top: calc(var(--menu-btn-width) + 10px);
left: 5px;
border-radius: .5em;
box-shadow: var(--gray-box-shadow-1);
background-color: var(--sidebar);
border: solid 1px var(--sidebar-border);
display: flex;
flex-direction: column;
padding: 10px 7px;
font-size: .9rem;
}
.file-menu .list .item {
margin: 2.5px;
padding: 4px;
width: 230px;
display: flex;
border-radius: .5em;
justify-content: space-between;
cursor: pointer;
transition: var(--animation-3s);
}
.file-menu .list > div {
display: flex;
align-items: center;
}
.file-menu .list .item:hover {
background-color: var(--sidebar-item-selected);
transition: var(--animation-3s);
}
.file-menu .list .status {
display: flex;
align-items: center;
font-size: 1.2rem;
width: 17px;
font-weight: 800;
}
</style>

View File

@ -0,0 +1,39 @@
<template>
<div>
<div class="status"></div>
<div class="item" @click="manualLoadView()">
<span>{{ t('toolbar.save-as-pdf') }}</span>
<span></span>
</div>
</div>
</template>
<script setup>
import { saveAsPdf } from '@/api';
import { ElLoading } from 'element-plus';
import { defineComponent } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
defineComponent({ name: 'save-as-pdf' });
async function manualLoadView() {
const loading = new ElLoading.service({
lock: true,
text: t('saving'),
background: 'rgba(0, 0, 0, 0.7)'
});
const res = await saveAsPdf();
loading.close();
}
// document.addEventListener('keydown', async event => {
// if (event.ctrlKey && event.key === 'k') {
// event.preventDefault();
// manualLoadView();
// }
// });
</script>

View File

@ -0,0 +1,39 @@
<template>
<div>
<div class="status"></div>
<div class="item" @click="manualLoadView()">
<span>{{ t('toolbar.save-as-svg') }}</span>
<span></span>
</div>
</div>
</template>
<script setup>
import { saveAsSvg } from '@/api';
import { ElLoading } from 'element-plus';
import { defineComponent } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
defineComponent({ name: 'save-as-svg' });
async function manualLoadView() {
const loading = new ElLoading.service({
lock: true,
text: t('saving'),
background: 'rgba(0, 0, 0, 0.7)'
});
const res = await saveAsSvg();
loading.close();
}
// document.addEventListener('keydown', async event => {
// if (event.ctrlKey && event.key === 'k') {
// event.preventDefault();
// manualLoadView();
// }
// });
</script>

View File

@ -0,0 +1,51 @@
<template>
<div
class="toolbar-container"
@mouseenter="onEnter()"
@click="toolBarClick()"
>
<div class="toolbar-body">
<FileMenu></FileMenu>
</div>
</div>
</template>
<script setup>
import { defineComponent } from 'vue';
import { fileMenuContext } from './file-menu/control';
import FileMenu from './file-menu';
/* eslint-disable vue/multi-word-component-names */
defineComponent({ name: 'toolbar' });
function onEnter() {
}
function toolBarClick() {
fileMenuContext.show = false;
}
</script>
<style>
.toolbar-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
min-width: 1000px;
height: var(--toolbar-height);
user-select: none;
background-color: var(--background);
z-index: 220;
}
.toolbar-body {
display: flex;
height: 100%;
align-items: top;
padding-left: 7px;
padding-top: 8px;
}
</style>

View File

@ -414,8 +414,6 @@ export class Module {
const connection = topSideConnections[i];
const xOffset = meta.getPortXOffset(connection.name);
console.log(xOffset);
ports.push({
id: connection.id,
renderName: connection.name,

View File

@ -41,5 +41,8 @@
"cross-dot-style.slice": "فاصل",
"cross-dot-style.connect": "محول مباشر",
"cross-dot-style.concat": "رمز الدمج",
"setting.pulsation-speed": "سرعة تأثير النبض"
"setting.pulsation-speed": "سرعة تأثير النبض",
"toolbar.save-as-svg": "حفظ العرض الحالي كـ SVG",
"toolbar.save-as-pdf": "حفظ العرض الحالي كـ PDF",
"saving": "جارٍ الحفظ"
}

View File

@ -41,5 +41,8 @@
"cross-dot-style.slice": "Trennzeichen",
"cross-dot-style.connect": "Direktverbinder",
"cross-dot-style.concat": "Zusammenführungszeichen",
"setting.pulsation-speed": "Pulseffektgeschwindigkeit"
"setting.pulsation-speed": "Pulseffektgeschwindigkeit",
"toolbar.save-as-svg": "Aktuelle Ansicht als SVG speichern",
"toolbar.save-as-pdf": "Aktuelle Ansicht als PDF speichern",
"saving": "Wird gespeichert"
}

View File

@ -41,5 +41,8 @@
"cross-dot-style.slice": "Separator",
"cross-dot-style.connect": "Direct connector",
"cross-dot-style.concat": "Combining Character",
"setting.pulsation-speed": "Pulse Effect Speed"
"setting.pulsation-speed": "Pulse Effect Speed",
"toolbar.save-as-svg": "Save current view as SVG",
"toolbar.save-as-pdf": "Save current view as PDF",
"saving": "Saving"
}

View File

@ -41,5 +41,8 @@
"cross-dot-style.slice": "Séparateur",
"cross-dot-style.connect": "Connecteur direct",
"cross-dot-style.concat": "Caractère de combinaison",
"setting.pulsation-speed": "Vitesse de l'effet de pulsation"
"setting.pulsation-speed": "Vitesse de l'effet de pulsation",
"toolbar.save-as-svg": "Enregistrer la vue actuelle au format SVG",
"toolbar.save-as-pdf": "Enregistrer la vue actuelle en PDF",
"saving": "Enregistrement en cours"
}

View File

@ -41,5 +41,8 @@
"cross-dot-style.slice": "区切り文字",
"cross-dot-style.connect": "ダイレクトコネクタ",
"cross-dot-style.concat": "結合文字",
"setting.pulsation-speed": "パルスエフェクト速度"
"setting.pulsation-speed": "パルスエフェクト速度",
"toolbar.save-as-svg": "現在のビューをSVGとして保存",
"toolbar.save-as-pdf": "現在のビューをPDFとして保存",
"saving": "保存中"
}

View File

@ -41,5 +41,8 @@
"cross-dot-style.slice": "구분자",
"cross-dot-style.connect": "직접 연결기",
"cross-dot-style.concat": "결합 문자",
"setting.pulsation-speed": "펄스 효과 속도"
"setting.pulsation-speed": "펄스 효과 속도",
"toolbar.save-as-svg": "현재 뷰를 SVG로 저장",
"toolbar.save-as-pdf": "현재 보기를 PDF로 저장",
"saving": "저장 중"
}

View File

@ -41,5 +41,8 @@
"cross-dot-style.slice": "Разделитель",
"cross-dot-style.connect": "Прямой соединитель",
"cross-dot-style.concat": "Комбинирующий символ",
"setting.pulsation-speed": "Скорость импульсного эффекта"
"setting.pulsation-speed": "Скорость импульсного эффекта",
"toolbar.save-as-svg": "Сохранить текущее представление как SVG",
"toolbar.save-as-pdf": "Сохранить текущее представление как PDF",
"saving": "Сохранение"
}

View File

@ -41,5 +41,8 @@
"cross-dot-style.slice": "拆分符",
"cross-dot-style.connect": "直连符",
"cross-dot-style.concat": "合并符",
"setting.pulsation-speed": "脉冲特效速度"
"setting.pulsation-speed": "脉冲特效速度",
"toolbar.save-as-svg": "将当前视图保存为 svg",
"toolbar.save-as-pdf": "将当前视图保存为 pdf",
"saving": "保存中"
}

View File

@ -41,5 +41,8 @@
"cross-dot-style.slice": "分隔符",
"cross-dot-style.connect": "直連符",
"cross-dot-style.concat": "合併符",
"setting.pulsation-speed": "脈衝特效速度"
"setting.pulsation-speed": "脈衝特效速度",
"toolbar.save-as-svg": "將目前視圖儲存為SVG",
"toolbar.save-as-pdf": "將目前視圖儲存為PDF",
"saving": "保存中"
}