This commit is contained in:
2026-02-26 11:45:32 +08:00
parent 11d7093af6
commit 708b1f7a36
53 changed files with 1101 additions and 348 deletions

View File

@@ -0,0 +1,3 @@
<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 8.00002C-3.54464e-07 7.7348 0.105356 7.48045 0.292892 7.29291L7.29289 0.292894C7.68342 -0.09763 8.31658 -0.0976319 8.70711 0.292892C9.09763 0.683416 9.09763 1.31658 8.70711 1.70711L3.41421 7.00002H17C17.5523 7.00002 18 7.44773 18 8.00002C18 8.5523 17.5523 9.00002 17 9.00002L3.41422 9.00002L8.70711 14.2929C9.09763 14.6834 9.09763 15.3166 8.70711 15.7071C8.31658 16.0976 7.68342 16.0976 7.29289 15.7071L0.292894 8.70712C0.105358 8.51959 3.54466e-07 8.26524 0 8.00002Z" fill="#FFF" />
</svg>

After

Width:  |  Height:  |  Size: 599 B

View File

@@ -1,3 +1,3 @@
<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 8.00002C-3.54464e-07 7.7348 0.105356 7.48045 0.292892 7.29291L7.29289 0.292894C7.68342 -0.09763 8.31658 -0.0976319 8.70711 0.292892C9.09763 0.683416 9.09763 1.31658 8.70711 1.70711L3.41421 7.00002H17C17.5523 7.00002 18 7.44773 18 8.00002C18 8.5523 17.5523 9.00002 17 9.00002L3.41422 9.00002L8.70711 14.2929C9.09763 14.6834 9.09763 15.3166 8.70711 15.7071C8.31658 16.0976 7.68342 16.0976 7.29289 15.7071L0.292894 8.70712C0.105358 8.51959 3.54466e-07 8.26524 0 8.00002Z" fill="#0D0D0D"/>
<path d="M0 8.00002C-3.54464e-07 7.7348 0.105356 7.48045 0.292892 7.29291L7.29289 0.292894C7.68342 -0.09763 8.31658 -0.0976319 8.70711 0.292892C9.09763 0.683416 9.09763 1.31658 8.70711 1.70711L3.41421 7.00002H17C17.5523 7.00002 18 7.44773 18 8.00002C18 8.5523 17.5523 9.00002 17 9.00002L3.41422 9.00002L8.70711 14.2929C9.09763 14.6834 9.09763 15.3166 8.70711 15.7071C8.31658 16.0976 7.68342 16.0976 7.29289 15.7071L0.292894 8.70712C0.105358 8.51959 3.54466e-07 8.26524 0 8.00002Z" fill="#0D0D0D" />
</svg>

Before

Width:  |  Height:  |  Size: 601 B

After

Width:  |  Height:  |  Size: 602 B

View File

@@ -0,0 +1,3 @@
<svg width="15" height="19" viewBox="0 0 15 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.6709 0.0615234C8.10609 0.0283563 8.55366 0.134081 8.89941 0.387695C9.23305 0.632466 9.46557 1.01335 9.50391 1.53125C10.351 1.35132 11.267 1.44554 11.7588 2.27734C11.8015 2.3493 11.8659 2.4826 11.9189 2.61523C11.9456 2.68187 11.9695 2.74999 11.9873 2.81055C12.0046 2.86956 12.0175 2.92657 12.0176 2.9707V3.5957C12.5446 3.4294 13.14 3.49012 13.624 3.73828C14.1314 3.99842 14.5203 4.46431 14.5742 5.08496C14.6215 5.63262 14.6169 6.23619 14.6025 6.84082C14.5882 7.44669 14.5638 8.05348 14.5703 8.6123C14.5869 9.99368 14.7346 11.4314 14.6328 12.7979C14.5306 14.1688 14.1779 15.482 13.1865 16.626C12.0543 17.9324 10.3202 18.602 8.55762 18.6631C6.7949 18.724 4.99508 18.1761 3.72949 17.04C1.92211 15.417 1.55066 13.6053 0.762695 11.4863C0.683586 11.2735 0.580869 11.0633 0.477539 10.8525C0.374729 10.6428 0.271227 10.4322 0.195312 10.2217C-0.173241 9.19784 0.228813 8.3138 0.931641 7.84082C1.60836 7.3855 2.5633 7.31169 3.37402 7.85449V3.34961H3.375C3.51944 2.06624 4.91534 1.38488 6.06836 1.80664C6.0365 1.28206 6.21192 0.868618 6.50293 0.575195C6.80823 0.26738 7.23566 0.0947109 7.6709 0.0615234ZM7.72461 1.09375C7.46487 1.08615 7.19561 1.25846 7.1543 1.625L7.15137 8.6123L7.13965 8.73438C7.09082 9.00322 6.89341 9.17338 6.67676 9.20898C6.55333 9.22924 6.42377 9.20583 6.31445 9.13184C6.20476 9.05759 6.11923 8.93515 6.0791 8.76465L6.07617 8.75195H6.07812L6.05176 3.38672C5.98373 3.13985 5.70675 2.9778 5.40723 2.95508C5.10822 2.93245 4.82595 3.05106 4.74219 3.32129V9.65234L5.86621 11.4463L5.87012 11.4531L5.87207 11.46C5.97956 11.8175 5.83236 12.1087 5.58691 12.2363C5.34248 12.3633 5.0111 12.3228 4.7627 12.0459C4.43376 11.6788 4.12868 11.1543 3.83105 10.624C3.53193 10.0911 3.24004 9.55123 2.93457 9.14258C2.75922 8.90799 2.52347 8.74466 2.2793 8.69531C2.03753 8.64653 1.78269 8.70852 1.55957 8.93164L1.55859 8.93262C1.51343 8.9778 1.45826 9.06092 1.41211 9.15332C1.36587 9.24592 1.33277 9.33916 1.3252 9.40137C1.32117 9.43477 1.32473 9.48179 1.33691 9.54199C1.34896 9.60148 1.36879 9.67074 1.39453 9.74707C1.44598 9.89961 1.51989 10.0773 1.60059 10.2588C1.76058 10.6185 1.94881 10.9985 2.02344 11.207C2.59378 12.8 2.9251 14.2378 4.05176 15.5625C5.42953 17.1827 7.62816 17.7419 9.54785 17.3232C11.4658 16.9049 13.0978 15.5124 13.3545 13.2334L13.3301 5.12207C13.2531 4.84033 12.9517 4.69225 12.6455 4.72461C12.3426 4.75666 12.0525 4.96612 12.0156 5.38379C11.9584 6.03179 11.9831 6.71982 12.0088 7.41406C12.0344 8.10699 12.0609 8.8062 12.0059 9.4707V9.47559H12.0049C11.9452 9.83123 11.6474 10.0102 11.3555 10.0137C11.0633 10.0171 10.763 9.84488 10.7012 9.48828L10.6992 9.47852H10.7002L10.6963 3.17578L10.665 3.01562C10.5699 2.66693 10.3323 2.48832 10.1123 2.47852C9.98617 2.47302 9.85974 2.52211 9.75879 2.63184C9.65734 2.74218 9.5789 2.91723 9.55762 3.16602L9.55664 8.99316V9.00098L9.55469 9.00977C9.44373 9.36044 9.13052 9.5024 8.84082 9.4668C8.55173 9.43119 8.27883 9.21782 8.24414 8.85645L8.24316 8.85059L8.24512 1.66797L8.23145 1.5332C8.2069 1.40874 8.15154 1.31244 8.08008 1.24219C7.98412 1.14786 7.85599 1.09762 7.72461 1.09375Z" fill="black" stroke="black" stroke-width="0.111111"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,3 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.20508 0.851562C0.985291 0.774157 0.7742 0.985289 0.851562 1.20508L5.83887 15.3369C5.92158 15.5713 6.24738 15.5874 6.35254 15.3623L8.91992 9.85938C9.11305 9.44566 9.44564 9.11303 9.85938 8.91992L15.3623 6.35254C15.5873 6.24733 15.5712 5.92157 15.3369 5.83887L1.20508 0.851562Z" stroke="#0D0D0D" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 481 B

View File

@@ -0,0 +1,3 @@
<svg width="23" height="23" viewBox="0 0 23 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14.16 2.12276C13.7984 2.48436 13.7984 3.07062 14.16 3.43222L16.283 5.55527H9.25915C5.67953 5.55527 2.77767 8.45712 2.77767 12.0367C2.77767 15.6164 5.67953 18.5182 9.25915 18.5182H12.9629C13.4742 18.5182 13.8888 18.1037 13.8888 17.5923C13.8888 17.0809 13.4742 16.6664 12.9629 16.6664H9.25915C6.70228 16.6664 4.62952 14.5936 4.62952 12.0367C4.62952 9.47987 6.70228 7.40712 9.25915 7.40712H16.283L14.16 9.53017C13.7984 9.89176 13.7984 10.478 14.16 10.8396C14.5216 11.2012 15.1078 11.2012 15.4694 10.8396L19.1731 7.13592C19.5347 6.77432 19.5347 6.18806 19.1731 5.82646L15.4694 2.12276C15.1078 1.76116 14.5216 1.76116 14.16 2.12276Z" fill="#0D0D0D"/>
</svg>

After

Width:  |  Height:  |  Size: 759 B

6
src/assets/icons/c-t.svg Normal file
View File

@@ -0,0 +1,6 @@
<svg width="23" height="23" viewBox="0 0 23 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.66623 17.7762C7.27988 17.7762 7.77735 17.2787 7.77735 16.6651C7.77735 16.0514 7.27988 15.5539 6.66623 15.5539C6.05259 15.5539 5.55512 16.0514 5.55512 16.6651C5.55512 17.2787 6.05259 17.7762 6.66623 17.7762Z" fill="black"/>
<path d="M16.144 11.404C16.3218 10.9206 17.0051 10.9206 17.1885 11.404L17.7773 12.9984C17.8329 13.1484 17.9551 13.2706 18.1051 13.3262L19.6996 13.9151C20.1829 14.0928 20.1829 14.7762 19.6996 14.9595L18.1051 15.5484C17.9551 15.604 17.8329 15.7262 17.7773 15.8762L17.1885 17.4706C17.0107 17.9539 16.3273 17.9539 16.144 17.4706L15.5551 15.8762C15.4996 15.7262 15.3773 15.604 15.2273 15.5484L13.6329 14.9595C13.1496 14.7817 13.1496 14.0984 13.6329 13.9151L15.2273 13.3262C15.3773 13.2706 15.4996 13.1484 15.5551 12.9984L16.144 11.404Z" fill="black"/>
<path d="M4.47734 8.62617C4.65512 8.14284 5.33846 8.14284 5.52179 8.62617L5.81068 9.40951C5.86623 9.55951 5.98846 9.68173 6.13846 9.73728L6.92179 10.0262C7.40512 10.2039 7.40512 10.8873 6.92179 11.0706L6.13846 11.3595C5.98846 11.4151 5.86623 11.5373 5.81068 11.6873L5.52179 12.4706C5.34401 12.954 4.66068 12.954 4.47734 12.4706L4.18845 11.6873C4.1329 11.5373 4.01068 11.4151 3.86068 11.3595L3.07734 11.0706C2.59401 10.8928 2.59401 10.2095 3.07734 10.0262L3.86068 9.73728C4.01068 9.68173 4.1329 9.55951 4.18845 9.40951L4.47734 8.62617Z" fill="black"/>
<path d="M17.222 4.44531H4.99978C4.38867 4.44531 3.88867 4.94531 3.88867 5.55642C3.88867 6.16753 4.38867 6.66753 4.99978 6.66753H9.99978V17.7786C9.99978 18.3898 10.4998 18.8898 11.1109 18.8898C11.722 18.8898 12.222 18.3898 12.222 17.7786V6.66753H17.222C17.8331 6.66753 18.3331 6.16753 18.3331 5.55642C18.3331 4.94531 17.8331 4.44531 17.222 4.44531Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,3 @@
<svg width="23" height="23" viewBox="0 0 23 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.06219 2.12276C8.42379 2.48436 8.42379 3.07062 8.06219 3.43222L5.93914 5.55527H12.963C16.5426 5.55527 19.4445 8.45712 19.4445 12.0367C19.4445 15.6164 16.5426 18.5182 12.963 18.5182H9.25931C8.74794 18.5182 8.33339 18.1037 8.33339 17.5923C8.33339 17.0809 8.74794 16.6664 9.25931 16.6664H12.963C15.5199 16.6664 17.5926 14.5936 17.5926 12.0367C17.5926 9.47987 15.5199 7.40712 12.963 7.40712H5.93914L8.06219 9.53017C8.42379 9.89176 8.42379 10.478 8.06219 10.8396C7.70059 11.2012 7.11433 11.2012 6.75273 10.8396L3.04903 7.13592C2.68743 6.77432 2.68743 6.18806 3.04903 5.82646L6.75273 2.12276C7.11433 1.76116 7.70059 1.76116 8.06219 2.12276Z" fill="#0D0D0D"/>
</svg>

After

Width:  |  Height:  |  Size: 767 B

View File

@@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.292893 0.292894C0.683418 -0.097631 1.31658 -0.0976307 1.70711 0.292894L6.65685 5.24264L11.6066 0.292894C11.9971 -0.0976317 12.6303 -0.0976307 13.0208 0.292894C13.4113 0.683418 13.4113 1.31658 13.0208 1.70711L8.07107 6.65685L13.0208 11.6066C13.4113 11.9971 13.4113 12.6303 13.0208 13.0208C12.6303 13.4113 11.9971 13.4113 11.6066 13.0208L6.65685 8.07107L1.70711 13.0208C1.31658 13.4113 0.683418 13.4113 0.292893 13.0208C-0.0976311 12.6303 -0.0976311 11.9971 0.292893 11.6066L5.24264 6.65685L0.292893 1.70711C-0.0976311 1.31658 -0.0976311 0.683418 0.292893 0.292894Z" fill="#FFF"/>
</svg>

After

Width:  |  Height:  |  Size: 694 B

View File

@@ -0,0 +1,9 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.88857 7.85248C5.37951 7.85248 5.7775 8.25046 5.7775 8.7414C5.7775 9.23234 5.37951 9.63033 4.88857 9.63033C4.39763 9.63033 3.99965 9.23234 3.99965 8.7414C3.99965 8.25046 4.39763 7.85248 4.88857 7.85248Z" fill="#0D0D0D"/>
<path d="M4.44411 5.03755C4.93505 5.03755 5.33304 5.43554 5.33304 5.92648C5.33304 6.41742 4.93505 6.8154 4.44411 6.8154C3.95317 6.8154 3.55519 6.41742 3.55519 5.92648C3.55519 5.43554 3.95317 5.03755 4.44411 5.03755Z" fill="#0D0D0D"/>
<path d="M9.33319 4.29678C9.82413 4.29678 10.2221 4.69477 10.2221 5.18571C10.2221 5.67665 9.82413 6.07463 9.33319 6.07463C8.84226 6.07463 8.44427 5.67665 8.44427 5.18571C8.44427 4.69477 8.84226 4.29678 9.33319 4.29678Z" fill="#0D0D0D"/>
<path d="M6.66642 3.2597C7.15736 3.2597 7.55535 3.65769 7.55535 4.14863C7.55535 4.63957 7.15736 5.03755 6.66642 5.03755C6.17548 5.03755 5.7775 4.63957 5.7775 4.14863C5.7775 3.65769 6.17548 3.2597 6.66642 3.2597Z" fill="#0D0D0D"/>
<path d="M7.11088 1.18555C10.3838 1.18555 13.037 3.83878 13.037 7.11171C13.037 8.31473 12.0617 9.29004 10.8587 9.29004H8.51372C8.30508 9.29006 8.13581 9.4593 8.13581 9.66794C8.13584 9.75046 8.16285 9.83084 8.21278 9.89654L8.74752 10.5997C8.91924 10.8256 9.01253 11.1018 9.01258 11.3856C9.01258 12.298 8.27271 13.0379 7.36032 13.0379H7.11088C3.83796 13.0379 1.18472 10.3846 1.18472 7.11171C1.18472 3.83878 3.83796 1.18555 7.11088 1.18555ZM7.11088 2.37078C4.49254 2.37078 2.36996 4.49337 2.36996 7.11171C2.36996 9.73005 4.49254 11.8526 7.11088 11.8526H7.36032C7.61812 11.8526 7.82735 11.6434 7.82735 11.3856C7.8273 11.361 7.81905 11.337 7.8042 11.3173L7.26946 10.6136C7.06279 10.3417 6.95061 10.0095 6.95058 9.66794C6.95058 8.80471 7.65049 8.10483 8.51372 8.1048H10.8587C11.4072 8.1048 11.8518 7.66014 11.8518 7.11171C11.8518 4.49337 9.72923 2.37078 7.11088 2.37078Z" fill="#0D0D0D"/>
<path d="M13.1974 9.45949C13.3042 9.15673 13.7159 9.15673 13.8227 9.45949L14.2989 10.793C14.3323 10.8877 14.4057 10.9617 14.497 10.9987L15.781 11.4933C16.0725 11.6042 16.0725 12.0317 15.781 12.1427L14.497 12.6372C14.4057 12.6719 14.3345 12.7482 14.2989 12.8429L13.8227 14.1764C13.7159 14.4792 13.3042 14.4792 13.1974 14.1764L12.7212 12.8429C12.6878 12.7482 12.6144 12.6742 12.5231 12.6372L11.2391 12.1427C10.9476 12.0317 10.9476 11.6042 11.2391 11.4933L12.5231 10.9987C12.6144 10.964 12.6856 10.8877 12.7212 10.793L13.1974 9.45949Z" fill="black"/>
<path d="M10.6325 13.3246C10.7037 13.1236 10.9774 13.1236 11.0508 13.3246L11.2867 13.9879C11.309 14.0503 11.3579 14.1012 11.418 14.1243L12.0567 14.3692C12.2503 14.4432 12.2503 14.7275 12.0567 14.8037L11.418 15.0487C11.3579 15.0718 11.309 15.1227 11.2867 15.1851L11.0508 15.8483C10.9796 16.0494 10.7059 16.0494 10.6325 15.8483L10.3966 15.1851C10.3743 15.1227 10.3254 15.0718 10.2653 15.0487L9.62665 14.8037C9.43305 14.7298 9.43305 14.4455 9.62665 14.3692L10.2653 14.1243C10.3254 14.1012 10.3743 14.0503 10.3966 13.9879L10.6325 13.3246Z" fill="#FF7A51"/>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,4 @@
<svg width="10" height="12" viewBox="0 0 10 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.31694 4.55806C2.07286 4.31398 1.67714 4.31398 1.43306 4.55806C1.18898 4.80214 1.18898 5.19786 1.43306 5.44194L4.55806 8.56694C4.80214 8.81102 5.19786 8.81102 5.44194 8.56694L8.56694 5.44194C8.81102 5.19786 8.81102 4.80214 8.56694 4.55806C8.32286 4.31398 7.92714 4.31398 7.68306 4.55806L5.625 6.61612L5.625 0.625C5.625 0.279822 5.34518 0 5 0C4.65482 0 4.375 0.279822 4.375 0.625L4.375 6.61612L2.31694 4.55806Z" fill="white"/>
<path d="M0.625 10C0.279822 10 0 10.2798 0 10.625C0 10.9702 0.279822 11.25 0.625 11.25H9.375C9.72018 11.25 10 10.9702 10 10.625C10 10.2798 9.72018 10 9.375 10L0.625 10Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 725 B

View File

@@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.17248 2H10.8275C11.3642 1.99999 11.8071 1.99998 12.1679 2.02946C12.5426 2.06008 12.8871 2.12579 13.2107 2.29065C13.7124 2.54631 14.1204 2.95426 14.376 3.45603C14.5409 3.77958 14.6066 4.12405 14.6372 4.49878C14.6667 4.85958 14.6667 5.30248 14.6667 5.83912V10.1609C14.6667 10.6975 14.6667 11.1404 14.6372 11.5012C14.6066 11.8759 14.5409 12.2204 14.376 12.544C14.1204 13.0457 13.7124 13.4537 13.2107 13.7094C12.8871 13.8742 12.5426 13.9399 12.1679 13.9705C11.8071 14 11.3642 14 10.8276 14H5.17246C4.63582 14 4.19292 14 3.83213 13.9705C3.4574 13.9399 3.11293 13.8742 2.78937 13.7094C2.2876 13.4537 1.87966 13.0457 1.62399 12.544C1.45913 12.2204 1.39342 11.8759 1.36281 11.5012C1.33333 11.1404 1.33334 10.6975 1.33334 10.1609V5.83913C1.33334 5.30249 1.33333 4.85958 1.36281 4.49878C1.39342 4.12405 1.45913 3.77958 1.62399 3.45603C1.87966 2.95426 2.2876 2.54631 2.78937 2.29065C3.11293 2.12579 3.4574 2.06008 3.83213 2.02946C4.19292 1.99998 4.63583 1.99999 5.17248 2ZM3.9407 3.35837C3.64843 3.38225 3.49896 3.42553 3.39469 3.47866C3.14381 3.60649 2.93983 3.81046 2.812 4.06135C2.75888 4.16561 2.71559 4.31508 2.69171 4.60736C2.6672 4.90742 2.66668 5.29561 2.66668 5.86667V8.39049L3.25246 7.8047C4.03351 7.02365 5.29984 7.02365 6.08089 7.8047L10.9428 12.6666C11.4369 12.6664 11.785 12.664 12.0593 12.6416C12.3516 12.6178 12.5011 12.5745 12.6053 12.5213C12.8562 12.3935 13.0602 12.1895 13.188 11.9387C13.2411 11.8344 13.2844 11.6849 13.3083 11.3926C13.3328 11.0926 13.3333 10.7044 13.3333 10.1333V5.86667C13.3333 5.29561 13.3328 4.90742 13.3083 4.60736C13.2844 4.31508 13.2411 4.16561 13.188 4.06135C13.0602 3.81046 12.8562 3.60649 12.6053 3.47866C12.5011 3.42553 12.3516 3.38225 12.0593 3.35837C11.7593 3.33385 11.3711 3.33333 10.8 3.33333H5.20001C4.62896 3.33333 4.24076 3.33385 3.9407 3.35837ZM9.05724 12.6667L5.13808 8.74751C4.87773 8.48716 4.45562 8.48716 4.19527 8.74751L2.6667 10.2761C2.66694 10.7702 2.6693 11.1183 2.69171 11.3926C2.71559 11.6849 2.75888 11.8344 2.812 11.9387C2.93983 12.1895 3.14381 12.3935 3.39469 12.5213C3.49896 12.5745 3.64843 12.6178 3.9407 12.6416C4.24076 12.6661 4.62896 12.6667 5.20001 12.6667H9.05724ZM10 5.66667C9.63182 5.66667 9.33334 5.96514 9.33334 6.33333C9.33334 6.70152 9.63182 7 10 7C10.3682 7 10.6667 6.70152 10.6667 6.33333C10.6667 5.96514 10.3682 5.66667 10 5.66667ZM8.00001 6.33333C8.00001 5.22876 8.89544 4.33333 10 4.33333C11.1046 4.33333 12 5.22876 12 6.33333C12 7.4379 11.1046 8.33333 10 8.33333C8.89544 8.33333 8.00001 7.4379 8.00001 6.33333Z" fill="#0D0D0D"/>
<path d="M14.3923 11.8923C14.334 11.7338 14.11 11.7338 14.0499 11.8923L13.8569 12.4149C13.8386 12.4641 13.7986 12.5042 13.7494 12.5224L13.2267 12.7154C13.0683 12.7737 13.0683 12.9977 13.2267 13.0578L13.7494 13.2509C13.7986 13.2691 13.8386 13.3091 13.8569 13.3583L14.0499 13.881C14.1082 14.0394 14.3322 14.0394 14.3923 13.881L14.5853 13.3583C14.6035 13.3091 14.6436 13.2691 14.6928 13.2509L15.2155 13.0578C15.3739 12.9995 15.3739 12.7755 15.2155 12.7154L14.6928 12.5224C14.6436 12.5042 14.6035 12.4641 14.5853 12.4149L14.3923 11.8923Z" fill="#FF7A51"/>
<path d="M12.293 8.84495C12.2055 8.60637 11.8686 8.60637 11.7812 8.84495L11.3915 9.89577C11.3642 9.97043 11.3041 10.0287 11.2294 10.0579L10.1786 10.4476C9.93999 10.535 9.93999 10.8719 10.1786 10.9593L11.2294 11.3491C11.3041 11.3764 11.3623 11.4365 11.3915 11.5112L11.7812 12.562C11.8686 12.8005 12.2055 12.8005 12.293 12.562L12.6827 11.5112C12.71 11.4365 12.7701 11.3782 12.8448 11.3491L13.8956 10.9593C14.1342 10.8719 14.1342 10.535 13.8956 10.4476L12.8448 10.0579C12.7701 10.0305 12.7118 9.97043 12.6827 9.89577L12.293 8.84495Z" fill="#FF7A51"/>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

3
src/assets/icons/sub.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg width="17" height="15" viewBox="0 0 17 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.912109 7.29883H15.5097" stroke="white" stroke-width="1.8247" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 201 B

View File

@@ -0,0 +1,4 @@
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.00017 3.33398C9.00017 2.98872 8.73756 2.70457 8.40122 2.67057L8.33351 2.66732H7.66684C7.29865 2.66732 7.00017 2.96579 7.00017 3.33398V5.11393C7.00017 5.3521 6.87309 5.57231 6.66684 5.69141C6.46062 5.81048 6.20642 5.81042 6.00017 5.69141L4.45851 4.80143C4.13988 4.61752 3.73257 4.72662 3.54835 5.04557H3.5477L3.21502 5.6224C3.03079 5.94149 3.14 6.34924 3.45851 6.5332L4.99952 7.42253C5.2057 7.54158 5.33278 7.76191 5.33286 8C5.33286 8.23806 5.20565 8.45834 4.99952 8.57747L3.45851 9.4681C3.14 9.65206 3.03079 10.0598 3.21502 10.3789L3.5477 10.9557H3.54835L3.58546 11.013C3.78319 11.2871 4.1598 11.3723 4.45851 11.1999L6.00017 10.3092C6.20639 10.1903 6.46063 10.1902 6.66684 10.3092C6.87309 10.4283 7.00017 10.6486 7.00017 10.8867V12.6673L7.00343 12.7357C7.03766 13.0718 7.32173 13.334 7.66684 13.334H8.33351C8.70165 13.3339 9.00017 13.0354 9.00017 12.6673V10.8867C9.00017 10.6485 9.1272 10.4283 9.33351 10.3092C9.53977 10.1902 9.79395 10.1902 10.0002 10.3092L11.5418 11.1999L11.6024 11.2311C11.9104 11.3695 12.2794 11.2548 12.452 10.9557L12.7853 10.3789C12.9695 10.0599 12.8602 9.65215 12.5418 9.4681L11.0002 8.57747C10.794 8.45836 10.6668 8.23811 10.6668 8C10.6669 7.76184 10.7939 7.54155 11.0002 7.42253L12.5418 6.5332L12.5991 6.49609C12.8727 6.29845 12.958 5.92141 12.7853 5.6224L12.452 5.04557C12.2679 4.72663 11.8605 4.6176 11.5418 4.80143L10.0002 5.69141C9.79396 5.81045 9.53974 5.81041 9.33351 5.69141C9.12725 5.57232 9.00017 5.3521 9.00017 5.11393V3.33398ZM10.3335 3.95898L10.8752 3.64648C11.8319 3.09437 13.0548 3.42258 13.6069 4.37891H13.6063L13.9396 4.95573H13.9403C14.4923 5.91197 14.1651 7.13567 13.2085 7.68815H13.2079L12.6668 8L13.2085 8.31315L13.2964 8.36719C14.1846 8.94217 14.475 10.1193 13.9403 11.0456H13.9396L13.6069 11.6224C13.0548 12.5787 11.8319 12.9069 10.8752 12.3548L10.3335 12.0417V12.6673C10.3335 13.7374 9.49304 14.6111 8.43637 14.6647L8.33351 14.6673H7.66684C6.56227 14.6673 5.66684 13.7719 5.66684 12.6673V12.0417L5.12517 12.3548C4.19829 12.8898 3.02137 12.5985 2.44679 11.7103L2.3934 11.6224L2.06007 11.0456C1.50804 10.0894 1.83471 8.86573 2.79119 8.31315L3.33221 8L2.79184 7.68815C1.83515 7.13565 1.50799 5.91197 2.06007 4.95573L2.3934 4.37891L2.44679 4.29102C3.02137 3.40277 4.19829 3.11148 5.12517 3.64648L5.66684 3.95898V3.33398C5.66684 2.22941 6.56227 1.33398 7.66684 1.33398H8.33351L8.43637 1.33659C9.49304 1.3902 10.3335 2.26394 10.3335 3.33398V3.95898Z" fill="#0D0D0D"/>
<path d="M14.6187 0.930453C14.7484 0.57787 15.2469 0.57787 15.3806 0.930453L15.5914 1.50188C15.6319 1.6113 15.7211 1.70046 15.8305 1.74099L16.4019 1.95173C16.7545 2.08142 16.7545 2.5799 16.4019 2.71363L15.8305 2.92437C15.7211 2.9649 15.6319 3.05406 15.5914 3.16348L15.3806 3.73491C15.2509 4.08749 14.7525 4.08749 14.6187 3.73491L14.408 3.16348C14.3675 3.05406 14.2783 2.9649 14.1689 2.92437L13.5974 2.71363C13.2449 2.58395 13.2449 2.08547 13.5974 1.95173L14.1689 1.74099C14.2783 1.70046 14.3675 1.6113 14.408 1.50188L14.6187 0.930453Z" fill="#FF7A51"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1,4 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.2494 4.16797C11.2494 3.73639 10.9211 3.3812 10.5007 3.3387L10.416 3.33464H9.58271C9.12248 3.33464 8.74938 3.70773 8.74938 4.16797V6.3929C8.74938 6.69061 8.59052 6.96588 8.33271 7.11475C8.07493 7.26358 7.75719 7.26351 7.49938 7.11475L5.5723 6.00228C5.17401 5.77239 4.66488 5.90876 4.4346 6.30745H4.43379L4.01793 7.02848C3.78765 7.42735 3.92416 7.93703 4.3223 8.16699L6.24857 9.27865C6.50629 9.42746 6.66514 9.70287 6.66523 10.0005C6.66523 10.2981 6.50622 10.5734 6.24857 10.7223L4.3223 11.8356C3.92416 12.0656 3.78764 12.5752 4.01793 12.9741L4.43379 13.6951H4.4346L4.48099 13.7668C4.72814 14.1094 5.19891 14.2158 5.5723 14.0003L7.49938 12.887C7.75714 12.7383 8.07495 12.7383 8.33271 12.887C8.59052 13.0359 8.74938 13.3112 8.74938 13.6089V15.8346L8.75345 15.9201C8.79623 16.3402 9.15132 16.668 9.58271 16.668H10.416C10.8762 16.6679 11.2494 16.2948 11.2494 15.8346V13.6089C11.2494 13.3111 11.4082 13.0359 11.666 12.887C11.9239 12.7383 12.2416 12.7382 12.4994 12.887L14.4265 14.0003L14.5021 14.0394C14.8872 14.2123 15.3484 14.0689 15.5642 13.6951L15.9808 12.9741C16.211 12.5754 16.0744 12.0657 15.6765 11.8356L13.7494 10.7223C13.4916 10.5734 13.3327 10.2981 13.3327 10.0005C13.3328 9.70279 13.4915 9.42743 13.7494 9.27865L15.6765 8.16699L15.7481 8.12061C16.0901 7.87355 16.1966 7.40226 15.9808 7.02848L15.5642 6.30745C15.334 5.90878 14.8248 5.77249 14.4265 6.00228L12.4994 7.11475C12.2416 7.26355 11.9238 7.2635 11.666 7.11475C11.4082 6.96588 11.2494 6.69062 11.2494 6.3929V4.16797ZM12.916 4.94922L13.5931 4.55859C14.789 3.86845 16.3177 4.27872 17.0078 5.47412H17.007L17.4237 6.19515H17.4245C18.1145 7.39045 17.7055 8.92007 16.5098 9.61068H16.509L15.8327 10.0005L16.5098 10.3919L16.6197 10.4595C17.7299 11.1782 18.0929 12.6496 17.4245 13.8075H17.4237L17.0078 14.5285C16.3177 15.7239 14.789 16.1342 13.5931 15.444L12.916 15.0526V15.8346C12.916 17.1722 11.8655 18.2644 10.5446 18.3314L10.416 18.3346H9.58271C8.202 18.3346 7.08271 17.2153 7.08271 15.8346V15.0526L6.40563 15.444C5.24702 16.1128 3.77587 15.7487 3.05765 14.6383L2.99092 14.5285L2.57425 13.8075C1.88421 12.6123 2.29255 11.0826 3.48815 10.3919L4.16442 10.0005L3.48896 9.61068C2.2931 8.92005 1.88414 7.39045 2.57425 6.19515L2.99092 5.47412L3.05765 5.36426C3.77587 4.25395 5.24703 3.88984 6.40563 4.55859L7.08271 4.94922V4.16797C7.08271 2.78726 8.202 1.66797 9.58271 1.66797H10.416L10.5446 1.67122C11.8655 1.73824 12.916 2.83041 12.916 4.16797V4.94922Z" fill="white"/>
<path d="M18.2722 1.16258C18.4343 0.721849 19.0574 0.721849 19.2246 1.16258L19.488 1.87686C19.5386 2.01364 19.6501 2.12509 19.7869 2.17575L20.5012 2.43917C20.9419 2.60128 20.9419 3.22438 20.5012 3.39156L19.7869 3.65498C19.6501 3.70564 19.5386 3.81709 19.488 3.95387L19.2246 4.66815C19.0625 5.10888 18.4394 5.10888 18.2722 4.66815L18.0088 3.95387C17.9581 3.81709 17.8466 3.70564 17.7099 3.65498L16.9956 3.39156C16.5549 3.22945 16.5549 2.60635 16.9956 2.43917L17.7099 2.17575C17.8466 2.12509 17.9581 2.01364 18.0088 1.87686L18.2722 1.16258Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.78 8.46094C12.72 9.08894 12.536 9.68094 12.256 10.2169C11.14 10.7129 9.63597 11.0009 7.99997 11.0009C6.36397 11.0009 4.85997 10.7089 3.74397 10.2129C3.46397 9.67694 3.27997 9.08494 3.21997 8.46094C3.82397 9.13294 5.61597 9.80094 7.99997 9.80094C10.384 9.80094 12.196 9.11294 12.78 8.46094Z" fill="#FF7A51"/>
<path d="M7.99997 2C4.69197 2 1.99997 4.692 1.99997 8C1.99997 11.308 4.69197 14 7.99997 14C11.308 14 14 11.308 14 8C14 4.692 11.308 2 7.99997 2ZM7.99997 12.8C5.35197 12.8 3.19997 10.648 3.19997 8C3.19997 7.84 3.20797 7.684 3.22397 7.528C3.22797 7.524 3.23197 7.52 3.23997 7.516C3.68797 7.04 4.61597 6.632 5.79597 6.404C6.11997 6.34 6.33197 6.024 6.26797 5.7C6.20397 5.376 5.88797 5.16 5.56397 5.228C4.88397 5.36 4.27197 5.548 3.75197 5.78C4.55597 4.248 6.15597 3.2 8.00397 3.2C9.85197 3.2 11.452 4.248 12.256 5.78C12.244 5.772 12.232 5.764 12.22 5.76C11.308 5.368 10.164 5.112 8.91197 5.032C8.57597 5.008 8.29597 5.26 8.27197 5.592C8.24797 5.924 8.49997 6.208 8.83197 6.232C9.93597 6.304 10.968 6.532 11.744 6.864C11.82 6.896 11.904 6.912 11.98 6.912C12.212 6.912 12.432 6.776 12.532 6.548C12.54 6.524 12.548 6.5 12.552 6.48C12.712 6.96 12.804 7.468 12.804 8C12.804 10.648 10.652 12.8 8.00397 12.8H7.99997Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,9 @@
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="14" height="15" fill="url(#pattern0_1471_45186)"/>
<defs>
<pattern id="pattern0_1471_45186" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_1471_45186" transform="matrix(0.0135135 0 0 0.0126126 0 -0.0171171)"/>
</pattern>
<image id="image0_1471_45186" width="74" height="82" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEoAAABSCAYAAADzVUKHAAAACXBIWXMAAAsSAAALEgHS3X78AAADL0lEQVR4nO2cTW7jMAyFqaAXnDlOu+515oqaRaCCkSWLpPjnuA/IIoEj0Z8fKVp1WmqtEK1SyjSIWmvxjGWmEg3qDBJWNLAwUFRAWJGw3EFJAPWKAOYGSgNQL09gLqAsIGF5ADMFZQ0IyxqWCShPQL2sgKmCigTUSxuYGqhMkLC0gG2DygoISwOWGNQVAPXaASYCdUVIWBJgLFBXB9SLA4wE6t0AYVFhnYJ6Z0C9VsCmoO4ECWsG7ADqroCwRrAe+M0vpKdGHF5ARe8iZo4hTY2a1oYscazaA49AlytOhhii+yhyH2MUA3X+D85g2sFG1iPu3AUAKveLWsDYwTrPi+f7AbUziETTeb7+Psf9/ndceazmHKif65B67YDVoCbp2CApSyNbHqMP2xcoEGqtxaTWDKBx5+HEtjrfKSg8ADUoynHTY5XdpAWoibTqhabjYA6Nhzq4MR6KOUU7wbDdRCzq1qv2MvVmE1Hrl2R8zriadej0uyBwVK8tIJTaNHAVRxqlQOQoi0BOJSz0Ow46jAUKjsJiuYsLgOEs7Yun4iiRJC4xakgpUnOUqZN6BTjLt5hrO4IITAPWNigSJOuUIQDbhbUF6hRSRD05AZYTVGDRBYApsB1Y+qteNCQj6YPa7KKtFJp6AInq1OIC5QbVZAXsSu0BQFAf5dx0qt7ruQALut9TvykGMExHx1Q7jAkGoLDUir1xsV7JHFTTVnNq2HFT5bbNMj0hYd+luSlHket+lOjEDP5iLJH7xt3wJJN281hxO5wUJXETQBCoK7oqt6MSKS+oRGnXVKNetVY4vD7/jD9/PkIZFqtbwzlS1BN3EuVNvU7RaRcKinry0ZAAEjhqBSEDJACAR4afVMxgZIFUay3hjsquZqQHfvOrV2EuH/2HWeweqeXv9dpBd3bY7NynNepusFYGOX18+g7pSDUEadV713TknBPpgfx+4Ks7THLRRX3UVd21kxksR/WTAlzDXRoXdrszz16/tGITO6pXNodpXzz1e71od1k5XM1RWBHusr5AprsHXvXLYw4TR/V6h38H4LofpXViESuti6OwdtwVuVCE7XByXRG9mv4HkdrDmcF2TuQAAAAASUVORK5CYII="/>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,14 @@
<svg width="14" height="15" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<mask id="mask0_1471_47329" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="14" height="15">
<rect width="14" height="15" fill="url(#pattern0_1471_47329)"/>
</mask>
<g mask="url(#mask0_1471_47329)">
<rect x="-1" y="-1" width="16" height="16" fill="white"/>
</g>
<defs>
<pattern id="pattern0_1471_47329" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_1471_47329" transform="matrix(0.0135135 0 0 0.0126126 0 -0.0171171)"/>
</pattern>
<image id="image0_1471_47329" width="74" height="82" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEoAAABSCAYAAADzVUKHAAAACXBIWXMAAAsSAAALEgHS3X78AAADL0lEQVR4nO2cTW7jMAyFqaAXnDlOu+515oqaRaCCkSWLpPjnuA/IIoEj0Z8fKVp1WmqtEK1SyjSIWmvxjGWmEg3qDBJWNLAwUFRAWJGw3EFJAPWKAOYGSgNQL09gLqAsIGF5ADMFZQ0IyxqWCShPQL2sgKmCigTUSxuYGqhMkLC0gG2DygoISwOWGNQVAPXaASYCdUVIWBJgLFBXB9SLA4wE6t0AYVFhnYJ6Z0C9VsCmoO4ECWsG7ADqroCwRrAe+M0vpKdGHF5ARe8iZo4hTY2a1oYscazaA49AlytOhhii+yhyH2MUA3X+D85g2sFG1iPu3AUAKveLWsDYwTrPi+f7AbUziETTeb7+Psf9/ndceazmHKif65B67YDVoCbp2CApSyNbHqMP2xcoEGqtxaTWDKBx5+HEtjrfKSg8ADUoynHTY5XdpAWoibTqhabjYA6Nhzq4MR6KOUU7wbDdRCzq1qv2MvVmE1Hrl2R8zriadej0uyBwVK8tIJTaNHAVRxqlQOQoi0BOJSz0Ow46jAUKjsJiuYsLgOEs7Yun4iiRJC4xakgpUnOUqZN6BTjLt5hrO4IITAPWNigSJOuUIQDbhbUF6hRSRD05AZYTVGDRBYApsB1Y+qteNCQj6YPa7KKtFJp6AInq1OIC5QbVZAXsSu0BQFAf5dx0qt7ruQALut9TvykGMExHx1Q7jAkGoLDUir1xsV7JHFTTVnNq2HFT5bbNMj0hYd+luSlHket+lOjEDP5iLJH7xt3wJJN281hxO5wUJXETQBCoK7oqt6MSKS+oRGnXVKNetVY4vD7/jD9/PkIZFqtbwzlS1BN3EuVNvU7RaRcKinry0ZAAEjhqBSEDJACAR4afVMxgZIFUay3hjsquZqQHfvOrV2EuH/2HWeweqeXv9dpBd3bY7NynNepusFYGOX18+g7pSDUEadV713TknBPpgfx+4Ks7THLRRX3UVd21kxksR/WTAlzDXRoXdrszz16/tGITO6pXNodpXzz1e71od1k5XM1RWBHusr5AprsHXvXLYw4TR/V6h38H4LofpXViESuti6OwdtwVuVCE7XByXRG9mv4HkdrDmcF2TuQAAAAASUVORK5CYII="/>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.1959 2.6173C12.4159 1.8333 11.1479 1.8333 10.3679 2.6173L3.01592 9.9693C2.23192 10.7493 2.23192 12.0173 3.01592 12.7973C3.79592 13.5813 5.06392 13.5813 5.84392 12.7973L13.1959 5.4453C13.9799 4.6653 13.9799 3.3973 13.1959 2.6173ZM12.5319 4.5213L11.1159 5.9333C11.0399 6.0133 10.9119 6.0133 10.8359 5.9333L10.2679 5.3693C10.1919 5.2893 10.1919 5.1613 10.2679 5.0853L11.6839 3.6693C11.7599 3.5933 11.8879 3.5933 11.9679 3.6693L12.5319 4.2373C12.6079 4.3133 12.6079 4.4413 12.5319 4.5213Z" fill="black"/>
<path d="M7.59998 3.6C8.04181 3.6 8.39998 3.24183 8.39998 2.8C8.39998 2.35817 8.04181 2 7.59998 2C7.15815 2 6.79998 2.35817 6.79998 2.8C6.79998 3.24183 7.15815 3.6 7.59998 3.6Z" fill="#FF7A51"/>
<path d="M11.624 9.412C11.752 9.064 12.244 9.064 12.376 9.412L12.8 10.56C12.84 10.668 12.928 10.756 13.036 10.796L14.184 11.22C14.532 11.348 14.532 11.84 14.184 11.972L13.036 12.396C12.928 12.436 12.84 12.524 12.8 12.632L12.376 13.78C12.248 14.128 11.756 14.128 11.624 13.78L11.2 12.632C11.16 12.524 11.072 12.436 10.964 12.396L9.81598 11.972C9.46798 11.844 9.46798 11.352 9.81598 11.22L10.964 10.796C11.072 10.756 11.16 10.668 11.2 10.56L11.624 9.412Z" fill="#FF7A51"/>
<path d="M3.62398 3.012C3.75198 2.664 4.24398 2.664 4.37598 3.012L4.58398 3.576C4.62398 3.684 4.71198 3.772 4.81998 3.812L5.38398 4.02C5.73198 4.148 5.73198 4.64 5.38398 4.772L4.81998 4.98C4.71198 5.02 4.62398 5.108 4.58398 5.216L4.37598 5.78C4.24798 6.128 3.75598 6.128 3.62398 5.78L3.41598 5.216C3.37598 5.108 3.28798 5.02 3.17998 4.98L2.61598 4.772C2.26798 4.644 2.26798 4.152 2.61598 4.02L3.17998 3.812C3.28798 3.772 3.37598 3.684 3.41598 3.576L3.62398 3.012Z" fill="#FF7A51"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,96 @@
<template>
<div class="canvas-test">
<div class="canvas-main" ref="canvasMain" @mousedown="onMouseDown" @wheel="onMouseWheel">
<div
class="canvas-content"
:style="{
top: `${data.y}px`,
left: `${data.x}px`,
transform: `scale(${data.scale})`
}"
>
<card type="cards-select" />
<card type="to-real-style" />
<card type="surface-edit" />
<card type="scene-composition" />
<card type="color-palette" />
<card type="to-3d-model" />
<card type="to-3view" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import card from './FlowCanvas/components/cards/index.vue'
import { computed, ref, markRaw, onMounted, reactive, nextTick } from 'vue'
const data = reactive({
x: 100,
y: 200,
scale: 1
})
const onMouseDown = (e: MouseEvent) => {
if (e.button !== 1) return
const ox = data.x
const oy = data.y
const X = e.clientX
const Y = e.clientY
const onMouseMove = (e: MouseEvent) => {
const dx = e.clientX - X
const dy = e.clientY - Y
data.x = ox + dx
data.y = oy + dy
}
const onMouseUp = (e: MouseEvent) => {
document.removeEventListener('mousemove', onMouseMove)
document.removeEventListener('mouseup', onMouseUp)
}
document.addEventListener('mousemove', onMouseMove)
document.addEventListener('mouseup', onMouseUp)
}
const onMouseWheel = (e: WheelEvent) => {
var delta = e.deltaY
var scale = data.scale - delta / 1000
if (scale < 0.2) scale = 0.2
if (scale > 10) scale = 10
data.scale = scale
}
</script>
<style lang="less" scoped>
.canvas-test {
// overflow-y: auto;
// display: flex;
// flex-wrap: wrap;
// align-content: flex-start;
// align-items: flex-start;
// padding: 2rem;
// gap: 2rem;
width: 100%;
height: 100%;
background-color: #fcf8f1;
position: relative;
overflow: hidden;
> .canvas-main {
width: 100%;
height: 100%;
position: relative;
> .canvas-content {
position: absolute;
width: auto;
height: auto;
display: flex;
align-items: flex-start;
gap: 5rem;
transform-origin: top left;
}
}
> .vue-flow {
width: 100%;
height: 100%;
}
}
</style>

View File

@@ -0,0 +1,65 @@
<template>
<!-- 高级工具选择 -->
<div class="cards-select">
<div v-for="v in list" :key="v.type">
<span class="icon">
<svg-icon :name="v.type + '-2'" size="15" size-unit="px" />
</span>
<span class="title">{{ v.title }}</span>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const list = ref([
{
type: 'to-real-style',
title: 'To Real Style'
},
{
type: 'surface-edit',
title: 'Surface Edit'
},
{
type: 'scene-composition',
title: 'Scene Composition'
},
{
type: 'color-palette',
title: 'Color Palette'
},
{
type: 'to-3view',
title: 'To 3-View'
},
{
type: 'to-3d-model',
title: 'To 3D Model'
}
])
defineExpose({})
</script>
<style lang="less" scoped>
.cards-select {
> div {
display: flex;
align-items: center;
padding: 6px 5px;
border-radius: 5px;
cursor: pointer;
&:hover {
background-color: rgb(225, 225, 225);
}
> .icon {
margin-right: 10px;
}
> .title {
font-size: 14px;
color: #000;
}
}
}
</style>

View File

@@ -8,8 +8,12 @@
v-for="(v, i) in data.colors"
:key="i"
:style="{ background: v }"
></div>
<div class="add" @click="addColor">
>
<span class="del" @click="delColor(i)">
<svg-icon name="close-white" size="7" size-unit="px" />
</span>
</div>
<div class="add" @click="addColor" v-if="data.colors.length < maxColor">
<svg-icon name="add" size="12" size-unit="px" color="#fff" />
<input type="color" ref="colorInput" @change="changeColor" />
</div>
@@ -20,11 +24,16 @@
<script setup lang="ts">
import { reactive, onMounted, ref } from 'vue'
const data = reactive({
colors: ['#FF4747', '#F96060', '#FFB1B1', '#FA7B7B', '#FF9090']
colors: []
})
const maxColor = 5
const delColor = (i: number) => {
data.colors.splice(i, 1)
}
const colorInput = ref<HTMLInputElement>()
// 添加颜色
const addColor = () => {
if (data.colors.length >= maxColor) return
colorInput.value?.click()
}
const changeColor = (e: Event) => {
@@ -45,6 +54,25 @@
> div {
width: 35px;
height: 35px;
position: relative;
&:hover {
> .del {
display: flex;
}
}
> .del {
display: none;
position: absolute;
width: 15px;
height: 15px;
top: -5px;
right: -5px;
background-color: #000;
border-radius: 50%;
align-items: center;
justify-content: center;
cursor: pointer;
}
}
> .add {
border: 1px solid rgba(0, 0, 0, 0.1);

View File

@@ -1,16 +1,22 @@
<template>
<div class="card">
<div class="header">
<svg-icon :name="currentComponent?.type" color="#fff" size="16" size-unit="px" />
<svg-icon
v-if="!currentComponent?.hideIcon"
:name="currentComponent?.type"
color="#fff"
size="16"
size-unit="px"
/>
<span>{{ currentComponent?.title }}</span>
<div class="add" @click="emit('add')">
<!-- <div class="add" @click="emit('add')" @mousedown.stop>
<svg-icon name="add" size="14" size-unit="px" />
</div>
</div> -->
</div>
<div class="body">
<div class="body" @mousedown.stop>
<component :is="currentComponent?.component" ref="componentRef" />
</div>
<div class="footer">
<div class="footer" @mousedown.stop v-if="!currentComponent?.hideFooter">
<button @click="onGenerateClick">
<svg-icon name="xingxing" size="16" size-unit="px" />
<span>Generate</span>
@@ -21,20 +27,35 @@
<script setup lang="ts">
import { computed, ref, markRaw, onMounted } from 'vue'
import CardsSelect from './cards-select.vue'
import ToRealStyle from './to-real-style.vue'
import SurfaceEdit from './surface-edit.vue'
import SceneComposition from './scene-composition.vue'
import ColorPalette from './color-palette.vue'
import ToVideo from './to-video.vue'
import To3View from './to-3view.vue'
import To3DModel from './to-3d-model.vue'
import ToVideo from './to-video.vue'
import AddPrint from './add-print.vue'
import ToCAD from './to-cad.vue'
import EditMaterial from './edit-material.vue'
const components = [
{
type: 'cards-select',
title: 'Advanced Tools',
component: CardsSelect,
hideFooter: true,
hideIcon: true
},
{
type: 'to-real-style',
title: 'To Real Style',
component: ToRealStyle
},
{
type: 'surface-edit',
title: 'Surface Edit',
component: SurfaceEdit
},
{
type: 'scene-composition',
title: 'Scene Composition',
@@ -46,43 +67,42 @@
component: ColorPalette
},
{
type: 'to-video',
title: 'To Video',
component: ToVideo
type: 'to-3view',
title: 'To 3-View',
component: To3View
},
{
type: 'to-3d-model',
title: 'To 3D Model',
component: To3DModel
},
{
type: 'to-cad',
title: 'To CAD',
component: ToCAD
},
{
type: 'add-print',
title: 'Add Print',
component: AddPrint
},
{
type: 'edit-material',
title: 'Edit Material',
component: EditMaterial
}
// {
// type: 'to-video',
// title: 'To Video',
// component: ToVideo
// },
// {
// type: 'to-cad',
// title: 'To CAD',
// component: ToCAD
// },
// {
// type: 'add-print',
// title: 'Add Print',
// component: AddPrint
// }
]
const emit = defineEmits(['add', 'generate'])
const props = defineProps({
type: {
type: String as () =>
| 'cards-select'
| 'to-real-style'
| 'surface-edit'
| 'scene-composition'
| 'color-palette'
| 'to-video'
| 'to-3d-model'
| 'to-cad'
| 'add-print'
| 'edit-material',
| 'to-3view',
default: 'to-real-style'
}
})
@@ -107,7 +127,6 @@
box-shadow: 0 15px 21px 0 rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
> .header {
border-radius: var(--border-radius) var(--border-radius) 0 0;
height: 50px;
@@ -142,9 +161,11 @@
font-size: 25px;
box-shadow: 0 8px 20px 0 #71809633;
cursor: pointer;
z-index: 20;
}
}
> .body {
cursor: initial;
padding: 16px 13px;
&:deep(> *) {
width: 100%;
@@ -162,10 +183,11 @@
}
}
> .footer {
margin-bottom: 16px;
cursor: initial;
display: flex;
flex-direction: row-reverse;
padding: 0 13px;
padding-bottom: 16px;
> button {
display: flex;
align-items: center;

View File

@@ -1,7 +1,7 @@
<template>
<!-- 编辑素材 -->
<div class="edit-material">
<p class="label">Material</p>
<div class="surface-edit">
<p class="label">Image</p>
<upload-file v-model="data.file" />
<p class="label">Prompt</p>
<my-textarea v-model="data.prompt" />
@@ -21,6 +21,6 @@
</script>
<style lang="less" scoped>
.edit-material {
.surface-edit {
}
</style>

View File

@@ -2,18 +2,16 @@
<!-- 转3D模型 -->
<div class="to-3d-model">
<p class="label">Image</p>
<upload-file v-model="data.file" />
<p class="label">Prompt</p>
<my-textarea v-model="data.prompt" />
<div class="image">
<img src="https://s3-alpha-sig.figma.com/img/ea2f/590e/9638f62a2fc91e31f33db0022db1642c?Expires=1773014400&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=M0B8oJJOk~dGG0aZAqOIocAp7T0LFdJ9FYmCrEZVTCRzYxM6SJRNtYMTX-rTO3Z~s14QINh~o-S41XiZnBv-0zcKjuWot~VVaNHfd0~1LesfNe2KwvCinT~72btFut1pheLnKE-wWCX5ewtonxU77bnw386YPMTqv7DBZzksf2udsJA7NmOYD6~TUG3Q2dWSt~zPH~lkaidscPqpCnCbqzljCEi4RiHY4U3A45l5XypcX2umqn1UaYUFCTqV9471J4qdB6Dg2pcKocdp-7-3s1De6Q~2SmBOrSgDQ~KEADCB2lhKfhxgWmy0lwMvhTd4l90ygVZDWZRABgjHNrGUvg__" alt="">
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, onMounted } from 'vue'
import myTextarea from '../tools/my-textarea.vue'
import uploadFile from '../tools/upload-file.vue'
const data = reactive({
prompt: '',
file: null
})
@@ -22,5 +20,14 @@
<style lang="less" scoped>
.to-3d-model {
> .image {
padding: 18px;
border-radius: 10px;
background-color: #f0f0f0;
>img{
width: 100%;
height: auto;
}
}
}
</style>

View File

@@ -0,0 +1,30 @@
<template>
<!-- 转3-View -->
<div class="to-3view">
<p class="label">3D Model</p>
<div class="image">
<img src="https://s3-alpha-sig.figma.com/img/ea2f/590e/9638f62a2fc91e31f33db0022db1642c?Expires=1773014400&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=M0B8oJJOk~dGG0aZAqOIocAp7T0LFdJ9FYmCrEZVTCRzYxM6SJRNtYMTX-rTO3Z~s14QINh~o-S41XiZnBv-0zcKjuWot~VVaNHfd0~1LesfNe2KwvCinT~72btFut1pheLnKE-wWCX5ewtonxU77bnw386YPMTqv7DBZzksf2udsJA7NmOYD6~TUG3Q2dWSt~zPH~lkaidscPqpCnCbqzljCEi4RiHY4U3A45l5XypcX2umqn1UaYUFCTqV9471J4qdB6Dg2pcKocdp-7-3s1De6Q~2SmBOrSgDQ~KEADCB2lhKfhxgWmy0lwMvhTd4l90ygVZDWZRABgjHNrGUvg__" alt="">
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, onMounted } from 'vue'
const data = reactive({})
defineExpose({ data })
</script>
<style lang="less" scoped>
.to-3view {
> .image {
padding: 18px;
border-radius: 10px;
background-color: #f0f0f0;
>img{
width: 100%;
height: auto;
}
}
}
</style>

View File

@@ -13,6 +13,8 @@
{{ v.label }}
</div>
</div>
<p class="label">Mode</p>
<my-select v-model="data.mode" :list="modeList" />
<p class="label">Size</p>
<pixel-ratio-selection v-model="data.pixelRatio" />
</div>
@@ -21,6 +23,7 @@
<script setup lang="ts">
import { computed, ref, reactive, onMounted } from 'vue'
import myTextarea from '../tools/my-textarea.vue'
import mySelect from '../tools/my-select.vue'
import pixelRatioSelection from '../tools/pixel-ratio-selection.vue'
const shortcutList = ref([
{
@@ -44,10 +47,14 @@
value: 'Wood Materials with...'
}
])
const modeList = ref([
{ value: 'Fast', label: 'Fast' },
{ value: 'Normal', label: 'Normal' }
])
const data = reactive({
prompt: '',
pixelRatio: '1:1',
file: null
mode: 'Normal'
})
defineExpose({ data })

View File

@@ -0,0 +1,80 @@
<template>
<div class="header-tools">
<span class="icon"><svg-icon name="c-mouse" size="16" /></span>
<span class="icon"><svg-icon name="c-hand" size="18" /></span>
<span class="icon"><svg-icon name="c-t" size="18" /></span>
<span class="line"></span>
<span class="icon"><svg-icon name="c-undo" size="18" /></span>
<span class="icon"><svg-icon name="c-redo" size="18" /></span>
<button class="export">
<span class="icon"><svg-icon name="export" size="11" /></span>
<span class="text">Export</span>
</button>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
const props = defineProps({
zoom: { default: 1, type: Number },
step: { default: 0.1, type: Number }
})
const emit = defineEmits(['add', 'sub'])
</script>
<style lang="less" scoped>
.header-tools {
position: absolute;
top: 10.6rem;
left: 50%;
transform: translateX(-50%);
height: 5rem;
padding: 0.7rem 2.5rem;
border: 0.2rem solid #ebebeb;
background: #ffffff;
border-radius: 1.1rem;
box-shadow: 0 1.66rem 2.33rem 0 rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
justify-content: center;
user-select: none;
gap: 1.4rem;
> .line {
width: 0;
height: 100%;
border-left: 0.2rem solid #d9d9d9;
border-radius: 0.2rem;
margin: 0 0.6rem;
}
> .icon {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
width: 3rem;
height: 3rem;
--svg-icon-color: #000;
border-radius: 0.4rem;
&:hover {
background-color: #dfdfdf;
}
}
> .export {
width: 10rem;
height: 3rem;
border-radius: 0.4rem;
border: none;
background-color: #ff7a51;
color: #fff;
font-size: 1.1rem;
display: flex;
align-items: center;
justify-content: center;
gap: 0.8rem;
&:active {
opacity: 0.8;
}
}
}
</style>

View File

@@ -0,0 +1,36 @@
<script lang="ts" setup>
import { Handle, Position } from '@vue-flow/core'
import { ref } from 'vue'
const props = defineProps({
type: {
type: String as () => 'InputNode' | 'SecondaryNode',
default: 'InputNode'
}
})
</script>
<template>
<div class="node start">
<template v-if="type === 'InputNode'">
<Handle type="source" id="Right" :position="Position.Right" />
</template>
<template v-else-if="type === 'SecondaryNode'">
<Handle type="target" id="Left" :position="Position.Left" />
<Handle type="source" id="Right" :position="Position.Right" />
</template>
<div class="item">
<slot></slot>
</div>
</div>
</template>
<style lang="less" scoped>
.node {
.vue-flow__handle {
width: 5px;
height: 5px;
top: 50px;
z-index: 10;
}
}
</style>

View File

@@ -0,0 +1,52 @@
<template>
<div class="my-select">
<el-select :model-value="modelValue" @change="onChange" v-bind="attrs">
<el-option v-for="v in list" :key="v.value" :label="v.label" :value="v.value" />
</el-select>
</div>
</template>
<script setup lang="ts">
import { ref, useAttrs, watch } from 'vue'
const props = defineProps({
modelValue: { required: true },
list: { default: () => [], type: [Array, Object] }
})
const attrs = useAttrs()
const emit = defineEmits(['update:modelValue', 'change'])
const onChange = (value) => {
emit('update:modelValue', value)
emit('change', value)
}
</script>
<style scoped lang="less">
.my-select {
&:deep(.el-select) {
--el-select-input-font-size: 12px;
.el-select__wrapper {
font-size: 12px;
min-height: 0;
height: 28px;
padding: 0 8px;
}
.el-select__selected-item,
.el-select__input-wrapper,
.el-select__placeholder {
line-height: normal;
}
.el-select__input {
height: 24px;
}
}
}
.el-popper {
.el-select-dropdown {
li {
padding-left: 8px;
height: 30px;
line-height: 30px;
font-size: 12px;
}
}
}
</style>

View File

@@ -9,7 +9,7 @@
<div class="control" v-else>
<div class="icon"><svg-icon name="upload" size="17" size-unit="px" /></div>
<div class="txt">{{ tip }}</div>
<button @click="onSelectFile">Select File</button>
<div class="btn" @click="onSelectFile">Select File</div>
</div>
</div>
</template>
@@ -59,8 +59,11 @@
font-size: 8px;
color: #7c7c7c;
}
> button {
box-shadow: 0px 0.75px 0px 0px #00000005;
> .btn {
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0px 0.75px 0px 0px rgba(0, 0, 0, 0.02);
min-width: 39px;
height: 13px;
border-radius: 2.3px;

View File

@@ -0,0 +1,116 @@
<template>
<div class="flow-canvas">
<VueFlow
ref="vueFlow"
:nodes="nodes"
:edges="edges"
:min-zoom="0.1"
:max-zoom="10"
:nodes-draggable="true"
@nodes-initialized="layoutGraph('LR')"
@node-drag-stop="(e) => eventManager.handleNodeDragStop(e)"
@viewport-change="(e) => eventManager.handleViewportChange(e)"
>
<template #node-InputNode="nodeProps">
<node type="InputNode">
<component :is="nodeProps.data.component" v-bind="nodeProps.data" />
</node>
</template>
<template #node-SecondaryNode="nodeProps">
<node type="SecondaryNode">
<component :is="nodeProps.data.component" v-bind="nodeProps.data" />
</node>
</template>
</VueFlow>
</div>
<header-tools />
<zoom
:zoom="stateManager.zoom.value"
:step="0.1"
@add="(e) => flowManager.setZoom(e)"
@sub="(e) => flowManager.setZoom(e)"
/>
</template>
<script setup lang="ts">
import { VueFlow, useVueFlow } from '@vue-flow/core'
import { useLayout } from '@/utils/treeDiagram'
// 组件
import headerTools from './components/header-tools.vue'
import zoom from '../components/zoom.vue'
import node from './components/node.vue'
import card from './components/cards/index.vue'
import { computed, ref, markRaw, onMounted, reactive, nextTick } from 'vue'
// 管理器
import { StateManager } from './manager/StateManager'
import { EventManager } from './manager/EventManager'
import { FlowManager } from './manager/FlowManager'
const vueFlow = ref<any>()
const stateManager = new StateManager({ vueFlow })
const nodes = computed(() => stateManager.nodes.value)
const edges = computed(() => stateManager.edges.value)
const eventManager = new EventManager({
stateManager,
vueFlow
})
const flowManager = new FlowManager({
stateManager,
vueFlow
})
const { fitView } = useVueFlow()
const { layout } = useLayout()
const index = ref(0)
async function layoutGraph(direction) {
if (index.value > 0) return
index.value++
setTimeout(() => {
stateManager.nodes.value = layout(
stateManager.nodes.value,
stateManager.edges.value,
direction
)
nextTick(() => {
fitView()
})
}, 0)
}
onMounted(() => {
window.vueFlow = vueFlow
window.nodes = nodes
window.addaaaaa = () => {
const lastNode = vueFlow.value.getNode(nodes.value[nodes.value.length - 1].id)
const width = lastNode.dimensions.width
const x = lastNode.position.x
const y = lastNode.position.y
nodes.value.push({
id: nodes.value.length + 1 + '',
type: 'SecondaryNode',
class: 'custom-node',
data: { component: card, type_: 'to-3d-model' },
position: {
x: width + x + 50,
y: y
}
})
}
})
</script>
<style lang="less">
@import '@vue-flow/core/dist/style.css';
@import '@vue-flow/core/dist/theme-default.css';
</style>
<style lang="less" scoped>
.flow-canvas {
width: 100%;
height: 100%;
> .vue-flow {
width: 100%;
height: 100%;
}
}
</style>

View File

@@ -1,151 +1,25 @@
<template>
<fullscreen-dialog v-model="dialogVisible">
<div class="flow-canvas">
<VueFlow
ref="vueFlow"
:nodes="nodes"
:edges="edges"
:nodes-draggable="true"
@nodes-initialized="layoutGraph('LR')"
@node-drag-stop="handleNodeDragStop"
>
<template #node-InputNode="nodeProps">
<inputNode v-bind="nodeProps">
<template v-slot:content>
<component
:is="nodeProps.data.component"
:type="nodeProps.data.type_"
/>
</template>
</inputNode>
</template>
<template #node-SecondaryNode="nodeProps">
<secondaryNode v-bind="nodeProps">
<template v-slot:content>
<component
:is="nodeProps.data.component"
:type="nodeProps.data.type_"
/>
</template>
</secondaryNode>
</template>
</VueFlow>
</div>
<fullscreen-dialog v-model="dialogVisible" hide-destroy>
<flow-canvas />
</fullscreen-dialog>
</template>
<script setup lang="ts">
import { VueFlow, useVueFlow } from '@vue-flow/core'
import { useLayout } from '@/utils/treeDiagram'
import secondaryNode from '../components/node/secondaryNode.vue'
import inputNode from '../components/node/InputNode.vue'
import FullscreenDialog from '../components/fullscreen-dialog.vue'
import card from './components/cards/index.vue'
import { computed, ref, markRaw, onMounted, reactive, nextTick } from 'vue'
import { useGlobalStore } from '@/stores'
const globalStore = useGlobalStore()
import flowCanvas from './flow-canvas.vue'
import { ref } from 'vue'
const dialogVisible = ref(false)
const position = { x: 0, y: 0 }
const nodes = ref<any[]>([
{
id: '1',
type: 'InputNode',
class: 'custom-node start',
position: { x: 0, y: 0 },
data: { component: card, type_: 'to-real-style' }
},
{
id: '2',
type: 'SecondaryNode',
class: 'custom-node',
position: { x: 0, y: 0 },
data: { component: card, type_: 'scene-composition' }
},
{
id: '3',
type: 'SecondaryNode',
class: 'custom-node',
position: { x: 0, y: 0 },
data: { component: card, type_: 'to-3d-model' }
}
])
const edges = computed(() => {
const arr = []
nodes.value.forEach((node, index) => {
if (index < nodes.value.length - 1) {
const id = node.id
const target = nodes.value[index + 1].id
arr.push({
id: `el-${id}-${target}`,
source: id,
target: target,
type: 'smoothstep'
})
}
})
return arr
})
const vueFlow = ref<any>()
onMounted(() => {
window.vueFlow = vueFlow
window.nodes = nodes
window.test = () => {
return vueFlow.value
}
window.addaaaaa = () => {
const lastNode = vueFlow.value.getNode(nodes.value[nodes.value.length - 1].id)
const width = lastNode.dimensions.width
const x = lastNode.position.x
const y = lastNode.position.y
nodes.value.push({
id: '4',
type: 'SecondaryNode',
class: 'custom-node',
data: { id: '主 1', component: card, type_: 'to-3d-model' },
position: {
x: width + x + 50,
y: y
}
})
}
})
const handleNodeDragStop = (e: any) => {
const { node } = e
const { id, position } = node
nodes.value.forEach((item) => {
if (item.id === id) {
item.position.x = position.x
item.position.y = position.y
}
})
const open = () => {
console.log('open')
dialogVisible.value = true
}
const { fitView } = useVueFlow()
const { layout } = useLayout()
const index = ref(0)
async function layoutGraph(direction) {
if (index.value > 0) return
index.value++
setTimeout(() => {
nodes.value = layout(nodes.value, edges.value, direction)
console.log(nodes.value)
nextTick(() => {
fitView()
})
}, 0)
const close = () => {
dialogVisible.value = false
}
defineExpose({
open,
close
})
</script>
<style lang="less">
@import '@vue-flow/core/dist/style.css';
@import '@vue-flow/core/dist/theme-default.css';
</style>
<style lang="less" scoped>
.flow-canvas {
width: 100%;
height: 100%;
> .vue-flow {
width: 100%;
height: 100%;
}
}
</style>

View File

@@ -0,0 +1,24 @@
export class EventManager {
stateManager: any
vueFlow: any
zoom: any
constructor(options) {
this.stateManager = options.stateManager;
this.vueFlow = options.vueFlow
this.zoom = this.stateManager.zoom
}
handleViewportChange(e: any) {
const { zoom } = e
this.zoom.value = zoom
}
handleNodeDragStop(e: any) {
const { node } = e
const { id, position } = node
this.stateManager.nodes.value.forEach((item) => {
if (item.id === id) {
item.position.x = position.x
item.position.y = position.y
}
})
}
}

View File

@@ -0,0 +1,22 @@
export class FlowManager {
stateManager: any
vueFlow: any
constructor(options) {
this.stateManager = options.stateManager;
this.vueFlow = options.vueFlow
}
setZoom(zoom: number) {
this.stateManager.zoom.value = zoom
this.vueFlow.value.zoomTo(zoom)
}
handleNodeDragStop(e: any) {
const { node } = e
const { id, position } = node
this.stateManager.nodes.value.forEach((item) => {
if (item.id === id) {
item.position.x = position.x
item.position.y = position.y
}
})
}
}

View File

@@ -0,0 +1,90 @@
import { ref, computed } from "vue";
import card from '../components/cards/index.vue'
export class StateManager {
vueFlow: any
nodes: any
edges: any
zoom: any
constructor(options) {
this.vueFlow = options.vueFlow
this.nodes = ref<any[]>([
{
id: '1',
type: 'InputNode',
class: 'custom-node start',
position: { x: 0, y: 0 },
data: { component: card, type: 'to-real-style' }
},
{
id: '2',
type: 'SecondaryNode',
class: 'custom-node',
position: { x: 0, y: 0 },
data: { component: card, type: 'scene-composition' }
},
{
id: '3',
type: 'SecondaryNode',
class: 'custom-node',
position: { x: 0, y: 0 },
data: { component: card, type: 'color-palette' }
},
{
id: '4',
type: 'SecondaryNode',
class: 'custom-node',
position: { x: 0, y: 0 },
data: { component: card, type: 'to-video' }
},
{
id: '5',
type: 'SecondaryNode',
class: 'custom-node',
position: { x: 0, y: 0 },
data: { component: card, type: 'to-3d-model' }
},
{
id: '6',
type: 'SecondaryNode',
class: 'custom-node',
position: { x: 0, y: 0 },
data: { component: card, type: 'to-cad' }
},
{
id: '7',
type: 'SecondaryNode',
class: 'custom-node',
position: { x: 0, y: 0 },
data: { component: card, type: 'add-print' }
},
{
id: '8',
type: 'SecondaryNode',
class: 'custom-node',
position: { x: 0, y: 0 },
data: { component: card, type: 'edit-material' }
}
]);
this.edges = computed(() => {
const arr = []
this.nodes.value.forEach((node, index) => {
if (index < this.nodes.value.length - 1) {
const id = node.id
const target = this.nodes.value[index + 1].id
arr.push({
id: `el-${id}-${target}`,
source: id,
target: target,
type: 'smoothstep'
})
}
})
return arr
})
this.zoom = ref(1)
}
}

View File

@@ -11,6 +11,9 @@
>
<slot></slot>
<my-info />
<div class="close-btn" @click="close">
<svg-icon name="back-white" color="#fff" size="18" />
</div>
</div>
</template>
@@ -25,7 +28,6 @@
const emit = defineEmits(['update:modelValue', 'closed'])
const show = ref(props.modelValue)
const show_ = ref(props.modelValue)
console.log(props.modelValue)
const timeout = ref(null)
watch(
() => props.modelValue,
@@ -44,6 +46,9 @@
}
}
)
const close = () => {
emit('update:modelValue', false)
}
</script>
<style lang="less" scoped>
@@ -55,7 +60,6 @@
left: 0;
overflow: hidden;
z-index: 1000;
background-color: #FFFCF4;
transition: opacity var(--transition-time);
opacity: 0;
&.show {
@@ -66,5 +70,33 @@
top: 3rem;
right: 3rem;
}
> .close-btn {
cursor: pointer;
position: absolute;
top: 3.4rem;
left: 3rem;
width: 5.1rem;
height: 5.1rem;
border-radius: 50%;
background-color: #ff7a51;
display: flex;
align-items: center;
justify-content: center;
}
}
.fullscreen-dialog {
--size: 0.25rem;
--width: 4rem;
--color: #bfbfbf;
background-color: #fffcf4;
background-image: repeating-radial-gradient(
circle at 50% 50%,
var(--color) 0,
var(--color) var(--size),
transparent var(--size),
transparent var(--width)
);
background-position: center center;
background-size: var(--width) var(--width); /* 设置平铺的大小 */
}
</style>

View File

@@ -1,27 +0,0 @@
<script lang="ts" setup>
import { Handle, Position } from '@vue-flow/core'
import { ref } from 'vue'
const props = defineProps<{
data: {
type: Object
default: () => {
id: ''
}
}
}>()
</script>
<template>
<div class="node start">
<Handle type="source" style="top: 40px" id="Right" :position="Position.Right" />
<div class="item">
<slot name="content"></slot>
</div>
</div>
</template>
<style lang="less" scoped>
.node {
cursor: initial;
}
</style>

View File

@@ -1,31 +0,0 @@
<script lang="ts" setup>
import { Handle, Position } from '@vue-flow/core'
import { ref } from 'vue'
const props = defineProps<{
data: {
type: Object
default: () => {
id: ''
}
}
}>()
</script>
<!-- source输入target输出 -->
<template>
<div class="node">
<Handle type="target" style="top: 40px" id="Left" :position="Position.Left" />
<Handle type="source" style="top: 40px" id="Right" :position="Position.Right" />
<!-- <Handle type="source" id="Right" :position="Position.Right" />
<Handle type="target" id="Left" :position="Position.Left" /> -->
<!-- <div>{{ props.data.id }}</div> -->
<div class="item">
<slot name="content"></slot>
</div>
</div>
</template>
<style lang="less" scoped>
.node {
cursor: initial;
}
</style>

View File

@@ -0,0 +1,57 @@
<template>
<div class="zoom">
<span class="icon" @click="zoomIn"><svg-icon name="add" size="14" /></span>
<span class="value">{{ Math.round(zoom * 100) }}%</span>
<span class="icon" @click="zoomOut"><svg-icon name="sub" size="14" /></span>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
const props = defineProps({
zoom: { default: 1, type: Number },
step: { default: 0.1, type: Number }
})
const emit = defineEmits(['add', 'sub'])
const zoomIn = () => {
emit('add', Number(props.zoom) + props.step)
}
const zoomOut = () => {
emit('sub', Number(props.zoom) - props.step)
}
</script>
<style lang="less" scoped>
.zoom {
position: absolute;
bottom: 4rem;
right: 3rem;
padding: 0.7rem 1rem;
min-width: 12.8rem;
height: 4.2rem;
border-radius: 0.8rem;
border: 0.1rem solid #ffcf90;
background: #ffffff;
box-shadow: 0 1.5rem 2.1rem 0 rgba(0, 0, 0, 0.05);
display: flex;
align-items: center;
justify-content: center;
color: #000;
user-select: none;
> .icon {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
width: 2.8rem;
height: 2.8rem;
--svg-icon-color: #0d0d0d;
}
> .value {
flex: 1;
text-align: center;
font-family: Medium;
font-size: 1.6rem;
}
}
</style>

View File

@@ -29,7 +29,7 @@
watch(codeStr, (newVal) => {
emit('update:modelValue', newVal)
})
const resetCode = (size) => {
const resetCode = (size = props.length) => {
code.value = []
for (let i = 0; i < size; i++) {
code.value.push('')
@@ -83,6 +83,9 @@
onMounted(() => {
focusLast()
})
defineExpose({
resetCode
})
</script>
<style lang="less" scoped>

View File

@@ -34,6 +34,7 @@ export default {
googleLogin: 'Sign in with Google',
wechatLogin: 'Sign in with Wechat',
indexTip: 'A multi-agent canvas for rapid, trend driven design iteration.',
sendCodeError: 'Send code error',
},
Nuic: {
hiName: 'Hi, {name}. This is Fiphant.',

View File

@@ -34,7 +34,8 @@ export default {
orContinueWith: '或者使用',
googleLogin: '使用 Google 登录',
wechatLogin: '使用微信登录',
indexTip: '一个多智能体画布,用于快速、趋势驱动的设计迭代。'
indexTip: '一个多智能体画布,用于快速、趋势驱动的设计迭代。',
sendCodeError: '发送验证码失败',
},
Nuic: {
hiName: '你好,{name}。这是 Fiphant。',

View File

@@ -7,69 +7,74 @@ import { createRouter, createWebHistory } from 'vue-router'
* 3. 路由的name默认是文件名,如果文件名与name不一致,通过defineOptions({ name: 'componentName' })来设置
*/
const router = createRouter({
history: createWebHistory('/'),
// history: createWebHistory(import.meta.env.VITE_APP_URL),
routes: [
{
path: '/',
redirect: '/index'
},
{
path: '/index',
name: 'index',
component: () => import('../views/login/index.vue')
},
{
path: '/login',
name: 'login',
component: () => import('../views/login/login.vue')
},
{
path: '/register',
name: 'register',
component: () => import('../views/login/register.vue')
},
{
path: '/nuic',
name: 'nuic',
component: () => import('../views/nuic/index.vue')
},
{
path: '/home',
name: 'home',
component: () => import('../views/home/index.vue'),
children: [
{
path: 'test/:id',
name: 'test',
component: () => import('../views/home/test.vue'),
meta: { topNavStyle: '2' }
},
{
path: '/home/versionTree',
name: 'versionTree',
component: () => import('../views/home/VersionTree.vue'),
meta: { topNavStyle: '2' }
},
{
path: 'mainInput',
name: 'mainInput',
component: () => import('../views/home/mainInput.vue')
},
{
path: 'agent',
name: 'agent',
component: () => import('../views/home/agent/index.vue')
}
]
},
history: createWebHistory('/'),
// history: createWebHistory(import.meta.env.VITE_APP_URL),
routes: [
{
path: '/',
redirect: '/index'
},
{
path: '/index',
name: 'index',
component: () => import('../views/login/index.vue')
},
{
path: '/login',
name: 'login',
component: () => import('../views/login/login.vue')
},
{
path: '/register',
name: 'register',
component: () => import('../views/login/register.vue')
},
{
path: '/nuic',
name: 'nuic',
component: () => import('../views/nuic/index.vue')
},
{
path: '/home',
name: 'home',
component: () => import('../views/home/index.vue'),
children: [
{
path: 'test/:id',
name: 'test',
component: () => import('../views/home/test.vue'),
meta: { topNavStyle: '2' }
},
{
path: '/home/versionTree',
name: 'versionTree',
component: () => import('../views/home/VersionTree.vue'),
meta: { topNavStyle: '2' }
},
{
path: 'mainInput',
name: 'mainInput',
component: () => import('../views/home/mainInput.vue')
},
{
path: 'agent',
name: 'agent',
component: () => import('../views/home/agent/index.vue')
}
]
},
{
path: '/canvastest',
name: 'canvastest',
component: () => import('../components/Canvas/CanvasTest.vue')
},
{
path: '/:pathMatch(.*)',
name: '404',
component: () => import('../views/404.vue')
}
]
path: '/:pathMatch(.*)',
name: '404',
component: () => import('../views/404.vue')
}
]
})
export default router

View File

@@ -16,11 +16,11 @@
</div>
</div>
<setting />
<flow-canvas />
<flow-canvas ref="flowCanvasRef" />
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { computed, onMounted, onUnmounted, ref } from 'vue'
import LeftNav from './left-nav.vue'
import TopNav from './top-nav.vue'
import setting from './setting/index.vue'
@@ -28,6 +28,16 @@
const globalStore = useGlobalStore()
const loading = computed(() => globalStore.state.loading)
import FlowCanvas from '@/components/Canvas/FlowCanvas/index.vue'
import myEvent from '@/utils/myEvent'
const flowCanvasRef = ref(null)
const openFlowCanvas = () => {
flowCanvasRef.value.open()
}
myEvent.add('openFlowCanvas', openFlowCanvas)
onUnmounted(() => {
myEvent.remove('openFlowCanvas', openFlowCanvas)
})
</script>
<style lang="less" scoped>

View File

@@ -15,10 +15,6 @@
<span class="icon"><svg-icon name="home" size="24" /></span>
<span class="title" v-show="!isCollapse">{{ $t('Home.home') }}</span>
</div> -->
<div class="menu-item" @click="onCanvas">
<!-- <span class="icon"><svg-icon name="home" size="24" /></span> -->
<span class="title">画布</span>
</div>
<div class="menu-item" @click="onHistory" :class="{ active: showHistory }">
<span class="icon"><svg-icon name="history" size="24" /></span>
<span class="title" v-show="!isCollapse">{{ $t('Home.history') }}</span>
@@ -108,9 +104,6 @@
router.push({ name: 'mainInput' })
}
const onHome = () => {}
const onCanvas = () => {
router.push({ name: 'canvas' })
}
const onHistory = () => {
if (isCollapse.value) {
globalStore.setHomeLeftNavCollapse(false)

View File

@@ -1,14 +1,22 @@
<template>
<div class="test">
<p>Conversation Item - {{ id }}</p>
<button @click="openCanvas">打开画布</button>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import myEvent from '@/utils/myEvent'
import { computed, onMounted } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const id = computed(() => route.params.id)
const openCanvas = () => {
myEvent.emit('openFlowCanvas')
}
onMounted(() => {
openCanvas();
})
</script>
<style lang="less" scoped>
@@ -19,6 +27,9 @@
display: flex;
align-items: center;
justify-content: center;
font-size: 10rem;
flex-direction: column;
> p {
font-size: 10rem;
}
}
</style>

View File

@@ -50,6 +50,8 @@
</template>
<visible-code
v-show="isVisible"
type="LOGIN"
:password="formData.password"
ref="visibleCodeRef"
:email="formData.email"
@submit="onVerifyCode"
@@ -61,6 +63,7 @@
</template>
<script setup lang="ts">
import md5 from 'md5'
import { Login } from '@/api/login'
import { computed, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
@@ -106,7 +109,7 @@
// console.log(code)
Login({
email: formData.email,
password: formData.password,
password: md5(formData.password),
verificationCode: code
})
.then((res) => {

View File

@@ -54,6 +54,7 @@
</template>
<visible-code
v-show="isVisible"
type="REGISTER"
ref="visibleCodeRef"
:email="formData.email"
@submit="onVerifyCode"
@@ -65,6 +66,7 @@
</template>
<script setup lang="ts">
import md5 from 'md5'
import { Register } from '@/api/login'
import { computed, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
@@ -113,7 +115,7 @@
Register({
username: formData.name,
email: formData.email,
password: formData.password,
password: md5(formData.password),
verificationCode: code
})
.then((res) => {

View File

@@ -2,7 +2,7 @@
<div class="visible-code">
<div class="title">{{ $t('Login.verifyEmail') }}</div>
<div class="tip" v-html="$t('Login.verifyCodeHasSent', { email: props.email })"></div>
<input-code @submit="onVerify" v-model="code" />
<input-code @submit="onVerify" v-model="code" ref="inputCodeRef" />
<el-button class="verify" @click="onVerify">{{ $t('Login.verify') }}</el-button>
<p class="time" v-if="time > 0">{{ $t('Login.resendCodeIn', { time: timeStr }) }}</p>
<p class="time" v-if="time === 0">
@@ -12,15 +12,21 @@
</template>
<script setup lang="ts">
import md5 from 'md5'
import { ElMessage } from 'element-plus'
import { SendVerificationCode } from '@/api/login'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import { CountDown } from '@/utils/tools'
import InputCode from '@/components/input-code.vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
const router = useRouter()
const emit = defineEmits(['submit'])
const props = defineProps({
email: ''
email: { type: String, required: true },
type: { default: 'LOGIN', type: String as () => 'LOGIN' | 'REGISTER' },
password: { type: String, default: '' }
})
const code = ref('')
const time = ref(60)
@@ -47,15 +53,31 @@
onMounted(() => {
// onSendCode()
})
const inputCodeRef = ref(null)
const resetCode = () => {
inputCodeRef.value?.resetCode?.()
}
const onSendCode = async () => {
resetCode()
const email = props.email
if (!email) {
console.warn('请输入邮箱')
return Promise.reject('请输入邮箱')
}
await SendVerificationCode({ email })
const data = {
email,
type: props.type
}
if (props.type === 'LOGIN') {
data['password'] = md5(props.password)
}
const res = await SendVerificationCode(data)
if (!res) {
ElMessage.error(t('Login.sendCodeError'))
return Promise.reject('发送验证码失败')
}
setTime()
return Promise.resolve()
return Promise.resolve(res)
}
const onResend = () => {
if (time.value > 0) return