Update App version to 0.1.1
Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
16
ui/src/assets/second/ConnectStatsPressed.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg viewBox="0 0 68 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68.000000" height="24.000000" fill="none">
|
||||
<defs>
|
||||
<clipPath id="clipPath_105">
|
||||
<rect width="16.000002" height="16.000002" x="10.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect id="类型=Connect Stats, 状态=按下" width="68.000000" height="24.000000" x="0.000000" y="0.000000" fill="rgb(230,230,230)" />
|
||||
<g id="信号 1" clip-path="url(#clipPath_105)" customFrame="url(#clipPath_105)">
|
||||
<rect id="信号 1" width="16.000002" height="16.000002" x="10.000000" y="4.000000" />
|
||||
<path id="矢量 12" d="M23.3334 6L23.3334 18" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 13" d="M19.6666 9.33337L19.6666 18" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 14" d="M16.3334 12.6666L16.3334 18" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 15" d="M12.6666 16L12.6666 18" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
</g>
|
||||
<path id="" d="M30.75 14.7949C31.0273 15.0371 31.3984 15.2363 31.8633 15.3926C32.3281 15.5488 32.7695 15.627 33.1875 15.627C34.4609 15.627 35.0977 15.1738 35.0977 14.2676C35.0977 14.0137 35.0293 13.7852 34.8926 13.582C34.7559 13.3789 34.5684 13.1992 34.3301 13.043C34.0918 12.8867 33.6445 12.6465 32.9883 12.3223C32.0781 11.8691 31.4785 11.4482 31.1895 11.0596C30.9004 10.6709 30.7559 10.2266 30.7559 9.72656C30.7559 8.97266 31.0586 8.375 31.6641 7.93359C32.2695 7.49219 33.0332 7.27148 33.9551 7.27148C34.8574 7.27148 35.5195 7.38086 35.9414 7.59961L35.9414 8.87695C35.3945 8.49805 34.7031 8.30859 33.8672 8.30859C33.3125 8.30859 32.8604 8.4248 32.5107 8.65723C32.1611 8.88965 31.9863 9.21289 31.9863 9.62695C31.9863 9.99414 32.1074 10.293 32.3496 10.5234C32.5918 10.7539 33.1172 11.0684 33.9258 11.4668C34.8164 11.8926 35.4395 12.3184 35.7949 12.7441C36.1504 13.1699 36.3281 13.6484 36.3281 14.1797C36.3281 14.9766 36.0391 15.5879 35.4609 16.0137C34.8828 16.4395 34.0801 16.6523 33.0527 16.6523C32.6934 16.6523 32.2744 16.6025 31.7959 16.5029C31.3174 16.4033 30.9688 16.2793 30.75 16.1309L30.75 14.7949ZM40.6465 16.4355C40.3965 16.5723 40.0586 16.6406 39.6328 16.6406C38.4727 16.6406 37.8926 15.998 37.8926 14.7129L37.8926 10.9688L36.7793 10.9688L36.7793 10.0195L37.8926 10.0195L37.8926 8.46094L39.0352 8.09766L39.0352 10.0195L40.6465 10.0195L40.6465 10.9688L39.0352 10.9688L39.0352 14.5078C39.0352 14.9336 39.1074 15.2383 39.252 15.4219C39.3965 15.6055 39.6367 15.6973 39.9727 15.6973C40.2305 15.6973 40.4551 15.625 40.6465 15.4805L40.6465 16.4355ZM42.1582 10.4707C42.8027 10.0684 43.5469 9.86719 44.3906 9.86719C45.9531 9.86719 46.7344 10.6875 46.7344 12.3281L46.7344 16.5L45.5977 16.5L45.5977 15.498L45.5684 15.498C45.1191 16.2676 44.457 16.6523 43.582 16.6523C42.9531 16.6523 42.4531 16.4824 42.082 16.1426C41.7109 15.8027 41.5254 15.3438 41.5254 14.7656C41.5254 13.5547 42.2422 12.8496 43.6758 12.6504L45.5977 12.3809C45.5977 11.3223 45.1602 10.793 44.2852 10.793C43.5078 10.793 42.7988 11.0547 42.1582 11.5781L42.1582 10.4707ZM44.0801 13.4531C43.5488 13.5234 43.1826 13.6562 42.9814 13.8516C42.7803 14.0469 42.6797 14.3203 42.6797 14.6719C42.6797 14.9805 42.7891 15.2324 43.0078 15.4277C43.2266 15.623 43.5156 15.7207 43.875 15.7207C44.375 15.7207 44.7871 15.5449 45.1113 15.1934C45.4355 14.8418 45.5977 14.4004 45.5977 13.8691L45.5977 13.248L44.0801 13.4531ZM51.75 16.4355C51.5 16.5723 51.1621 16.6406 50.7363 16.6406C49.5762 16.6406 48.9961 15.998 48.9961 14.7129L48.9961 10.9688L47.8828 10.9688L47.8828 10.0195L48.9961 10.0195L48.9961 8.46094L50.1387 8.09766L50.1387 10.0195L51.75 10.0195L51.75 10.9688L50.1387 10.9688L50.1387 14.5078C50.1387 14.9336 50.2109 15.2383 50.3555 15.4219C50.5 15.6055 50.7402 15.6973 51.0762 15.6973C51.334 15.6973 51.5586 15.625 51.75 15.4805L51.75 16.4355ZM52.7461 15.0996C53.3242 15.5176 53.9473 15.7266 54.6152 15.7266C55.5098 15.7266 55.957 15.4336 55.957 14.8477C55.957 14.5977 55.8594 14.3916 55.6641 14.2295C55.4688 14.0674 55.0723 13.875 54.4746 13.6523C53.7559 13.3633 53.2891 13.0771 53.0742 12.7939C52.8594 12.5107 52.752 12.168 52.752 11.7656C52.752 11.1914 52.9951 10.7314 53.4814 10.3857C53.9678 10.04 54.5664 9.86719 55.2773 9.86719C55.8281 9.86719 56.3398 9.96289 56.8125 10.1543L56.8125 11.2617C56.3281 10.9492 55.7793 10.793 55.166 10.793C54.7988 10.793 54.5 10.873 54.2695 11.0332C54.0391 11.1934 53.9238 11.4043 53.9238 11.666C53.9238 11.9238 54.0068 12.125 54.1729 12.2695C54.3389 12.4141 54.707 12.5996 55.2773 12.8262C56 13.0957 56.4883 13.375 56.7422 13.6641C56.9961 13.9531 57.123 14.3105 57.123 14.7363C57.123 15.3301 56.8799 15.7979 56.3936 16.1396C55.9072 16.4814 55.2773 16.6523 54.5039 16.6523C53.832 16.6523 53.2461 16.5254 52.7461 16.2715L52.7461 15.0996Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
16
ui/src/assets/second/ConnectStatsSelected.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg viewBox="0 0 68 24.0001" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68.000000" height="24.000122" fill="none">
|
||||
<defs>
|
||||
<clipPath id="clipPath_88">
|
||||
<rect width="16.000002" height="16.000002" x="10.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect id="类型=Connect Stats, 状态=选中" width="68.000000" height="24.000000" x="0.000000" y="0.000000" />
|
||||
<g id="信号 1" clip-path="url(#clipPath_88)" customFrame="url(#clipPath_88)">
|
||||
<rect id="信号 1" width="16.000002" height="16.000002" x="10.000000" y="4.000000" />
|
||||
<path id="矢量 12" d="M23.3334 6L23.3334 18" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 13" d="M19.6666 9.33337L19.6666 18" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 14" d="M16.3334 12.6666L16.3334 18" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 15" d="M12.6666 16.0001L12.6666 18.0001" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
</g>
|
||||
<path id="" d="M30.75 14.795C31.0273 15.0372 31.3984 15.2365 31.8633 15.3927C32.3281 15.549 32.7695 15.6271 33.1875 15.6271C34.4609 15.6271 35.0977 15.174 35.0977 14.2677C35.0977 14.0138 35.0293 13.7853 34.8926 13.5822C34.7559 13.379 34.5684 13.1993 34.3301 13.0431C34.0918 12.8868 33.6445 12.6466 32.9883 12.3224C32.0781 11.8693 31.4785 11.4484 31.1895 11.0597C30.9004 10.671 30.7559 10.2267 30.7559 9.72668C30.7559 8.97278 31.0586 8.37512 31.6641 7.93372C32.2695 7.49231 33.0332 7.27161 33.9551 7.27161C34.8574 7.27161 35.5195 7.38098 35.9414 7.59973L35.9414 8.87708C35.3945 8.49817 34.7031 8.30872 33.8672 8.30872C33.3125 8.30872 32.8604 8.42493 32.5107 8.65735C32.1611 8.88977 31.9863 9.21301 31.9863 9.62708C31.9863 9.99426 32.1074 10.2931 32.3496 10.5236C32.5918 10.754 33.1172 11.0685 33.9258 11.4669C34.8164 11.8927 35.4395 12.3185 35.7949 12.7443C36.1504 13.17 36.3281 13.6486 36.3281 14.1798C36.3281 14.9767 36.0391 15.588 35.4609 16.0138C34.8828 16.4396 34.0801 16.6525 33.0527 16.6525C32.6934 16.6525 32.2744 16.6027 31.7959 16.5031C31.3174 16.4034 30.9688 16.2794 30.75 16.131L30.75 14.795ZM40.6465 16.4357C40.3965 16.5724 40.0586 16.6407 39.6328 16.6407C38.4727 16.6407 37.8926 15.9982 37.8926 14.713L37.8926 10.9689L36.7793 10.9689L36.7793 10.0197L37.8926 10.0197L37.8926 8.46106L39.0352 8.09778L39.0352 10.0197L40.6465 10.0197L40.6465 10.9689L39.0352 10.9689L39.0352 14.5079C39.0352 14.9337 39.1074 15.2384 39.252 15.422C39.3965 15.6056 39.6367 15.6974 39.9727 15.6974C40.2305 15.6974 40.4551 15.6251 40.6465 15.4806L40.6465 16.4357ZM42.1582 10.4708C42.8027 10.0685 43.5469 9.86731 44.3906 9.86731C45.9531 9.86731 46.7344 10.6876 46.7344 12.3282L46.7344 16.5001L45.5977 16.5001L45.5977 15.4982L45.5684 15.4982C45.1191 16.2677 44.457 16.6525 43.582 16.6525C42.9531 16.6525 42.4531 16.4825 42.082 16.1427C41.7109 15.8029 41.5254 15.3439 41.5254 14.7657C41.5254 13.5548 42.2422 12.8497 43.6758 12.6505L45.5977 12.381C45.5977 11.3224 45.1602 10.7931 44.2852 10.7931C43.5078 10.7931 42.7988 11.0548 42.1582 11.5782L42.1582 10.4708ZM44.0801 13.4532C43.5488 13.5236 43.1826 13.6564 42.9814 13.8517C42.7803 14.047 42.6797 14.3204 42.6797 14.672C42.6797 14.9806 42.7891 15.2325 43.0078 15.4279C43.2266 15.6232 43.5156 15.7208 43.875 15.7208C44.375 15.7208 44.7871 15.545 45.1113 15.1935C45.4355 14.8419 45.5977 14.4005 45.5977 13.8693L45.5977 13.2482L44.0801 13.4532ZM51.75 16.4357C51.5 16.5724 51.1621 16.6407 50.7363 16.6407C49.5762 16.6407 48.9961 15.9982 48.9961 14.713L48.9961 10.9689L47.8828 10.9689L47.8828 10.0197L48.9961 10.0197L48.9961 8.46106L50.1387 8.09778L50.1387 10.0197L51.75 10.0197L51.75 10.9689L50.1387 10.9689L50.1387 14.5079C50.1387 14.9337 50.2109 15.2384 50.3555 15.422C50.5 15.6056 50.7402 15.6974 51.0762 15.6974C51.334 15.6974 51.5586 15.6251 51.75 15.4806L51.75 16.4357ZM52.7461 15.0997C53.3242 15.5177 53.9473 15.7267 54.6152 15.7267C55.5098 15.7267 55.957 15.4337 55.957 14.8478C55.957 14.5978 55.8594 14.3917 55.6641 14.2296C55.4688 14.0675 55.0723 13.8751 54.4746 13.6525C53.7559 13.3634 53.2891 13.0773 53.0742 12.7941C52.8594 12.5109 52.752 12.1681 52.752 11.7657C52.752 11.1915 52.9951 10.7316 53.4814 10.3859C53.9678 10.0402 54.5664 9.86731 55.2773 9.86731C55.8281 9.86731 56.3398 9.96301 56.8125 10.1544L56.8125 11.2618C56.3281 10.9493 55.7793 10.7931 55.166 10.7931C54.7988 10.7931 54.5 10.8732 54.2695 11.0333C54.0391 11.1935 53.9238 11.4044 53.9238 11.6661C53.9238 11.924 54.0068 12.1251 54.1729 12.2697C54.3389 12.4142 54.707 12.5997 55.2773 12.8263C56 13.0958 56.4883 13.3751 56.7422 13.6642C56.9961 13.9532 57.123 14.3107 57.123 14.7365C57.123 15.3302 56.8799 15.798 56.3936 16.1398C55.9072 16.4816 55.2773 16.6525 54.5039 16.6525C53.832 16.6525 53.2461 16.5255 52.7461 16.2716L52.7461 15.0997Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
17
ui/src/assets/second/DisabledPressed.svg
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
9
ui/src/assets/second/IMG.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="36.000000" height="36.000000" fill="none">
|
||||
<rect id="IMG" width="36.000000" height="36.000000" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 109" d="M29.8086 8.44189L29.8086 32.6294C29.8086 33.5631 29.056 34.3169 28.1211 34.3169L7.87109 34.3169C6.93734 34.3169 6.18359 33.5631 6.18359 32.6294L6.18359 3.37939C6.18359 2.44452 6.93734 1.69189 7.87109 1.69189L23.0586 1.69189L29.8086 8.44189Z" fill="rgb(242,242,242)" fill-rule="nonzero" />
|
||||
<path id="矢量 109" d="M29.8086 32.6294L29.8086 8.44189L23.0586 1.69189L7.87109 1.69189C6.93734 1.69189 6.18359 2.44452 6.18359 3.37939L6.18359 32.6294C6.18359 33.5631 6.93734 34.3169 7.87109 34.3169L28.1211 34.3169C29.056 34.3169 29.8086 33.5631 29.8086 32.6294ZM22.6444 2.69189L7.87109 2.69189C7.7723 2.69189 7.68118 2.70978 7.59771 2.74554C7.51985 2.77891 7.44866 2.82784 7.38413 2.89234C7.31975 2.95669 7.27086 3.02771 7.23749 3.10539C7.20156 3.189 7.18359 3.28034 7.18359 3.37939L7.18359 32.6294C7.18359 32.7273 7.20124 32.8178 7.23653 32.9007C7.26996 32.9793 7.31921 33.0511 7.38429 33.1162C7.44938 33.1813 7.52121 33.2305 7.59977 33.264C7.6827 33.2993 7.77315 33.3169 7.87109 33.3169L28.1211 33.3169C28.2201 33.3169 28.3115 33.2989 28.3951 33.263C28.4728 33.2296 28.5438 33.1807 28.6082 33.1164C28.6726 33.0518 28.7216 32.9806 28.7549 32.9028C28.7907 32.8193 28.8086 32.7282 28.8086 32.6294L28.8086 8.85611L22.6444 2.69189Z" fill="rgb(229,229,229)" fill-rule="evenodd" />
|
||||
<path id="矢量 110" d="M5.625 25.0044L5.625 32.6294C5.625 33.8759 6.6285 34.8794 7.875 34.8794L28.125 34.8794C29.3715 34.8794 30.375 33.8759 30.375 32.6294L30.375 25.0044L5.625 25.0044Z" fill="rgb(153,153,153)" fill-rule="nonzero" />
|
||||
<path id="" d="M11.5625 26.9492L11.5625 33L10.7812 33L10.7812 26.9492L11.5625 26.9492ZM18.6055 33L18.6055 28.9922C18.6055 28.6615 18.625 28.2643 18.6641 27.8008L18.6445 27.8008C18.5768 28.0924 18.5169 28.2956 18.4648 28.4102L16.4688 33L16.0352 33L14.043 28.4453C13.9961 28.3411 13.9362 28.1263 13.8633 27.8008L13.8398 27.8008C13.8659 28.082 13.8789 28.4909 13.8789 29.0273L13.8789 33L13.1328 33L13.1328 26.9492L14.1914 26.9492L15.9766 31.0977C16.112 31.4154 16.2018 31.6628 16.2461 31.8398L16.2734 31.8398C16.4089 31.4674 16.5039 31.2148 16.5586 31.082L18.375 26.9492L19.3828 26.9492L19.3828 33L18.6055 33ZM25.5234 32.5859C24.9193 32.9297 24.237 33.1016 23.4766 33.1016C22.6016 33.1016 21.8965 32.8249 21.3613 32.2715C20.8262 31.7181 20.5586 30.9792 20.5586 30.0547C20.5586 29.1198 20.8542 28.3516 21.4453 27.75C22.0365 27.1484 22.7943 26.8477 23.7188 26.8477C24.3724 26.8477 24.9258 26.9518 25.3789 27.1602L25.3789 28.0039C24.8945 27.6992 24.3177 27.5469 23.6484 27.5469C22.9896 27.5469 22.4466 27.7721 22.0195 28.2227C21.5924 28.6732 21.3789 29.2669 21.3789 30.0039C21.3789 30.7617 21.5755 31.3516 21.9688 31.7734C22.362 32.1953 22.8932 32.4062 23.5625 32.4062C24.0234 32.4062 24.4154 32.3177 24.7383 32.1406L24.7383 30.5039L23.4258 30.5039L23.4258 29.8125L25.5234 29.8125L25.5234 32.5859Z" fill="rgb(255,255,255)" fill-rule="nonzero" />
|
||||
<path id="矢量 111" d="M29.8086 8.44189L24.7461 8.44189C23.8123 8.44189 23.0586 7.68814 23.0586 6.75439L23.0586 1.69189" fill="rgb(153,153,153)" fill-rule="nonzero" />
|
||||
<path id="矢量 112" d="M17.9961 9.125C14.2746 9.125 11.2461 12.1535 11.2461 15.875C11.2461 19.5965 14.2746 22.625 17.9961 22.625C21.7176 22.625 24.7461 19.5965 24.7461 15.875C24.7461 12.1535 21.7176 9.125 17.9961 9.125ZM17.9961 10.25C21.109 10.25 23.6211 12.7621 23.6211 15.875C23.6211 18.9879 21.109 21.5 17.9961 21.5C14.8832 21.5 12.3711 18.9879 12.3711 15.875C12.3711 12.7621 14.8832 10.25 17.9961 10.25ZM17.9961 13.625C16.7597 13.625 15.7461 14.6386 15.7461 15.875C15.7461 17.1114 16.7597 18.125 17.9961 18.125C19.2325 18.125 20.2461 17.1114 20.2461 15.875C20.2461 14.6386 19.2325 13.625 17.9961 13.625ZM17.9961 14.75C18.6238 14.75 19.1211 15.2473 19.1211 15.875C19.1211 16.5028 18.6238 17 17.9961 17C17.3683 17 16.8711 16.5028 16.8711 15.875C16.8711 15.2473 17.3683 14.75 17.9961 14.75Z" fill="rgb(153,153,153)" fill-rule="nonzero" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
80
ui/src/assets/second/KeyboardPressed.svg
Normal file
@@ -0,0 +1,80 @@
|
||||
<svg viewBox="0 0 221 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="221.000000" height="24.000000" fill="none" customFrame="#000000">
|
||||
<defs>
|
||||
<clipPath id="clipPath_108">
|
||||
<rect width="16.000002" height="16.000002" x="10.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_109">
|
||||
<rect width="57.000000" height="16.000000" x="30.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_110">
|
||||
<rect width="16.000002" height="16.000002" x="34.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_111">
|
||||
<rect width="56.000000" height="16.000000" x="91.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_112">
|
||||
<rect width="16.000002" height="16.000002" x="95.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_113">
|
||||
<rect width="60.000000" height="16.000000" x="151.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_114">
|
||||
<rect width="16.000002" height="16.000002" x="155.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect id="类型=键盘, 状态=按下" width="221.000000" height="24.000000" x="0.000000" y="0.000000" fill="rgb(230,230,230)" />
|
||||
<g id="键盘 1" clip-path="url(#clipPath_108)" customFrame="url(#clipPath_108)">
|
||||
<rect id="键盘 1" width="16.000002" height="16.000002" x="10.000000" y="4.000000" />
|
||||
<rect id="矩形 7" width="13.333334" height="8.000001" x="11.333313" y="10.000000" rx="0.666667" fill="rgb(51,51,51)" />
|
||||
<rect id="矩形 7" width="13.333334" height="8.000001" x="11.333313" y="10.000000" rx="0.666667" stroke="rgb(51,51,51)" stroke-linejoin="round" stroke-width="1" />
|
||||
<circle id="椭圆 11" cx="14.666667" cy="12.000041" r="0.666666746" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 11" cx="14.666667" cy="12.000041" r="0.166666746" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 12" cx="15.333354" cy="14.000041" r="0.666666985" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 12" cx="15.333354" cy="14.000041" r="0.166666985" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 13" cx="13.333354" cy="14.000041" r="0.666666746" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 13" cx="13.333354" cy="14.000041" r="0.166666746" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 14" cx="16.666666" cy="12.000041" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 14" cx="16.666666" cy="12.000041" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 15" cx="17.333353" cy="14.000041" r="0.666666746" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 15" cx="17.333353" cy="14.000041" r="0.166666746" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 16" cx="18.666666" cy="12.000041" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 16" cx="18.666666" cy="12.000041" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 17" cx="19.333353" cy="14.000041" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 17" cx="19.333353" cy="14.000041" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 18" cx="20.6666679" cy="12.000041" r="0.666666985" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 18" cx="20.6666679" cy="12.000041" r="0.166666985" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 19" cx="21.3333549" cy="14.000041" r="0.666666985" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 19" cx="21.3333549" cy="14.000041" r="0.166666985" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 20" cx="22.666666" cy="12.000041" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 20" cx="22.666666" cy="12.000041" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<path id="矢量 95" d="M15.6667 16L20.3334 16" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 96" d="M18 10L18 8.375C18 8.1909 18.1492 8.04167 18.3333 8.04167L20 8.04167C20.1841 8.04167 20.3333 7.89243 20.3333 7.70833L20.3333 6" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</g>
|
||||
<g id="状态栏按键" clip-path="url(#clipPath_109)" customFrame="url(#clipPath_109)">
|
||||
<rect id="状态栏按键" width="57.000000" height="16.000000" x="30.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" fill-opacity="0" />
|
||||
<g id="点 1" clip-path="url(#clipPath_110)" customFrame="url(#clipPath_110)">
|
||||
<rect id="点 1" width="16.000002" height="16.000002" x="34.000000" y="4.000000" />
|
||||
<path id="矢量 11" d="M42 15C43.6569 15 45 13.6569 45 12C45 10.3431 43.6569 9 42 9C40.3431 9 39 10.3431 39 12C39 13.6569 40.3431 15 42 15Z" fill="rgb(0,205,27)" fill-rule="nonzero" />
|
||||
<path id="矢量 11" d="M45 12C45 10.3431 43.6569 9 42 9C40.3431 9 39 10.3431 39 12C39 13.6569 40.3431 15 42 15C43.6569 15 45 13.6569 45 12Z" fill-rule="nonzero" stroke="rgb(0,205,27)" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M62.584 16.5L61.1953 16.5L56.6309 9.43945C56.502 9.24023 56.3984 9.04297 56.3203 8.84766L56.2852 8.84766C56.3164 9.05078 56.332 9.47461 56.332 10.1191L56.332 16.5L55.1719 16.5L55.1719 7.42383L56.6426 7.42383L61.084 14.3613C61.2949 14.6895 61.4199 14.8984 61.459 14.9883L61.4824 14.9883C61.4434 14.7305 61.4238 14.2891 61.4238 13.6641L61.4238 7.42383L62.584 7.42383L62.584 16.5ZM70.1309 16.5L68.9766 16.5L68.9766 15.4805L68.9531 15.4805C68.5195 16.2617 67.8535 16.6523 66.9551 16.6523C65.4199 16.6523 64.6523 15.7344 64.6523 13.8984L64.6523 10.0195L65.7891 10.0195L65.7891 13.7285C65.7891 15.0449 66.293 15.7031 67.3008 15.7031C67.8008 15.7031 68.2051 15.5186 68.5137 15.1494C68.8223 14.7803 68.9766 14.3145 68.9766 13.752L68.9766 10.0195L70.1309 10.0195L70.1309 16.5ZM81.5039 16.5L80.3555 16.5L80.3555 12.7793C80.3555 12.0762 80.2461 11.5732 80.0273 11.2705C79.8086 10.9678 79.4492 10.8164 78.9492 10.8164C78.5273 10.8164 78.166 11.0137 77.8652 11.4082C77.5645 11.8027 77.4141 12.2695 77.4141 12.8086L77.4141 16.5L76.2656 16.5L76.2656 12.6621C76.2656 11.4316 75.791 10.8164 74.8418 10.8164C74.4043 10.8164 74.042 11.0039 73.7549 11.3789C73.4678 11.7539 73.3242 12.2324 73.3242 12.8145L73.3242 16.5L72.1758 16.5L72.1758 10.0195L73.3242 10.0195L73.3242 11.0449L73.3477 11.0449C73.8086 10.2598 74.4824 9.86719 75.3691 9.86719C75.8027 9.86719 76.1855 9.98633 76.5176 10.2246C76.8496 10.4629 77.0801 10.7852 77.209 11.1914C77.6895 10.3086 78.4082 9.86719 79.3652 9.86719C80.791 9.86719 81.5039 10.7461 81.5039 12.5039L81.5039 16.5Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</g>
|
||||
<g id="状态栏按键" clip-path="url(#clipPath_111)" customFrame="url(#clipPath_111)">
|
||||
<rect id="状态栏按键" width="56.000000" height="16.000000" x="91.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" fill-opacity="0" />
|
||||
<g id="点 1" clip-path="url(#clipPath_112)" customFrame="url(#clipPath_112)">
|
||||
<rect id="点 1" width="16.000002" height="16.000002" x="95.000000" y="4.000000" />
|
||||
<path id="矢量 11" d="M103 15C104.657 15 106 13.6569 106 12C106 10.3431 104.657 9 103 9C101.343 9 100 10.3431 100 12C100 13.6569 101.343 15 103 15Z" fill="rgb(205,205,205)" fill-rule="nonzero" />
|
||||
<path id="矢量 11" d="M106 12C106 10.3431 104.657 9 103 9C101.343 9 100 10.3431 100 12C100 13.6569 101.343 15 103 15C104.657 15 106 13.6569 106 12Z" fill-rule="nonzero" stroke="rgb(205,205,205)" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M122.383 16.125C121.715 16.4766 120.877 16.6523 119.869 16.6523C118.568 16.6523 117.529 16.2393 116.752 15.4131C115.975 14.5869 115.586 13.4941 115.586 12.1348C115.586 10.6738 116.023 9.49805 116.898 8.60742C117.773 7.7168 118.885 7.27148 120.232 7.27148C121.1 7.27148 121.816 7.39453 122.383 7.64062L122.383 8.86523C121.734 8.50586 121.021 8.32617 120.244 8.32617C119.232 8.32617 118.408 8.66309 117.771 9.33691C117.135 10.0107 116.816 10.9199 116.816 12.0645C116.816 13.1504 117.113 14.0127 117.707 14.6514C118.301 15.29 119.078 15.6094 120.039 15.6094C120.938 15.6094 121.719 15.4062 122.383 15L122.383 16.125ZM124.205 10.4707C124.85 10.0684 125.594 9.86719 126.438 9.86719C128 9.86719 128.781 10.6875 128.781 12.3281L128.781 16.5L127.645 16.5L127.645 15.498L127.615 15.498C127.166 16.2676 126.504 16.6523 125.629 16.6523C125 16.6523 124.5 16.4824 124.129 16.1426C123.758 15.8027 123.572 15.3438 123.572 14.7656C123.572 13.5547 124.289 12.8496 125.723 12.6504L127.645 12.3809C127.645 11.3223 127.207 10.793 126.332 10.793C125.555 10.793 124.846 11.0547 124.205 11.5781L124.205 10.4707ZM126.127 13.4531C125.596 13.5234 125.229 13.6562 125.028 13.8516C124.827 14.0469 124.727 14.3203 124.727 14.6719C124.727 14.9805 124.836 15.2324 125.055 15.4277C125.273 15.623 125.562 15.7207 125.922 15.7207C126.422 15.7207 126.834 15.5449 127.158 15.1934C127.482 14.8418 127.645 14.4004 127.645 13.8691L127.645 13.248L126.127 13.4531ZM131.834 15.5859L131.834 19.4824L130.686 19.4824L130.686 10.0195L131.834 10.0195L131.834 11.1387L131.857 11.1387C132.365 10.291 133.107 9.86719 134.084 9.86719C134.912 9.86719 135.562 10.1572 136.032 10.7373C136.503 11.3174 136.738 12.0957 136.738 13.0723C136.738 14.1504 136.472 15.0166 135.938 15.6709C135.405 16.3252 134.688 16.6523 133.785 16.6523C132.953 16.6523 132.311 16.2969 131.857 15.5859L131.834 15.5859ZM131.828 13.8281C131.828 14.3555 131.998 14.7998 132.338 15.1611C132.678 15.5225 133.104 15.7031 133.615 15.7031C134.225 15.7031 134.701 15.4688 135.045 15C135.389 14.5312 135.561 13.8828 135.561 13.0547C135.561 12.3555 135.4 11.8076 135.08 11.4111C134.76 11.0146 134.322 10.8164 133.768 10.8164C133.201 10.8164 132.736 11.0176 132.373 11.4199C132.01 11.8223 131.828 12.3379 131.828 12.9668L131.828 13.8281ZM137.986 15.0996C138.564 15.5176 139.188 15.7266 139.855 15.7266C140.75 15.7266 141.197 15.4336 141.197 14.8477C141.197 14.5977 141.1 14.3916 140.904 14.2295C140.709 14.0674 140.312 13.875 139.715 13.6523C138.996 13.3633 138.529 13.0771 138.314 12.7939C138.1 12.5107 137.992 12.168 137.992 11.7656C137.992 11.1914 138.235 10.7314 138.722 10.3857C139.208 10.04 139.807 9.86719 140.518 9.86719C141.068 9.86719 141.58 9.96289 142.053 10.1543L142.053 11.2617C141.568 10.9492 141.02 10.793 140.406 10.793C140.039 10.793 139.74 10.873 139.51 11.0332C139.279 11.1934 139.164 11.4043 139.164 11.666C139.164 11.9238 139.247 12.125 139.413 12.2695C139.579 12.4141 139.947 12.5996 140.518 12.8262C141.24 13.0957 141.729 13.375 141.982 13.6641C142.236 13.9531 142.363 14.3105 142.363 14.7363C142.363 15.3301 142.12 15.7979 141.634 16.1396C141.147 16.4814 140.518 16.6523 139.744 16.6523C139.072 16.6523 138.486 16.5254 137.986 16.2715L137.986 15.0996Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</g>
|
||||
<g id="状态栏按键" clip-path="url(#clipPath_113)" customFrame="url(#clipPath_113)">
|
||||
<rect id="状态栏按键" width="60.000000" height="16.000000" x="151.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" fill-opacity="0" />
|
||||
<g id="点 1" clip-path="url(#clipPath_114)" customFrame="url(#clipPath_114)">
|
||||
<rect id="点 1" width="16.000002" height="16.000002" x="155.000000" y="4.000000" />
|
||||
<path id="矢量 11" d="M163 15C164.657 15 166 13.6569 166 12C166 10.3431 164.657 9 163 9C161.343 9 160 10.3431 160 12C160 13.6569 161.343 15 163 15Z" fill="rgb(0,205,27)" fill-rule="nonzero" />
|
||||
<path id="矢量 11" d="M166 12C166 10.3431 164.657 9 163 9C161.343 9 160 10.3431 160 12C160 13.6569 161.343 15 163 15C164.657 15 166 13.6569 166 12Z" fill-rule="nonzero" stroke="rgb(0,205,27)" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M175.75 14.7949C176.027 15.0371 176.398 15.2363 176.863 15.3926C177.328 15.5488 177.77 15.627 178.188 15.627C179.461 15.627 180.098 15.1738 180.098 14.2676C180.098 14.0137 180.029 13.7852 179.893 13.582C179.756 13.3789 179.568 13.1992 179.33 13.043C179.092 12.8867 178.645 12.6465 177.988 12.3223C177.078 11.8691 176.479 11.4482 176.189 11.0596C175.9 10.6709 175.756 10.2266 175.756 9.72656C175.756 8.97266 176.059 8.375 176.664 7.93359C177.27 7.49219 178.033 7.27148 178.955 7.27148C179.857 7.27148 180.52 7.38086 180.941 7.59961L180.941 8.87695C180.395 8.49805 179.703 8.30859 178.867 8.30859C178.312 8.30859 177.86 8.4248 177.511 8.65723C177.161 8.88965 176.986 9.21289 176.986 9.62695C176.986 9.99414 177.107 10.293 177.35 10.5234C177.592 10.7539 178.117 11.0684 178.926 11.4668C179.816 11.8926 180.439 12.3184 180.795 12.7441C181.15 13.1699 181.328 13.6484 181.328 14.1797C181.328 14.9766 181.039 15.5879 180.461 16.0137C179.883 16.4395 179.08 16.6523 178.053 16.6523C177.693 16.6523 177.274 16.6025 176.796 16.5029C176.317 16.4033 175.969 16.2793 175.75 16.1309L175.75 14.7949ZM187.428 16.207C186.932 16.5039 186.334 16.6523 185.635 16.6523C184.697 16.6523 183.943 16.3516 183.373 15.75C182.803 15.1484 182.518 14.3691 182.518 13.4121C182.518 12.3496 182.825 11.4932 183.44 10.8428C184.056 10.1924 184.879 9.86719 185.91 9.86719C186.504 9.86719 187.012 9.97266 187.434 10.1836L187.434 11.3203C186.977 10.9844 186.469 10.8164 185.91 10.8164C185.254 10.8164 184.72 11.0439 184.308 11.499C183.896 11.9541 183.689 12.5605 183.689 13.3184C183.689 14.0645 183.884 14.6484 184.272 15.0703C184.661 15.4922 185.186 15.7031 185.846 15.7031C186.404 15.7031 186.932 15.5195 187.428 15.1523L187.428 16.207ZM192.443 11.1562C192.252 11.0195 191.988 10.9512 191.652 10.9512C191.207 10.9512 190.84 11.1592 190.551 11.5752C190.262 11.9912 190.117 12.5391 190.117 13.2188L190.117 16.5L188.969 16.5L188.969 10.0195L190.117 10.0195L190.117 11.3379L190.141 11.3379C190.469 10.3848 191.035 9.9082 191.84 9.9082C192.102 9.9082 192.303 9.9375 192.443 9.99609L192.443 11.1562ZM192.947 13.3301C192.947 12.2598 193.246 11.415 193.844 10.7959C194.441 10.1768 195.252 9.86719 196.275 9.86719C197.248 9.86719 198.011 10.165 198.563 10.7607C199.116 11.3564 199.393 12.1797 199.393 13.2305C199.393 14.2539 199.098 15.0801 198.508 15.709C197.918 16.3379 197.127 16.6523 196.135 16.6523C195.166 16.6523 194.393 16.3477 193.814 15.7383C193.236 15.1289 192.947 14.3262 192.947 13.3301ZM194.119 13.2949C194.119 14.041 194.308 14.6289 194.685 15.0586C195.062 15.4883 195.568 15.7031 196.205 15.7031C196.861 15.7031 197.361 15.4932 197.705 15.0732C198.049 14.6533 198.221 14.0508 198.221 13.2656C198.221 12.4766 198.049 11.8711 197.705 11.4492C197.361 11.0273 196.861 10.8164 196.205 10.8164C195.561 10.8164 195.052 11.0371 194.679 11.4785C194.306 11.9199 194.119 12.5254 194.119 13.2949ZM201.004 16.5L201.004 6.9082L202.152 6.9082L202.152 16.5L201.004 16.5ZM204.197 16.5L204.197 6.9082L205.346 6.9082L205.346 16.5L204.197 16.5Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 14 KiB |
80
ui/src/assets/second/KeyboardSelected.svg
Normal file
@@ -0,0 +1,80 @@
|
||||
<svg viewBox="0 0 221 23.9999" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="221.000000" height="23.999878" fill="none" customFrame="#000000">
|
||||
<defs>
|
||||
<clipPath id="clipPath_89">
|
||||
<rect width="16.000002" height="16.000002" x="10.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_90">
|
||||
<rect width="57.000000" height="16.000000" x="30.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_91">
|
||||
<rect width="16.000002" height="16.000002" x="34.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_92">
|
||||
<rect width="56.000000" height="16.000000" x="91.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_93">
|
||||
<rect width="16.000002" height="16.000002" x="95.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_94">
|
||||
<rect width="60.000000" height="16.000000" x="151.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_95">
|
||||
<rect width="16.000002" height="16.000002" x="155.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect id="类型=键盘, 状态=选中" width="221.000000" height="24.000000" x="0.000000" y="0.000000" />
|
||||
<g id="键盘 1" clip-path="url(#clipPath_89)" customFrame="url(#clipPath_89)">
|
||||
<rect id="键盘 1" width="16.000002" height="16.000002" x="10.000000" y="4.000000" />
|
||||
<rect id="矩形 7" width="13.333334" height="8.000001" x="11.333313" y="9.999878" rx="0.666667" fill="rgb(22,152,217)" />
|
||||
<rect id="矩形 7" width="13.333334" height="8.000001" x="11.333313" y="9.999878" rx="0.666667" stroke="rgb(22,152,217)" stroke-linejoin="round" stroke-width="1" />
|
||||
<circle id="椭圆 11" cx="14.666667" cy="12.000041" r="0.666666746" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 11" cx="14.666667" cy="12.000041" r="0.166666746" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 12" cx="15.333354" cy="14.000041" r="0.666666985" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 12" cx="15.333354" cy="14.000041" r="0.166666985" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 13" cx="13.333354" cy="14.000041" r="0.666666746" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 13" cx="13.333354" cy="14.000041" r="0.166666746" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 14" cx="16.666666" cy="12.000041" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 14" cx="16.666666" cy="12.000041" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 15" cx="17.333353" cy="14.000041" r="0.666666746" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 15" cx="17.333353" cy="14.000041" r="0.166666746" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 16" cx="18.666666" cy="12.000041" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 16" cx="18.666666" cy="12.000041" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 17" cx="19.333353" cy="14.000041" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 17" cx="19.333353" cy="14.000041" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 18" cx="20.6666679" cy="12.000041" r="0.666666985" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 18" cx="20.6666679" cy="12.000041" r="0.166666985" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 19" cx="21.3333549" cy="14.000041" r="0.666666985" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 19" cx="21.3333549" cy="14.000041" r="0.166666985" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 20" cx="22.666666" cy="12.000041" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 20" cx="22.666666" cy="12.000041" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<path id="矢量 95" d="M15.6667 15.9999L20.3334 15.9999" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 96" d="M18 9.99988L18 8.37488C18 8.19078 18.1492 8.04154 18.3333 8.04154L20 8.04154C20.1841 8.04154 20.3333 7.89231 20.3333 7.70821L20.3333 5.99988" fill-rule="nonzero" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</g>
|
||||
<g id="状态栏按键" clip-path="url(#clipPath_90)" customFrame="url(#clipPath_90)">
|
||||
<rect id="状态栏按键" width="57.000000" height="16.000000" x="30.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" fill-opacity="0" />
|
||||
<g id="点 1" clip-path="url(#clipPath_91)" customFrame="url(#clipPath_91)">
|
||||
<rect id="点 1" width="16.000002" height="16.000002" x="34.000000" y="4.000000" />
|
||||
<path id="矢量 11" d="M42 14.9999C43.6569 14.9999 45 13.6567 45 11.9999C45 10.343 43.6569 8.99988 42 8.99988C40.3431 8.99988 39 10.343 39 11.9999C39 13.6567 40.3431 14.9999 42 14.9999Z" fill="rgb(0,205,27)" fill-rule="nonzero" />
|
||||
<path id="矢量 11" d="M45 11.9999C45 10.343 43.6569 8.99988 42 8.99988C40.3431 8.99988 39 10.343 39 11.9999C39 13.6567 40.3431 14.9999 42 14.9999C43.6569 14.9999 45 13.6567 45 11.9999Z" fill-rule="nonzero" stroke="rgb(0,205,27)" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M62.584 16.4999L61.1953 16.4999L56.6309 9.43933C56.502 9.24011 56.3984 9.04285 56.3203 8.84753L56.2852 8.84753C56.3164 9.05066 56.332 9.47449 56.332 10.119L56.332 16.4999L55.1719 16.4999L55.1719 7.42371L56.6426 7.42371L61.084 14.3612C61.2949 14.6893 61.4199 14.8983 61.459 14.9882L61.4824 14.9882C61.4434 14.7303 61.4238 14.2889 61.4238 13.6639L61.4238 7.42371L62.584 7.42371L62.584 16.4999ZM70.1309 16.4999L68.9766 16.4999L68.9766 15.4803L68.9531 15.4803C68.5195 16.2616 67.8535 16.6522 66.9551 16.6522C65.4199 16.6522 64.6523 15.7343 64.6523 13.8983L64.6523 10.0194L65.7891 10.0194L65.7891 13.7284C65.7891 15.0448 66.293 15.703 67.3008 15.703C67.8008 15.703 68.2051 15.5184 68.5137 15.1493C68.8223 14.7802 68.9766 14.3143 68.9766 13.7518L68.9766 10.0194L70.1309 10.0194L70.1309 16.4999ZM81.5039 16.4999L80.3555 16.4999L80.3555 12.7792C80.3555 12.076 80.2461 11.5731 80.0273 11.2704C79.8086 10.9677 79.4492 10.8163 78.9492 10.8163C78.5273 10.8163 78.166 11.0135 77.8652 11.4081C77.5645 11.8026 77.4141 12.2694 77.4141 12.8085L77.4141 16.4999L76.2656 16.4999L76.2656 12.662C76.2656 11.4315 75.791 10.8163 74.8418 10.8163C74.4043 10.8163 74.042 11.0038 73.7549 11.3788C73.4678 11.7538 73.3242 12.2323 73.3242 12.8143L73.3242 16.4999L72.1758 16.4999L72.1758 10.0194L73.3242 10.0194L73.3242 11.0448L73.3477 11.0448C73.8086 10.2596 74.4824 9.86707 75.3691 9.86707C75.8027 9.86707 76.1855 9.98621 76.5176 10.2245C76.8496 10.4628 77.0801 10.785 77.209 11.1913C77.6895 10.3085 78.4082 9.86707 79.3652 9.86707C80.791 9.86707 81.5039 10.746 81.5039 12.5038L81.5039 16.4999Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</g>
|
||||
<g id="状态栏按键" clip-path="url(#clipPath_92)" customFrame="url(#clipPath_92)">
|
||||
<rect id="状态栏按键" width="56.000000" height="16.000000" x="91.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" fill-opacity="0" />
|
||||
<g id="点 1" clip-path="url(#clipPath_93)" customFrame="url(#clipPath_93)">
|
||||
<rect id="点 1" width="16.000002" height="16.000002" x="95.000000" y="4.000000" />
|
||||
<path id="矢量 11" d="M103 14.9999C104.657 14.9999 106 13.6567 106 11.9999C106 10.343 104.657 8.99988 103 8.99988C101.343 8.99988 100 10.343 100 11.9999C100 13.6567 101.343 14.9999 103 14.9999Z" fill="rgb(205,205,205)" fill-rule="nonzero" />
|
||||
<path id="矢量 11" d="M106 11.9999C106 10.343 104.657 8.99988 103 8.99988C101.343 8.99988 100 10.343 100 11.9999C100 13.6567 101.343 14.9999 103 14.9999C104.657 14.9999 106 13.6567 106 11.9999Z" fill-rule="nonzero" stroke="rgb(205,205,205)" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M122.383 16.1249C121.715 16.4764 120.877 16.6522 119.869 16.6522C118.568 16.6522 117.529 16.2391 116.752 15.413C115.975 14.5868 115.586 13.494 115.586 12.1346C115.586 10.6737 116.023 9.49792 116.898 8.6073C117.773 7.71667 118.885 7.27136 120.232 7.27136C121.1 7.27136 121.816 7.39441 122.383 7.6405L122.383 8.86511C121.734 8.50574 121.021 8.32605 120.244 8.32605C119.232 8.32605 118.408 8.66296 117.771 9.33679C117.135 10.0106 116.816 10.9198 116.816 12.0643C116.816 13.1503 117.113 14.0126 117.707 14.6512C118.301 15.2899 119.078 15.6093 120.039 15.6093C120.938 15.6093 121.719 15.4061 122.383 14.9999L122.383 16.1249ZM124.205 10.4706C124.85 10.0682 125.594 9.86707 126.438 9.86707C128 9.86707 128.781 10.6874 128.781 12.328L128.781 16.4999L127.645 16.4999L127.645 15.4979L127.615 15.4979C127.166 16.2675 126.504 16.6522 125.629 16.6522C125 16.6522 124.5 16.4823 124.129 16.1425C123.758 15.8026 123.572 15.3436 123.572 14.7655C123.572 13.5546 124.289 12.8495 125.723 12.6503L127.645 12.3807C127.645 11.3221 127.207 10.7928 126.332 10.7928C125.555 10.7928 124.846 11.0546 124.205 11.578L124.205 10.4706ZM126.127 13.453C125.596 13.5233 125.229 13.6561 125.028 13.8514C124.827 14.0468 124.727 14.3202 124.727 14.6718C124.727 14.9803 124.836 15.2323 125.055 15.4276C125.273 15.6229 125.562 15.7206 125.922 15.7206C126.422 15.7206 126.834 15.5448 127.158 15.1932C127.482 14.8417 127.645 14.4003 127.645 13.869L127.645 13.2479L126.127 13.453ZM131.834 15.5858L131.834 19.4823L130.686 19.4823L130.686 10.0194L131.834 10.0194L131.834 11.1385L131.857 11.1385C132.365 10.2909 133.107 9.86707 134.084 9.86707C134.912 9.86707 135.562 10.1571 136.032 10.7372C136.503 11.3173 136.738 12.0956 136.738 13.0721C136.738 14.1503 136.472 15.0165 135.938 15.6708C135.405 16.3251 134.688 16.6522 133.785 16.6522C132.953 16.6522 132.311 16.2968 131.857 15.5858L131.834 15.5858ZM131.828 13.828C131.828 14.3553 131.998 14.7997 132.338 15.161C132.678 15.5223 133.104 15.703 133.615 15.703C134.225 15.703 134.701 15.4686 135.045 14.9999C135.389 14.5311 135.561 13.8827 135.561 13.0546C135.561 12.3553 135.4 11.8075 135.08 11.411C134.76 11.0145 134.322 10.8163 133.768 10.8163C133.201 10.8163 132.736 11.0175 132.373 11.4198C132.01 11.8221 131.828 12.3378 131.828 12.9667L131.828 13.828ZM137.986 15.0995C138.564 15.5175 139.188 15.7264 139.855 15.7264C140.75 15.7264 141.197 15.4335 141.197 14.8475C141.197 14.5975 141.1 14.3915 140.904 14.2294C140.709 14.0673 140.312 13.8749 139.715 13.6522C138.996 13.3632 138.529 13.077 138.314 12.7938C138.1 12.5106 137.992 12.1678 137.992 11.7655C137.992 11.1913 138.235 10.7313 138.722 10.3856C139.208 10.0399 139.807 9.86707 140.518 9.86707C141.068 9.86707 141.58 9.96277 142.053 10.1542L142.053 11.2616C141.568 10.9491 141.02 10.7928 140.406 10.7928C140.039 10.7928 139.74 10.8729 139.51 11.0331C139.279 11.1932 139.164 11.4042 139.164 11.6659C139.164 11.9237 139.247 12.1249 139.413 12.2694C139.579 12.4139 139.947 12.5995 140.518 12.826C141.24 13.0956 141.729 13.3749 141.982 13.6639C142.236 13.953 142.363 14.3104 142.363 14.7362C142.363 15.33 142.12 15.7977 141.634 16.1395C141.147 16.4813 140.518 16.6522 139.744 16.6522C139.072 16.6522 138.486 16.5253 137.986 16.2714L137.986 15.0995Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</g>
|
||||
<g id="状态栏按键" clip-path="url(#clipPath_94)" customFrame="url(#clipPath_94)">
|
||||
<rect id="状态栏按键" width="60.000000" height="16.000000" x="151.000000" y="4.000000" rx="4.000000" fill="rgb(255,255,255)" fill-opacity="0" />
|
||||
<g id="点 1" clip-path="url(#clipPath_95)" customFrame="url(#clipPath_95)">
|
||||
<rect id="点 1" width="16.000002" height="16.000002" x="155.000000" y="4.000000" />
|
||||
<path id="矢量 11" d="M163 14.9999C164.657 14.9999 166 13.6567 166 11.9999C166 10.343 164.657 8.99988 163 8.99988C161.343 8.99988 160 10.343 160 11.9999C160 13.6567 161.343 14.9999 163 14.9999Z" fill="rgb(0,205,27)" fill-rule="nonzero" />
|
||||
<path id="矢量 11" d="M166 11.9999C166 10.343 164.657 8.99988 163 8.99988C161.343 8.99988 160 10.343 160 11.9999C160 13.6567 161.343 14.9999 163 14.9999C164.657 14.9999 166 13.6567 166 11.9999Z" fill-rule="nonzero" stroke="rgb(0,205,27)" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M175.75 14.7948C176.027 15.037 176.398 15.2362 176.863 15.3925C177.328 15.5487 177.77 15.6268 178.188 15.6268C179.461 15.6268 180.098 15.1737 180.098 14.2675C180.098 14.0135 180.029 13.785 179.893 13.5819C179.756 13.3788 179.568 13.1991 179.33 13.0428C179.092 12.8866 178.645 12.6464 177.988 12.3221C177.078 11.869 176.479 11.4481 176.189 11.0594C175.9 10.6708 175.756 10.2264 175.756 9.72644C175.756 8.97253 176.059 8.37488 176.664 7.93347C177.27 7.49207 178.033 7.27136 178.955 7.27136C179.857 7.27136 180.52 7.38074 180.941 7.59949L180.941 8.87683C180.395 8.49792 179.703 8.30847 178.867 8.30847C178.312 8.30847 177.86 8.42468 177.511 8.6571C177.161 8.88953 176.986 9.21277 176.986 9.62683C176.986 9.99402 177.107 10.2928 177.35 10.5233C177.592 10.7538 178.117 11.0682 178.926 11.4667C179.816 11.8925 180.439 12.3182 180.795 12.744C181.15 13.1698 181.328 13.6483 181.328 14.1796C181.328 14.9764 181.039 15.5878 180.461 16.0135C179.883 16.4393 179.08 16.6522 178.053 16.6522C177.693 16.6522 177.274 16.6024 176.796 16.5028C176.317 16.4032 175.969 16.2792 175.75 16.1307L175.75 14.7948ZM187.428 16.2069C186.932 16.5038 186.334 16.6522 185.635 16.6522C184.697 16.6522 183.943 16.3514 183.373 15.7499C182.803 15.1483 182.518 14.369 182.518 13.412C182.518 12.3495 182.825 11.493 183.44 10.8427C184.056 10.1923 184.879 9.86707 185.91 9.86707C186.504 9.86707 187.012 9.97253 187.434 10.1835L187.434 11.3202C186.977 10.9843 186.469 10.8163 185.91 10.8163C185.254 10.8163 184.72 11.0438 184.308 11.4989C183.896 11.954 183.689 12.5604 183.689 13.3182C183.689 14.0643 183.884 14.6483 184.272 15.0702C184.661 15.4921 185.186 15.703 185.846 15.703C186.404 15.703 186.932 15.5194 187.428 15.1522L187.428 16.2069ZM192.443 11.1561C192.252 11.0194 191.988 10.951 191.652 10.951C191.207 10.951 190.84 11.1591 190.551 11.5751C190.262 11.9911 190.117 12.5389 190.117 13.2186L190.117 16.4999L188.969 16.4999L188.969 10.0194L190.117 10.0194L190.117 11.3378L190.141 11.3378C190.469 10.3846 191.035 9.90808 191.84 9.90808C192.102 9.90808 192.303 9.93738 192.443 9.99597L192.443 11.1561ZM192.947 13.33C192.947 12.2596 193.246 11.4149 193.844 10.7958C194.441 10.1766 195.252 9.86707 196.275 9.86707C197.248 9.86707 198.011 10.1649 198.563 10.7606C199.116 11.3563 199.393 12.1796 199.393 13.2303C199.393 14.2538 199.098 15.08 198.508 15.7089C197.918 16.3378 197.127 16.6522 196.135 16.6522C195.166 16.6522 194.393 16.3475 193.814 15.7382C193.236 15.1288 192.947 14.326 192.947 13.33ZM194.119 13.2948C194.119 14.0409 194.308 14.6288 194.685 15.0585C195.062 15.4882 195.568 15.703 196.205 15.703C196.861 15.703 197.361 15.493 197.705 15.0731C198.049 14.6532 198.221 14.0507 198.221 13.2655C198.221 12.4764 198.049 11.871 197.705 11.4491C197.361 11.0272 196.861 10.8163 196.205 10.8163C195.561 10.8163 195.052 11.037 194.679 11.4784C194.306 11.9198 194.119 12.5253 194.119 13.2948ZM201.004 16.4999L201.004 6.90808L202.152 6.90808L202.152 16.4999L201.004 16.4999ZM204.197 16.4999L204.197 6.90808L205.346 6.90808L205.346 16.4999L204.197 16.4999Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
17
ui/src/assets/second/MTPPressed.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg viewBox="0 0 66 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="66.000000" height="24.000000" fill="none">
|
||||
<defs>
|
||||
<clipPath id="clipPath_102">
|
||||
<rect width="16.000002" height="16.000002" x="10.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect id="类型=MTP, 状态=按下" width="66.000000" height="24.000000" x="0.000000" y="0.000000" fill="rgb(230,230,230)" />
|
||||
<g id="数据接口 3" clip-path="url(#clipPath_102)" customFrame="url(#clipPath_102)">
|
||||
<rect id="数据接口 3" width="16.000002" height="16.000002" x="10.000000" y="4.000000" />
|
||||
<path id="矢量 12" d="M24 11L12 11L12 18L24 18L24 11Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
<path id="矢量 12" d="M12 11L12 18L24 18L24 11L12 11Z" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M14.6667 11L14.6667 6L21.3334 6L21.3334 11" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M16.6667 8L16.6667 8.66667" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M19.3333 8L19.3333 8.66667" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M39.3809 16.5L39.3809 10.4883C39.3809 9.99219 39.4102 9.39648 39.4688 8.70117L39.4395 8.70117C39.3379 9.13867 39.248 9.44336 39.1699 9.61523L36.1758 16.5L35.5254 16.5L32.5371 9.66797C32.4668 9.51172 32.377 9.18945 32.2676 8.70117L32.2324 8.70117C32.2715 9.12305 32.291 9.73633 32.291 10.541L32.291 16.5L31.1719 16.5L31.1719 7.42383L32.7598 7.42383L35.4375 13.6465C35.6406 14.123 35.7754 14.4941 35.8418 14.7598L35.8828 14.7598C36.0859 14.2012 36.2285 13.8223 36.3105 13.623L39.0352 7.42383L40.5469 7.42383L40.5469 16.5L39.3809 16.5ZM48.3809 8.4668L45.7617 8.4668L45.7617 16.5L44.584 16.5L44.584 8.4668L41.9766 8.4668L41.9766 7.42383L48.3809 7.42383L48.3809 8.4668ZM50.9473 13.1074L50.9473 16.5L49.7754 16.5L49.7754 7.42383L52.3535 7.42383C53.334 7.42383 54.0947 7.66016 54.6357 8.13281C55.1768 8.60547 55.4473 9.28125 55.4473 10.1602C55.4473 11.0508 55.1309 11.7725 54.498 12.3252C53.8652 12.8779 53.0742 13.1387 52.125 13.1074L50.9473 13.1074ZM50.9473 8.45508L50.9473 12.0762L52.0312 12.0762C52.7461 12.0762 53.2891 11.915 53.6602 11.5928C54.0312 11.2705 54.2168 10.8086 54.2168 10.207C54.2168 9.03906 53.5254 8.45508 52.1426 8.45508L50.9473 8.45508Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
8
ui/src/assets/second/MingLing.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="命令键 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 11" d="M4.9697 4.96974C4.9697 4.07781 4.9697 3.47174 4.9697 3.15156C4.9697 2.1474 4.15566 1.33337 3.15151 1.33337C2.14736 1.33337 1.33333 2.1474 1.33333 3.15156C1.33333 4.15571 2.14736 4.96974 3.15151 4.96974C3.50076 4.96974 4.10683 4.96974 4.9697 4.96974Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 12" d="M4.9697 11.0303L4.9697 12.8484C4.9697 13.8526 4.15566 14.6666 3.15151 14.6666C2.14736 14.6666 1.33333 13.8526 1.33333 12.8484C1.33333 11.8443 2.14736 11.0303 3.15151 11.0303L4.9697 11.0303Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<rect id="矩形 1" width="6.060601" height="6.060601" x="4.969727" y="4.969727" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M11.0303 4.96974L11.0303 3.15156C11.0303 2.1474 11.8443 1.33337 12.8485 1.33337C13.8526 1.33337 14.6666 2.1474 14.6666 3.15156C14.6666 4.15571 13.8526 4.96974 12.8485 4.96974L11.0303 4.96974Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M14.6666 12.8484C14.6666 13.8526 13.8526 14.6666 12.8485 14.6666C11.8443 14.6666 11.0303 13.8526 11.0303 12.8484L11.0303 11.0303L12.8485 11.0303C13.8526 11.0303 14.6666 11.8443 14.6666 12.8484Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
16
ui/src/assets/second/MousePressed.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg viewBox="0 0 80 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="80.000000" height="24.000000" fill="none">
|
||||
<defs>
|
||||
<clipPath id="clipPath_107">
|
||||
<rect width="16.000002" height="16.000002" x="10.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect id="类型=鼠标, 状态=按下" width="80.000000" height="24.000000" x="0.000000" y="0.000000" fill="rgb(230,230,230)" />
|
||||
<g id="鼠标 1" clip-path="url(#clipPath_107)" customFrame="url(#clipPath_107)">
|
||||
<rect id="鼠标 1" width="16.000002" height="16.000002" x="10.000000" y="4.000000" />
|
||||
<path id="矢量 12" d="M18 9.33337L14 9.33337L14 14.6667C14 16.8758 15.7909 18.6667 18 18.6667C20.2091 18.6667 22 16.8758 22 14.6667L22 9.33337L18 9.33337Z" fill="rgb(51,51,51)" fill-rule="evenodd" />
|
||||
<path id="矢量 12" d="M14 9.33337L14 14.6667C14 16.8758 15.7909 18.6667 18 18.6667C20.2091 18.6667 22 16.8758 22 14.6667L22 9.33337L18 9.33337L14 9.33337Z" fill-rule="evenodd" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M18 5.33337L18 9.33337L22 9.33337C22 7.12423 20.2091 5.33337 18 5.33337Z" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M14 9.33337L18 9.33337L18 5.33337C15.7909 5.33337 14 7.12423 14 9.33337Z" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M39.3809 16.5L39.3809 10.4883C39.3809 9.99219 39.4102 9.39648 39.4688 8.70117L39.4395 8.70117C39.3379 9.13867 39.248 9.44336 39.1699 9.61523L36.1758 16.5L35.5254 16.5L32.5371 9.66797C32.4668 9.51172 32.377 9.18945 32.2676 8.70117L32.2324 8.70117C32.2715 9.12305 32.291 9.73633 32.291 10.541L32.291 16.5L31.1719 16.5L31.1719 7.42383L32.7598 7.42383L35.4375 13.6465C35.6406 14.123 35.7754 14.4941 35.8418 14.7598L35.8828 14.7598C36.0859 14.2012 36.2285 13.8223 36.3105 13.623L39.0352 7.42383L40.5469 7.42383L40.5469 16.5L39.3809 16.5ZM42.3164 13.3301C42.3164 12.2598 42.6152 11.415 43.2129 10.7959C43.8105 10.1768 44.6211 9.86719 45.6445 9.86719C46.6172 9.86719 47.3799 10.165 47.9326 10.7607C48.4854 11.3564 48.7617 12.1797 48.7617 13.2305C48.7617 14.2539 48.4668 15.0801 47.877 15.709C47.2871 16.3379 46.4961 16.6523 45.5039 16.6523C44.5352 16.6523 43.7617 16.3477 43.1836 15.7383C42.6055 15.1289 42.3164 14.3262 42.3164 13.3301ZM43.4883 13.2949C43.4883 14.041 43.6768 14.6289 44.0537 15.0586C44.4307 15.4883 44.9375 15.7031 45.5742 15.7031C46.2305 15.7031 46.7305 15.4932 47.0742 15.0732C47.418 14.6533 47.5898 14.0508 47.5898 13.2656C47.5898 12.4766 47.418 11.8711 47.0742 11.4492C46.7305 11.0273 46.2305 10.8164 45.5742 10.8164C44.9297 10.8164 44.4209 11.0371 44.0479 11.4785C43.6748 11.9199 43.4883 12.5254 43.4883 13.2949ZM55.7285 16.5L54.5742 16.5L54.5742 15.4805L54.5508 15.4805C54.1172 16.2617 53.4512 16.6523 52.5527 16.6523C51.0176 16.6523 50.25 15.7344 50.25 13.8984L50.25 10.0195L51.3867 10.0195L51.3867 13.7285C51.3867 15.0449 51.8906 15.7031 52.8984 15.7031C53.3984 15.7031 53.8027 15.5186 54.1113 15.1494C54.4199 14.7803 54.5742 14.3145 54.5742 13.752L54.5742 10.0195L55.7285 10.0195L55.7285 16.5ZM57.4102 15.0996C57.9883 15.5176 58.6113 15.7266 59.2793 15.7266C60.1738 15.7266 60.6211 15.4336 60.6211 14.8477C60.6211 14.5977 60.5234 14.3916 60.3281 14.2295C60.1328 14.0674 59.7363 13.875 59.1387 13.6523C58.4199 13.3633 57.9531 13.0771 57.7383 12.7939C57.5234 12.5107 57.416 12.168 57.416 11.7656C57.416 11.1914 57.6592 10.7314 58.1455 10.3857C58.6318 10.04 59.2305 9.86719 59.9414 9.86719C60.4922 9.86719 61.0039 9.96289 61.4766 10.1543L61.4766 11.2617C60.9922 10.9492 60.4434 10.793 59.8301 10.793C59.4629 10.793 59.1641 10.873 58.9336 11.0332C58.7031 11.1934 58.5879 11.4043 58.5879 11.666C58.5879 11.9238 58.6709 12.125 58.8369 12.2695C59.0029 12.4141 59.3711 12.5996 59.9414 12.8262C60.6641 13.0957 61.1523 13.375 61.4062 13.6641C61.6602 13.9531 61.7871 14.3105 61.7871 14.7363C61.7871 15.3301 61.5439 15.7979 61.0576 16.1396C60.5713 16.4814 59.9414 16.6523 59.168 16.6523C58.4961 16.6523 57.9102 16.5254 57.4102 16.2715L57.4102 15.0996ZM68.6074 13.5527L64.0723 13.5527C64.0918 14.2441 64.2812 14.7783 64.6406 15.1553C65 15.5322 65.502 15.7207 66.1465 15.7207C66.873 15.7207 67.5391 15.4883 68.1445 15.0234L68.1445 16.0488C67.5742 16.4512 66.8184 16.6523 65.877 16.6523C64.9395 16.6523 64.208 16.3555 63.6826 15.7617C63.1572 15.168 62.8945 14.3438 62.8945 13.2891C62.8945 12.2969 63.1826 11.4785 63.7588 10.834C64.335 10.1895 65.0508 9.86719 65.9062 9.86719C66.7539 9.86719 67.416 10.1396 67.8926 10.6846C68.3691 11.2295 68.6074 11.9922 68.6074 12.9727L68.6074 13.5527ZM67.459 12.6328C67.4551 12.0469 67.3164 11.5938 67.043 11.2734C66.7695 10.9531 66.3848 10.793 65.8887 10.793C65.4316 10.793 65.0361 10.9629 64.7021 11.3027C64.3682 11.6426 64.1582 12.0859 64.0723 12.6328L67.459 12.6328Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
16
ui/src/assets/second/MouseSelected.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg viewBox="0 0 80 23.9999" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="80.000000" height="23.999878" fill="none">
|
||||
<defs>
|
||||
<clipPath id="clipPath_96">
|
||||
<rect width="16.000002" height="16.000002" x="10.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect id="类型=鼠标, 状态=选中" width="80.000000" height="24.000000" x="0.000000" y="0.000000" fill="rgb(255,255,255)" fill-opacity="0" />
|
||||
<g id="鼠标 1" clip-path="url(#clipPath_96)" customFrame="url(#clipPath_96)">
|
||||
<rect id="鼠标 1" width="16.000002" height="16.000002" x="10.000000" y="4.000000" />
|
||||
<path id="矢量 12" d="M18 9.33337L14 9.33337L14 14.6667C14 16.8758 15.7909 18.6667 18 18.6667C20.2091 18.6667 22 16.8758 22 14.6667L22 9.33337L18 9.33337Z" fill="rgb(22,152,217)" fill-rule="evenodd" />
|
||||
<path id="矢量 12" d="M14 9.33337L14 14.6667C14 16.8758 15.7909 18.6667 18 18.6667C20.2091 18.6667 22 16.8758 22 14.6667L22 9.33337L18 9.33337L14 9.33337Z" fill-rule="evenodd" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M18 5.33337L18 9.33337L22 9.33337C22 7.12423 20.2091 5.33337 18 5.33337Z" fill-rule="nonzero" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M14 9.33337L18 9.33337L18 5.33337C15.7909 5.33337 14 7.12423 14 9.33337Z" fill-rule="nonzero" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M39.3809 16.4999L39.3809 10.4882C39.3809 9.99207 39.4102 9.39636 39.4688 8.70105L39.4395 8.70105C39.3379 9.13855 39.248 9.44324 39.1699 9.61511L36.1758 16.4999L35.5254 16.4999L32.5371 9.66785C32.4668 9.5116 32.377 9.18933 32.2676 8.70105L32.2324 8.70105C32.2715 9.12292 32.291 9.73621 32.291 10.5409L32.291 16.4999L31.1719 16.4999L31.1719 7.42371L32.7598 7.42371L35.4375 13.6464C35.6406 14.1229 35.7754 14.494 35.8418 14.7596L35.8828 14.7596C36.0859 14.201 36.2285 13.8221 36.3105 13.6229L39.0352 7.42371L40.5469 7.42371L40.5469 16.4999L39.3809 16.4999ZM42.3164 13.33C42.3164 12.2596 42.6152 11.4149 43.2129 10.7958C43.8105 10.1766 44.6211 9.86707 45.6445 9.86707C46.6172 9.86707 47.3799 10.1649 47.9326 10.7606C48.4854 11.3563 48.7617 12.1796 48.7617 13.2303C48.7617 14.2538 48.4668 15.08 47.877 15.7089C47.2871 16.3378 46.4961 16.6522 45.5039 16.6522C44.5352 16.6522 43.7617 16.3475 43.1836 15.7382C42.6055 15.1288 42.3164 14.326 42.3164 13.33ZM43.4883 13.2948C43.4883 14.0409 43.6768 14.6288 44.0537 15.0585C44.4307 15.4882 44.9375 15.703 45.5742 15.703C46.2305 15.703 46.7305 15.493 47.0742 15.0731C47.418 14.6532 47.5898 14.0507 47.5898 13.2655C47.5898 12.4764 47.418 11.871 47.0742 11.4491C46.7305 11.0272 46.2305 10.8163 45.5742 10.8163C44.9297 10.8163 44.4209 11.037 44.0479 11.4784C43.6748 11.9198 43.4883 12.5253 43.4883 13.2948ZM55.7285 16.4999L54.5742 16.4999L54.5742 15.4803L54.5508 15.4803C54.1172 16.2616 53.4512 16.6522 52.5527 16.6522C51.0176 16.6522 50.25 15.7343 50.25 13.8983L50.25 10.0194L51.3867 10.0194L51.3867 13.7284C51.3867 15.0448 51.8906 15.703 52.8984 15.703C53.3984 15.703 53.8027 15.5184 54.1113 15.1493C54.4199 14.7802 54.5742 14.3143 54.5742 13.7518L54.5742 10.0194L55.7285 10.0194L55.7285 16.4999ZM57.4102 15.0995C57.9883 15.5175 58.6113 15.7264 59.2793 15.7264C60.1738 15.7264 60.6211 15.4335 60.6211 14.8475C60.6211 14.5975 60.5234 14.3915 60.3281 14.2294C60.1328 14.0673 59.7363 13.8749 59.1387 13.6522C58.4199 13.3632 57.9531 13.077 57.7383 12.7938C57.5234 12.5106 57.416 12.1678 57.416 11.7655C57.416 11.1913 57.6592 10.7313 58.1455 10.3856C58.6318 10.0399 59.2305 9.86707 59.9414 9.86707C60.4922 9.86707 61.0039 9.96277 61.4766 10.1542L61.4766 11.2616C60.9922 10.9491 60.4434 10.7928 59.8301 10.7928C59.4629 10.7928 59.1641 10.8729 58.9336 11.0331C58.7031 11.1932 58.5879 11.4042 58.5879 11.6659C58.5879 11.9237 58.6709 12.1249 58.8369 12.2694C59.0029 12.4139 59.3711 12.5995 59.9414 12.826C60.6641 13.0956 61.1523 13.3749 61.4062 13.6639C61.6602 13.953 61.7871 14.3104 61.7871 14.7362C61.7871 15.33 61.5439 15.7977 61.0576 16.1395C60.5713 16.4813 59.9414 16.6522 59.168 16.6522C58.4961 16.6522 57.9102 16.5253 57.4102 16.2714L57.4102 15.0995ZM68.6074 13.5526L64.0723 13.5526C64.0918 14.244 64.2812 14.7782 64.6406 15.1552C65 15.5321 65.502 15.7206 66.1465 15.7206C66.873 15.7206 67.5391 15.4882 68.1445 15.0233L68.1445 16.0487C67.5742 16.451 66.8184 16.6522 65.877 16.6522C64.9395 16.6522 64.208 16.3553 63.6826 15.7616C63.1572 15.1678 62.8945 14.3436 62.8945 13.2889C62.8945 12.2968 63.1826 11.4784 63.7588 10.8339C64.335 10.1893 65.0508 9.86707 65.9062 9.86707C66.7539 9.86707 67.416 10.1395 67.8926 10.6844C68.3691 11.2294 68.6074 11.9921 68.6074 12.9725L68.6074 13.5526ZM67.459 12.6327C67.4551 12.0468 67.3164 11.5936 67.043 11.2733C66.7695 10.953 66.3848 10.7928 65.8887 10.7928C65.4316 10.7928 65.0361 10.9628 64.7021 11.3026C64.3682 11.6425 64.1582 12.0858 64.0723 12.6327L67.459 12.6327Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.9 KiB |
18
ui/src/assets/second/SharedFoldersPressed.svg
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
8
ui/src/assets/second/UAC.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="数据接口 3" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 12" d="M14 7L2 7L2 14L14 14L14 7Z" fill="currentColor" fill-rule="nonzero" />
|
||||
<path id="矢量 12" d="M2 7L2 14L14 14L14 7L2 7Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M4.66699 7L4.66699 2L11.3337 2L11.3337 7" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M6.66699 4L6.66699 4.66667" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M9.33301 4L9.33301 4.66667" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 947 B |
17
ui/src/assets/second/UACPressed.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg viewBox="0 0 66 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="66.000000" height="24.000000" fill="none">
|
||||
<defs>
|
||||
<clipPath id="clipPath_103">
|
||||
<rect width="16.000002" height="16.000002" x="10.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect id="类型=UAC, 状态=按下" width="66.000000" height="24.000000" x="0.000000" y="0.000000" fill="rgb(230,230,230)" />
|
||||
<g id="数据接口 3" clip-path="url(#clipPath_103)" customFrame="url(#clipPath_103)">
|
||||
<rect id="数据接口 3" width="16.000002" height="16.000002" x="10.000000" y="4.000000" />
|
||||
<path id="矢量 12" d="M24 11L12 11L12 18L24 18L24 11Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
<path id="矢量 12" d="M12 11L12 18L24 18L24 11L12 11Z" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M14.6666 11L14.6666 6L21.3333 6L21.3333 11" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M16.6666 8L16.6666 8.66667" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M19.3334 8L19.3334 8.66667" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M37.8984 12.8027C37.8984 15.3691 36.7344 16.6523 34.4062 16.6523C32.1758 16.6523 31.0605 15.4141 31.0605 12.9375L31.0605 7.42383L32.2324 7.42383L32.2324 12.8848C32.2324 14.7012 32.9941 15.6094 34.5176 15.6094C35.9902 15.6094 36.7266 14.7305 36.7266 12.9727L36.7266 7.42383L37.8984 7.42383L37.8984 12.8027ZM47.0039 16.5L45.709 16.5L44.7832 14.0156L41.0039 14.0156L40.1309 16.5L38.8359 16.5L42.293 7.42383L43.5469 7.42383L47.0039 16.5ZM44.4199 12.9902L43.0488 9.2168C43.0059 9.0957 42.959 8.88477 42.9082 8.58398L42.8789 8.58398C42.8359 8.85742 42.7871 9.06836 42.7324 9.2168L41.373 12.9902L44.4199 12.9902ZM54.3574 16.125C53.6895 16.4766 52.8516 16.6523 51.8438 16.6523C50.543 16.6523 49.5039 16.2393 48.7266 15.4131C47.9492 14.5869 47.5605 13.4941 47.5605 12.1348C47.5605 10.6738 47.998 9.49805 48.873 8.60742C49.748 7.7168 50.8594 7.27148 52.207 7.27148C53.0742 7.27148 53.791 7.39453 54.3574 7.64062L54.3574 8.86523C53.709 8.50586 52.9961 8.32617 52.2188 8.32617C51.207 8.32617 50.3828 8.66309 49.7461 9.33691C49.1094 10.0107 48.791 10.9199 48.791 12.0645C48.791 13.1504 49.0879 14.0127 49.6816 14.6514C50.2754 15.29 51.0527 15.6094 52.0137 15.6094C52.9121 15.6094 53.6934 15.4062 54.3574 15L54.3574 16.125Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
17
ui/src/assets/second/UACSelected.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg viewBox="0 0 66 23.9999" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="66.000000" height="23.999878" fill="none">
|
||||
<defs>
|
||||
<clipPath id="clipPath_98">
|
||||
<rect width="16.000002" height="16.000002" x="10.000000" y="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect id="类型=UAC, 状态=选中" width="66.000000" height="24.000000" x="0.000000" y="0.000000" />
|
||||
<g id="数据接口 3" clip-path="url(#clipPath_98)" customFrame="url(#clipPath_98)">
|
||||
<rect id="数据接口 3" width="16.000002" height="16.000002" x="10.000000" y="4.000000" />
|
||||
<path id="矢量 12" d="M24 10.9999L12 10.9999L12 17.9999L24 17.9999L24 10.9999Z" fill="rgb(22,152,217)" fill-rule="nonzero" />
|
||||
<path id="矢量 12" d="M12 10.9999L12 17.9999L24 17.9999L24 10.9999L12 10.9999Z" fill-rule="nonzero" stroke="rgb(22,152,217)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M14.6666 10.9999L14.6666 5.99988L21.3333 5.99988L21.3333 10.9999" fill-rule="nonzero" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M16.6666 7.99988L16.6666 8.66654" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M19.3334 7.99988L19.3334 8.66654" stroke="rgb(22,152,217)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</g>
|
||||
<path id="" d="M37.8984 12.8026C37.8984 15.369 36.7344 16.6522 34.4062 16.6522C32.1758 16.6522 31.0605 15.4139 31.0605 12.9374L31.0605 7.42371L32.2324 7.42371L32.2324 12.8846C32.2324 14.701 32.9941 15.6093 34.5176 15.6093C35.9902 15.6093 36.7266 14.7303 36.7266 12.9725L36.7266 7.42371L37.8984 7.42371L37.8984 12.8026ZM47.0039 16.4999L45.709 16.4999L44.7832 14.0155L41.0039 14.0155L40.1309 16.4999L38.8359 16.4999L42.293 7.42371L43.5469 7.42371L47.0039 16.4999ZM44.4199 12.9901L43.0488 9.21667C43.0059 9.09558 42.959 8.88464 42.9082 8.58386L42.8789 8.58386C42.8359 8.8573 42.7871 9.06824 42.7324 9.21667L41.373 12.9901L44.4199 12.9901ZM54.3574 16.1249C53.6895 16.4764 52.8516 16.6522 51.8438 16.6522C50.543 16.6522 49.5039 16.2391 48.7266 15.413C47.9492 14.5868 47.5605 13.494 47.5605 12.1346C47.5605 10.6737 47.998 9.49792 48.873 8.6073C49.748 7.71667 50.8594 7.27136 52.207 7.27136C53.0742 7.27136 53.791 7.39441 54.3574 7.6405L54.3574 8.86511C53.709 8.50574 52.9961 8.32605 52.2188 8.32605C51.207 8.32605 50.3828 8.66296 49.7461 9.33679C49.1094 10.0106 48.791 10.9198 48.791 12.0643C48.791 13.1503 49.0879 14.0126 49.6816 14.6512C50.2754 15.2899 51.0527 15.6093 52.0137 15.6093C52.9121 15.6093 53.6934 15.4061 54.3574 14.9999L54.3574 16.1249Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
17
ui/src/assets/second/VideoPressed.svg
Normal file
|
After Width: | Height: | Size: 10 KiB |
17
ui/src/assets/second/VideoSelected.svg
Normal file
|
After Width: | Height: | Size: 11 KiB |
18
ui/src/assets/second/VirtualStoragePressed.svg
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
18
ui/src/assets/second/VirtualStorageSelected.svg
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
6
ui/src/assets/second/access.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="人身安全 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 34" d="M8.00287 1.33325L14 3.08513L14 6.67782C14 10.454 11.5834 13.4731 8.00087 14.6668C4.41737 13.4731 2 10.4533 2 6.67615L2 3.08513L8.00287 1.33325Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<circle id="椭圆 1" cx="8.00001049" cy="5.99991894" r="1.66666698" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 35" d="M10.6667 10.3334C10.6667 8.86065 9.47278 7.66675 8.00001 7.66675C6.52724 7.66675 5.33334 8.86065 5.33334 10.3334" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 916 B |
4
ui/src/assets/second/advanced.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="工具 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 34" d="M10.6667 9.33325C9.99111 9.33325 9.35464 9.16575 8.79654 8.87005L3.00001 14.6666L1.33334 12.9999L7.12988 7.20339C6.83418 6.64529 6.66668 6.00882 6.66668 5.33325C6.66668 3.12411 8.45754 1.33325 10.6667 1.33325C11.3422 1.33325 11.9787 1.50074 12.5368 1.79645L10 4.33325L11.6667 5.99992L14.2035 3.46312C14.4992 4.02122 14.6667 4.65769 14.6667 5.33325C14.6667 7.54239 12.8758 9.33325 10.6667 9.33325Z" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 779 B |
9
ui/src/assets/second/copy.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="复制 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 7" d="M4.33331 12.6667L13.6666 12.6667L13.6666 5.33337L9.99998 5.33337L9.99998 1.33337L4.33331 1.33337L4.33331 12.6667Z" fill="currentColor" fill-rule="nonzero" />
|
||||
<path id="矢量 7" d="M13.6666 12.6667L13.6666 5.33337L9.99998 5.33337L9.99998 1.33337L4.33331 1.33337L4.33331 12.6667L13.6666 12.6667Z" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 8" d="M10 1.33337L13.6667 5.33337" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 9" d="M2.33331 6.66663L2.33331 14.6666L9.33331 14.6666" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 10" d="M6.33331 6.66663L7.66665 6.66663" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-width="1" />
|
||||
<path id="矢量 11" d="M6.33331 9.33337L10.3333 9.33337" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
5
ui/src/assets/second/delete.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="关闭 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 28" d="M2.66699 2.66675L13.3337 13.3334" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
|
||||
<path id="矢量 29" d="M2.66699 13.3334L13.3337 2.66675" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 555 B |
5
ui/src/assets/second/down.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="下1 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 60" d="M1.66699 8L8.00033 14L14.3337 8L10.3337 8L10.3337 2L5.66699 2L5.66699 8L1.66699 8Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
<path id="矢量 60" d="M8.00033 14L14.3337 8L10.3337 8L10.3337 2L5.66699 2L5.66699 8L1.66699 8L8.00033 14Z" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 618 B |
5
ui/src/assets/second/dwon.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="下1 2" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 79" d="M12 6.33325L8 10.3333L4 6.33325L12 6.33325Z" fill="currentColor" fill-rule="nonzero" />
|
||||
<path id="矢量 79" d="M8 10.3333L4 6.33325L12 6.33325L8 10.3333Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 513 B |
16
ui/src/assets/second/dwon2.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg viewBox="0 0 28 28" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="28.000000" height="28.000000" fill="none" clip-path="url(#clipPath_0)" customFrame="url(#clipPath_0)">
|
||||
<defs>
|
||||
<clipPath id="clipPath_0">
|
||||
<rect width="28.000002" height="28.000000" x="0.000000" y="0.000000" rx="4.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
<clipPath id="clipPath_1">
|
||||
<rect width="16.000002" height="16.000002" x="6.000000" y="6.000000" fill="rgb(255,255,255)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<rect id="宏按键" width="27.000002" height="27.000000" x="0.500000" y="0.500000" rx="3.500000" stroke="rgb(56,56,56)" stroke-width="1" />
|
||||
<g id="下1 2" clip-path="url(#clipPath_1)" customFrame="url(#clipPath_1)">
|
||||
<rect id="下1 2" width="16.000002" height="16.000002" x="6.000000" y="6.000000" />
|
||||
<path id="矢量 79" d="M18 12.3335L14 16.3335L10 12.3335L18 12.3335Z" fill="rgb(255,255,255)" fill-rule="nonzero" />
|
||||
<path id="矢量 79" d="M14 16.3335L10 12.3335L18 12.3335L14 16.3335Z" fill-rule="nonzero" stroke="rgb(255,255,255)" stroke-linejoin="round" stroke-width="1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
4
ui/src/assets/second/float_button1.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="工具 2" width="16.000000" height="16.000000" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 82" d="M10.6666 9.33325C9.99102 9.33325 9.35455 9.16575 8.79645 8.87005L2.99992 14.6666L1.33325 12.9999L7.12979 7.20339C6.83409 6.64529 6.66659 6.00882 6.66659 5.33325C6.66659 3.12411 8.45745 1.33325 10.6666 1.33325C11.3422 1.33325 11.9786 1.50074 12.5367 1.79645L9.99992 4.33325L11.6666 5.99992L14.2034 3.46312C14.4991 4.02122 14.6666 4.65769 14.6666 5.33325C14.6666 7.54239 12.8757 9.33325 10.6666 9.33325Z" fill-rule="nonzero" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 788 B |
5
ui/src/assets/second/float_button2.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="关闭 1" width="16.000000" height="16.000000" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 82" d="M2.66675 2.6665L13.3334 13.3332" stroke="rgb(153,153,153)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 83" d="M2.66675 13.3332L13.3334 2.6665" stroke="rgb(153,153,153)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 549 B |
5
ui/src/assets/second/general.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="设置 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 34" d="M3.19597 12.6223C3.48968 12.2742 3.66668 11.8244 3.66668 11.3333C3.66668 10.2288 2.77125 9.33333 1.66668 9.33333C1.59986 9.33333 1.53381 9.33663 1.46867 9.34303C1.37994 8.90919 1.33334 8.46006 1.33334 7.99999C1.33334 7.30313 1.44027 6.63123 1.63861 5.99979C1.64795 5.99993 1.6573 5.99999 1.66668 5.99999C2.77125 5.99999 3.66668 5.10456 3.66668 3.99999C3.66668 3.68289 3.59288 3.38306 3.46154 3.11666C4.23251 2.39979 5.17351 1.8633 6.21738 1.57434C6.54814 2.22269 7.22224 2.66667 8.00001 2.66667C8.77778 2.66667 9.45188 2.22269 9.78264 1.57434C10.8265 1.8633 11.7675 2.39979 12.5385 3.11666C12.4071 3.38306 12.3333 3.68289 12.3333 3.99999C12.3333 5.10456 13.2288 5.99999 14.3333 5.99999C14.3427 5.99999 14.3521 5.99993 14.3614 5.99979C14.5597 6.63123 14.6667 7.30313 14.6667 7.99999C14.6667 8.46006 14.6201 8.90919 14.5313 9.34303C14.4662 9.33663 14.4002 9.33333 14.3333 9.33333C13.2288 9.33333 12.3333 10.2288 12.3333 11.3333C12.3333 11.8244 12.5103 12.2742 12.804 12.6223C12.0167 13.4404 11.0224 14.0578 9.90541 14.3904C9.64761 13.584 8.89201 13 8.00001 13C7.10801 13 6.35241 13.584 6.09461 14.3904C4.97758 14.0578 3.98328 13.4404 3.19597 12.6223Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 35" d="M10.3333 7.99996C10.3333 6.71129 9.28866 5.66663 7.99999 5.66663C6.71132 5.66663 5.66666 6.71129 5.66666 7.99996C5.66666 9.28863 6.71132 10.3333 7.99999 10.3333C9.28866 10.3333 10.3333 9.28863 10.3333 7.99996Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
5
ui/src/assets/second/gobottom.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="去底部1 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 107" d="M12 4.66675L8 8.66675L4 4.66675" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 108" d="M4 11.3333L12 11.3333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 557 B |
29
ui/src/assets/second/hardware.svg
Normal file
@@ -0,0 +1,29 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="芯片 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 34" d="M3.33332 2.66675C2.96513 2.66675 2.66666 2.96522 2.66666 3.33341L2.66666 12.6667C2.66666 13.0349 2.96513 13.3334 3.33332 13.3334L12.6667 13.3334C13.0349 13.3334 13.3333 13.0349 13.3333 12.6667L13.3333 3.33341C13.3333 2.96522 13.0349 2.66675 12.6667 2.66675L3.33332 2.66675Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 35" d="M6 6L6 10L10 10L10 6L6 6Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 36" d="M4.96973 0.666748L4.96973 2.66675L4.96973 0.666748Z" fill-rule="evenodd" />
|
||||
<path id="矢量 37" d="M4.96973 0.666748L4.96973 2.66675" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 38" d="M4.96973 13.3333L4.96973 15.3333L4.96973 13.3333Z" fill-rule="evenodd" />
|
||||
<path id="矢量 39" d="M4.96973 13.3333L4.96973 15.3333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 40" d="M8 0.666748L8 2.66675L8 0.666748Z" fill-rule="evenodd" />
|
||||
<path id="矢量 41" d="M8 0.666748L8 2.66675" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 42" d="M8 13.3333L8 15.3333L8 13.3333Z" fill-rule="evenodd" />
|
||||
<path id="矢量 43" d="M8 13.3333L8 15.3333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 44" d="M11.0303 0.666748L11.0303 2.66675L11.0303 0.666748Z" fill-rule="evenodd" />
|
||||
<path id="矢量 45" d="M11.0303 0.666748L11.0303 2.66675" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 46" d="M11.0303 13.3333L11.0303 15.3333L11.0303 13.3333Z" fill-rule="evenodd" />
|
||||
<path id="矢量 47" d="M11.0303 13.3333L11.0303 15.3333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 48" />
|
||||
<path id="矢量 49" d="M0.666656 4.96973L2.66666 4.96973" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 50" />
|
||||
<path id="矢量 51" d="M13.3333 4.96973L15.3333 4.96973" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 52" />
|
||||
<path id="矢量 53" d="M0.666656 8L2.66666 8" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 54" />
|
||||
<path id="矢量 55" d="M13.3333 8L15.3333 8" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 56" />
|
||||
<path id="矢量 57" d="M0.666656 11.0303L2.66666 11.0303" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 58" />
|
||||
<path id="矢量 59" d="M13.3333 11.0303L15.3333 11.0303" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
13
ui/src/assets/second/hdmi-cord.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48.000000" height="48.000000" fill="none">
|
||||
<rect id="hdmi-cord 2" width="48.000000" height="48.000000" x="0.000000" y="0.000000" fill="none" />
|
||||
<g id="组合 186">
|
||||
<path id="矩形 8" d="M16.9289 45L16.9289 36.3333L7.5 36.3333C6.39543 36.3333 5.5 35.4379 5.5 34.3333L5.5 19L37.5 19L37.5 30M26.1289 45L26.1289 36.3333L28.5 36.3333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矩形 9" d="M8.5 19L8.5 4L34.5 4L34.5 19" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 99" d="M12.5 4L12.5 19" stroke="currentColor" stroke-linecap="round" stroke-width="2" />
|
||||
<path id="矢量 100" d="M30.5 4L30.5 19" stroke="currentColor" stroke-linecap="round" stroke-width="2" />
|
||||
<rect id="矩形 10" width="2.000000" height="2.000000" x="17.000000" y="11.000000" stroke="currentColor" stroke-linejoin="round" stroke-width="2" />
|
||||
<rect id="矩形 11" width="2.000000" height="2.000000" x="24.000000" y="11.000000" stroke="currentColor" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 105" d="M0.001 0L0 15.5565" stroke="rgb(230,23,23)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="matrix(0.707107,-0.707107,0.707107,0.707107,33,34.0007)" />
|
||||
<path id="矢量 106" d="M0 0L0.001 15.5568" stroke="rgb(230,23,23)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="matrix(0.707107,0.707107,0.707107,-0.707107,33,45.0007)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
14
ui/src/assets/second/hdml.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="HDMI线 2" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 11" d="M1.33331 5.33329C1.33331 4.96509 1.63179 4.66663 1.99998 4.66663L14 4.66663C14.3682 4.66663 14.6666 4.96509 14.6666 5.33329L14.6666 8.21526C14.6666 8.48786 14.4994 8.73393 14.2736 8.88666C13.8671 9.16169 13.2645 9.71633 13.066 10.6706C12.991 11.0311 12.7015 11.3333 12.3333 11.3333L3.66665 11.3333C3.29846 11.3333 3.00891 11.0311 2.93392 10.6706C2.73541 9.71633 2.13286 9.16169 1.72637 8.88666C1.50059 8.73393 1.33331 8.48786 1.33331 8.21526L1.33331 5.33329Z" fill="rgb(205,205,205)" fill-rule="nonzero" />
|
||||
<path id="矢量 11" d="M1.99998 4.66663L14 4.66663C14.3682 4.66663 14.6666 4.96509 14.6666 5.33329L14.6666 8.21526C14.6666 8.48786 14.4994 8.73393 14.2736 8.88666C13.8671 9.16169 13.2645 9.71633 13.066 10.6706C12.991 11.0311 12.7015 11.3333 12.3333 11.3333L3.66665 11.3333C3.29846 11.3333 3.00891 11.0311 2.93392 10.6706C2.73541 9.71633 2.13286 9.16169 1.72637 8.88666C1.50059 8.73393 1.33331 8.48786 1.33331 8.21526L1.33331 5.33329C1.33331 4.96509 1.63179 4.66663 1.99998 4.66663Z" fill-rule="nonzero" stroke="rgb(205,205,205)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 12" d="M4.66669 9.33337L11.3334 9.33337" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M4.66669 9.33337L4.66669 8.33337" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M7 9.33337L7 8.33337" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M9 9.33337L9 8.33337" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 16" d="M11.3333 9.33337L11.3333 8.33337" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 17" d="M3.66669 6.66663L4.33335 6.66663" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 18" d="M6.33331 6.66663L6.99998 6.66663" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 19" d="M9 6.66663L9.66667 6.66663" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 20" d="M11.6667 6.66663L12.3334 6.66663" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
14
ui/src/assets/second/hdml2.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="HDMI线 2" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 11" d="M1.33301 5.33317C1.33301 4.96497 1.63148 4.6665 1.99967 4.6665L13.9997 4.6665C14.3679 4.6665 14.6663 4.96497 14.6663 5.33317L14.6663 8.21514C14.6663 8.48774 14.4991 8.7338 14.2733 8.88654C13.8668 9.16157 13.2642 9.71621 13.0657 10.6705C12.9907 11.0309 12.7012 11.3332 12.333 11.3332L3.66634 11.3332C3.29815 11.3332 3.0086 11.0309 2.93361 10.6705C2.7351 9.71621 2.13255 9.16157 1.72607 8.88654C1.50029 8.7338 1.33301 8.48774 1.33301 8.21514L1.33301 5.33317Z" fill="rgb(0,205,27)" fill-rule="nonzero" />
|
||||
<path id="矢量 11" d="M1.99967 4.6665L13.9997 4.6665C14.3679 4.6665 14.6663 4.96497 14.6663 5.33317L14.6663 8.21514C14.6663 8.48774 14.4991 8.7338 14.2733 8.88654C13.8668 9.16157 13.2642 9.71621 13.0657 10.6705C12.9907 11.0309 12.7012 11.3332 12.333 11.3332L3.66634 11.3332C3.29815 11.3332 3.0086 11.0309 2.93361 10.6705C2.7351 9.71621 2.13255 9.16157 1.72607 8.88654C1.50029 8.7338 1.33301 8.48774 1.33301 8.21514L1.33301 5.33317C1.33301 4.96497 1.63148 4.6665 1.99967 4.6665Z" fill-rule="nonzero" stroke="rgb(0,205,27)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 12" d="M4.66699 9.3335L11.3337 9.3335" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M4.66699 9.3335L4.66699 8.3335" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M7 9.3335L7 8.3335" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M9 9.3335L9 8.3335" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 16" d="M11.333 9.3335L11.333 8.3335" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 17" d="M3.66699 6.6665L4.33366 6.6665" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 18" d="M6.33301 6.6665L6.99967 6.6665" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 19" d="M9 6.6665L9.66667 6.6665" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 20" d="M11.667 6.6665L12.3337 6.6665" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
27
ui/src/assets/second/keyboard.svg
Normal file
@@ -0,0 +1,27 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="键盘 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<rect id="矩形 7" width="13.333334" height="8.000001" x="1.333008" y="6.000000" rx="0.666667" fill="currentColor" />
|
||||
<rect id="矩形 7" width="13.333334" height="8.000001" x="1.333008" y="6.000000" rx="0.666667" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<circle id="椭圆 11" cx="4.66666698" cy="8.00016308" r="0.666666746" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 11" cx="4.66666698" cy="8.00016308" r="0.166666746" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 12" cx="5.33365917" cy="10.0001631" r="0.666666985" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 12" cx="5.33365917" cy="10.0001631" r="0.166666985" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 13" cx="3.33365893" cy="10.0001631" r="0.666666746" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 13" cx="3.33365893" cy="10.0001631" r="0.166666746" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 14" cx="6.66666651" cy="8.00016308" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 14" cx="6.66666651" cy="8.00016308" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 15" cx="7.33365917" cy="10.0001631" r="0.666666746" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 15" cx="7.33365917" cy="10.0001631" r="0.166666746" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 16" cx="8.66666603" cy="8.00016308" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 16" cx="8.66666603" cy="8.00016308" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 17" cx="9.33365822" cy="10.0001631" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 17" cx="9.33365822" cy="10.0001631" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 18" cx="10.666667" cy="8.00016308" r="0.666666985" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 18" cx="10.666667" cy="8.00016308" r="0.166666985" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 19" cx="11.3336592" cy="10.0001631" r="0.666666985" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 19" cx="11.3336592" cy="10.0001631" r="0.166666985" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<circle id="椭圆 20" cx="12.666666" cy="8.00016308" r="0.666666508" fill="rgb(255,255,255)" />
|
||||
<circle id="椭圆 20" cx="12.666666" cy="8.00016308" r="0.166666508" stroke="rgb(255,255,255)" stroke-width="1" />
|
||||
<path id="矢量 95" d="M5.66699 12L10.3337 12" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 96" d="M8 6L8 4.375C8 4.1909 8.14923 4.04167 8.33333 4.04167L10 4.04167C10.1841 4.04167 10.3333 3.89243 10.3333 3.70833L10.3333 2" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
27
ui/src/assets/second/keyboard2.svg
Normal file
@@ -0,0 +1,27 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="键盘 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<rect id="矩形 7" width="13.333334" height="8.000001" x="1.333374" y="6.000000" rx="0.666667" fill="currentColor" />
|
||||
<rect id="矩形 7" width="13.333334" height="8.000001" x="1.333374" y="6.000000" rx="0.666667" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<circle id="椭圆 11" cx="4.66666698" cy="7.99991894" r="0.666666746" fill="rgb(26,26,26)" />
|
||||
<circle id="椭圆 11" cx="4.66666698" cy="7.99991894" r="0.166666746" stroke="rgb(26,26,26)" stroke-width="1" />
|
||||
<circle id="椭圆 12" cx="5.33329296" cy="9.99991894" r="0.666666985" fill="rgb(26,26,26)" />
|
||||
<circle id="椭圆 12" cx="5.33329296" cy="9.99991894" r="0.166666985" stroke="rgb(26,26,26)" stroke-width="1" />
|
||||
<circle id="椭圆 13" cx="3.33329272" cy="9.99991894" r="0.666666746" fill="rgb(26,26,26)" />
|
||||
<circle id="椭圆 13" cx="3.33329272" cy="9.99991894" r="0.166666746" stroke="rgb(26,26,26)" stroke-width="1" />
|
||||
<circle id="椭圆 14" cx="6.66666651" cy="7.99991894" r="0.666666508" fill="rgb(26,26,26)" />
|
||||
<circle id="椭圆 14" cx="6.66666651" cy="7.99991894" r="0.166666508" stroke="rgb(26,26,26)" stroke-width="1" />
|
||||
<circle id="椭圆 15" cx="7.33329296" cy="9.99991894" r="0.666666746" fill="rgb(26,26,26)" />
|
||||
<circle id="椭圆 15" cx="7.33329296" cy="9.99991894" r="0.166666746" stroke="rgb(26,26,26)" stroke-width="1" />
|
||||
<circle id="椭圆 16" cx="8.66666603" cy="7.99991894" r="0.666666508" fill="rgb(26,26,26)" />
|
||||
<circle id="椭圆 16" cx="8.66666603" cy="7.99991894" r="0.166666508" stroke="rgb(26,26,26)" stroke-width="1" />
|
||||
<circle id="椭圆 17" cx="9.33329201" cy="9.99991894" r="0.666666508" fill="rgb(26,26,26)" />
|
||||
<circle id="椭圆 17" cx="9.33329201" cy="9.99991894" r="0.166666508" stroke="rgb(26,26,26)" stroke-width="1" />
|
||||
<circle id="椭圆 18" cx="10.666667" cy="7.99991894" r="0.666666985" fill="rgb(26,26,26)" />
|
||||
<circle id="椭圆 18" cx="10.666667" cy="7.99991894" r="0.166666985" stroke="rgb(26,26,26)" stroke-width="1" />
|
||||
<circle id="椭圆 19" cx="11.333293" cy="9.99991894" r="0.666666985" fill="rgb(26,26,26)" />
|
||||
<circle id="椭圆 19" cx="11.333293" cy="9.99991894" r="0.166666985" stroke="rgb(26,26,26)" stroke-width="1" />
|
||||
<circle id="椭圆 20" cx="12.666666" cy="7.99991894" r="0.666666508" fill="rgb(26,26,26)" />
|
||||
<circle id="椭圆 20" cx="12.666666" cy="7.99991894" r="0.166666508" stroke="rgb(26,26,26)" stroke-width="1" />
|
||||
<path id="矢量 95" d="M5.66663 12L10.3333 12" stroke="rgb(26,26,26)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 96" d="M8 6L8 4.375C8 4.1909 8.14923 4.04167 8.33333 4.04167L10 4.04167C10.1841 4.04167 10.3333 3.89243 10.3333 3.70833L10.3333 2" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
4
ui/src/assets/second/left.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="右 2" width="16.000002" height="16.000000" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 64" d="M6.33398 4L10.334 8L6.33398 12" fill-rule="nonzero" stroke="rgb(153,153,153)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 416 B |
9
ui/src/assets/second/media.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="从动装置 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 12" d="M14.6666 9.6665L1.33331 9.6665L1.33331 13.9998L14.6666 13.9998L14.6666 9.6665Z" fill="currentColor" fill-rule="nonzero" />
|
||||
<path id="矢量 12" d="M1.33331 9.6665L1.33331 13.9998L14.6666 13.9998L14.6666 9.6665L1.33331 9.6665Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M1.33331 9.66677L3.01277 1.6665L13.0068 1.6665L14.6666 9.66677" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M6.33335 4C5.41289 4 4.66669 4.7462 4.66669 5.66667C4.66669 6.58713 5.41289 7.33333 6.33335 7.33333" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M9.66669 7.33333C10.5872 7.33333 11.3334 6.58713 11.3334 5.66667C11.3334 4.7462 10.5872 4 9.66669 4" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-width="1" />
|
||||
<path id="矢量 16" d="M6.66669 5.6665L9.33335 5.6665" stroke="currentColor" stroke-linecap="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
8
ui/src/assets/second/minglingdarkac.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="命令键 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 11" d="M4.96962 4.96962C4.96962 4.07769 4.96962 3.47162 4.96962 3.15144C4.96962 2.14728 4.15559 1.33325 3.15144 1.33325C2.14728 1.33325 1.33325 2.14728 1.33325 3.15144C1.33325 4.15559 2.14728 4.96962 3.15144 4.96962C3.50069 4.96962 4.10675 4.96962 4.96962 4.96962Z" fill-rule="nonzero" stroke="rgb(45,106,229)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 12" d="M4.96962 11.0303L4.96962 12.8484C4.96962 13.8526 4.15559 14.6666 3.15144 14.6666C2.14728 14.6666 1.33325 13.8526 1.33325 12.8484C1.33325 11.8443 2.14728 11.0303 3.15144 11.0303L4.96962 11.0303Z" fill-rule="nonzero" stroke="rgb(45,106,229)" stroke-linejoin="round" stroke-width="1" />
|
||||
<rect id="矩形 1" width="6.060601" height="6.060601" x="4.969727" y="4.969727" stroke="rgb(45,106,229)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M11.0303 4.96962L11.0303 3.15144C11.0303 2.14728 11.8443 1.33325 12.8485 1.33325C13.8526 1.33325 14.6666 2.14728 14.6666 3.15144C14.6666 4.15559 13.8526 4.96962 12.8485 4.96962L11.0303 4.96962Z" fill-rule="nonzero" stroke="rgb(45,106,229)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M14.6666 12.8484C14.6666 13.8526 13.8526 14.6666 12.8485 14.6666C11.8443 14.6666 11.0303 13.8526 11.0303 12.8484L11.0303 11.0303L12.8485 11.0303C13.8526 11.0303 14.6666 11.8443 14.6666 12.8484Z" fill-rule="nonzero" stroke="rgb(45,106,229)" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
7
ui/src/assets/second/mouse.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="鼠标 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 12" d="M8 5.3335L4 5.3335L4 10.6668C4 12.876 5.79087 14.6668 8 14.6668C10.2091 14.6668 12 12.876 12 10.6668L12 5.3335L8 5.3335Z" fill="currentColor" fill-rule="evenodd" />
|
||||
<path id="矢量 12" d="M4 5.3335L4 10.6668C4 12.876 5.79087 14.6668 8 14.6668C10.2091 14.6668 12 12.876 12 10.6668L12 5.3335L8 5.3335L4 5.3335Z" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M8 1.3335L8 5.3335L12 5.3335C12 3.12436 10.2091 1.3335 8 1.3335Z" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M4 5.3335L8 5.3335L8 1.3335C5.79087 1.3335 4 3.12436 4 5.3335Z" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
8
ui/src/assets/second/network.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="地球仪 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 34" d="M14.6667 7.99992C14.6667 4.31802 11.6819 1.33325 8.00001 1.33325C4.31811 1.33325 1.33334 4.31802 1.33334 7.99992C1.33334 11.6818 4.31811 14.6666 8.00001 14.6666C11.6819 14.6666 14.6667 11.6818 14.6667 7.99992Z" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 35" d="M1.33334 8L14.6667 8" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 36" d="M10.6667 7.99992C10.6667 4.31802 9.47278 1.33325 8.00001 1.33325C6.52724 1.33325 5.33334 4.31802 5.33334 7.99992C5.33334 11.6818 6.52724 14.6666 8.00001 14.6666C9.47278 14.6666 10.6667 11.6818 10.6667 7.99992Z" fill-rule="evenodd" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 37" d="M3.28598 3.38062C4.49241 4.58705 6.15908 5.33325 8.00001 5.33325C9.84098 5.33325 11.5076 4.58705 12.7141 3.38062" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 38" d="M12.7141 12.6194C11.5076 11.4129 9.84098 10.6667 8.00001 10.6667C6.15908 10.6667 4.49241 11.4129 3.28598 12.6194" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
7
ui/src/assets/second/noSD.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none">
|
||||
<rect id="提示 2" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 86" d="M22 4L2 4L2 19L9.5 19L12 21.5L14.5 19L22 19L22 4Z" fill="rgb(255,0,0)" fill-rule="nonzero" />
|
||||
<path id="矢量 86" d="M2 4L2 19L9.5 19L12 21.5L14.5 19L22 19L22 4L2 4Z" fill-rule="nonzero" stroke="rgb(255,0,0)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
|
||||
<path id="矢量 87" d="M12 11.5L12 16" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-width="1.5" />
|
||||
<path id="矢量 88" d="M12 8L12 8.5" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-width="1.5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 774 B |
5
ui/src/assets/second/open.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="开关 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 7" d="M4.83335 2.66675C4.61355 2.79225 4.40209 2.93042 4.20002 3.08025C3.85419 3.33665 3.53582 3.62721 3.25002 3.94682C2.26461 5.04885 1.66669 6.49645 1.66669 8.08191C1.66669 11.5345 4.50222 14.3334 8.00002 14.3334C11.4978 14.3334 14.3334 11.5345 14.3334 8.08191C14.3334 6.49645 13.7354 5.04885 12.75 3.94682C12.4642 3.62721 12.1459 3.33665 11.8 3.08025C11.598 2.93042 11.3865 2.79225 11.1667 2.66675" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
|
||||
<path id="矢量 8" d="M8 1.33325L8 7.99992" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 915 B |
6
ui/src/assets/second/refresh.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.000000" height="12.000000" fill="none">
|
||||
<rect id="刷新 2" width="12.000000" height="12.000000" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 80" d="M10.5 2L10.5 6" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 81" d="M1.5 6L1.5 10" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 82" d="M10.5 6C10.5 3.51472 8.48528 1.5 6 1.5C4.72862 1.5 3.5804 2.02724 2.76203 2.875M1.5 6C1.5 8.48528 3.51472 10.5 6 10.5C7.2139 10.5 8.31555 10.0194 9.125 9.23798" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 801 B |
161
ui/src/assets/second/rname.py
Normal file
@@ -0,0 +1,161 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
def translate_chinese_to_english(text):
|
||||
"""
|
||||
将特定的中文关键词翻译成英文
|
||||
"""
|
||||
translation_dict = {
|
||||
'类型': 'Type',
|
||||
'状态': 'State',
|
||||
'按下': 'Pressed',
|
||||
'选中': 'Selected',
|
||||
'键盘': 'Keyboard',
|
||||
'鼠标': 'Mouse',
|
||||
'虚拟存储': 'VirtualStorage',
|
||||
'禁用': 'Disabled',
|
||||
'连接统计': 'ConnectStats',
|
||||
'共享文件夹': 'SharedFolders',
|
||||
'视频': 'Video',
|
||||
'MTP': 'MTP',
|
||||
'UAC': 'UAC'
|
||||
}
|
||||
|
||||
for chinese, english in translation_dict.items():
|
||||
text = text.replace(chinese, english)
|
||||
|
||||
return text
|
||||
|
||||
def clean_filename(filename):
|
||||
"""
|
||||
清理文件名:翻译中文关键词,移除空格、等号、逗号,并去除Type和State文字
|
||||
"""
|
||||
# 分离文件名和扩展名[1,5](@ref)
|
||||
name, ext = os.path.splitext(filename)
|
||||
|
||||
# 1. 翻译中文关键词
|
||||
translated_name = translate_chinese_to_english(name)
|
||||
|
||||
# 2. 使用正则表达式移除所有空格、等号、逗号[7](@ref)
|
||||
cleaned_name = re.sub(r'[\s=,]+', '', translated_name)
|
||||
|
||||
# 3. 去除Type和State文字(新增功能)
|
||||
cleaned_name = cleaned_name.replace('Type', '').replace('State', '')
|
||||
|
||||
return cleaned_name + ext
|
||||
|
||||
def rename_files(directory_path='.'):
|
||||
"""
|
||||
重命名指定目录下的所有文件[4,6](@ref)
|
||||
"""
|
||||
print(f"正在处理目录: {os.path.abspath(directory_path)}")
|
||||
|
||||
try:
|
||||
files = [f for f in os.listdir(directory_path) if os.path.isfile(os.path.join(directory_path, f))]
|
||||
except FileNotFoundError:
|
||||
print(f"错误:目录 '{directory_path}' 不存在。")
|
||||
return
|
||||
except PermissionError:
|
||||
print(f"错误:没有权限访问目录 '{directory_path}'。")
|
||||
return
|
||||
|
||||
if not files:
|
||||
print("指定目录中没有文件。")
|
||||
return
|
||||
|
||||
renamed_count = 0
|
||||
print("\n开始重命名...")
|
||||
|
||||
for filename in files:
|
||||
old_name = filename
|
||||
new_name = clean_filename(old_name)
|
||||
|
||||
# 只有当文件名确实发生变化时才进行重命名
|
||||
if old_name != new_name:
|
||||
old_path = os.path.join(directory_path, old_name)
|
||||
new_path = os.path.join(directory_path, new_name)
|
||||
|
||||
# 检查新文件名是否已存在,避免覆盖
|
||||
if os.path.exists(new_path):
|
||||
print(f"警告:目标文件已存在,跳过 {old_name} -> {new_name}")
|
||||
continue
|
||||
|
||||
try:
|
||||
os.rename(old_path, new_path)
|
||||
print(f"✓ 重命名: {old_name} -> {new_name}")
|
||||
renamed_count += 1
|
||||
except OSError as e:
|
||||
print(f"✗ 重命名失败 {old_name}: {e}")
|
||||
|
||||
print(f"\n完成!成功重命名了 {renamed_count} 个文件。")
|
||||
|
||||
def preview_renames(directory_path='.'):
|
||||
"""
|
||||
预览重命名效果,而不实际执行重命名操作[4](@ref)
|
||||
"""
|
||||
print("=== 预览重命名效果(非实际执行)===")
|
||||
print(f"预览目录: {os.path.abspath(directory_path)}")
|
||||
print("-" * 60)
|
||||
|
||||
try:
|
||||
files = [f for f in os.listdir(directory_path) if os.path.isfile(os.path.join(directory_path, f))]
|
||||
except Exception as e:
|
||||
print(f"无法读取目录: {e}")
|
||||
return
|
||||
|
||||
if not files:
|
||||
print("目录中没有文件可预览。")
|
||||
return
|
||||
|
||||
change_count = 0
|
||||
for filename in files:
|
||||
new_filename = clean_filename(filename)
|
||||
if filename != new_filename:
|
||||
print(f"原文件名: {filename}")
|
||||
print(f"新文件名: {new_filename}")
|
||||
print("-" * 40)
|
||||
change_count += 1
|
||||
|
||||
if change_count == 0:
|
||||
print("未发现需要重命名的文件(所有文件名已符合规则)。")
|
||||
else:
|
||||
print(f"预览结束。共有 {change_count} 个文件将被重命名。")
|
||||
|
||||
# 使用示例
|
||||
if __name__ == "__main__":
|
||||
# 1. 先预览重命名效果(推荐)
|
||||
print("=== 预览模式 ===")
|
||||
preview_renames() # 处理当前目录
|
||||
|
||||
# 2. 测试您提供的示例文件名转换效果
|
||||
print("\n=== 示例文件名转换效果 ===")
|
||||
example_files = [
|
||||
"类型=Connect Stats,状态=按下.svg",
|
||||
"类型=Connect Stats,状态=选中.svg",
|
||||
"类型=Disabled,状态=按下.svg",
|
||||
"类型=MTP,状态=按下.svg",
|
||||
"类型=Shared Folders,状态=按下.svg",
|
||||
"类型=UAC,状态=按下.svg",
|
||||
"类型=UAC,状态=选中.svg",
|
||||
"类型=Video,状态=按下.svg",
|
||||
"类型=Video,状态=选中.svg",
|
||||
"类型=键盘,状态=按下.svg",
|
||||
"类型=键盘,状态=选中.svg",
|
||||
"类型=鼠标,状态=按下.svg",
|
||||
"类型=鼠标,状态=选中.svg",
|
||||
"类型=虚拟存储,状态=按下.svg",
|
||||
"类型=虚拟存储,状态=选中.svg"
|
||||
]
|
||||
|
||||
for old_name in example_files:
|
||||
new_name = clean_filename(old_name)
|
||||
print(f"{old_name}")
|
||||
print(f"-> {new_name}")
|
||||
print()
|
||||
|
||||
# 3. 实际执行重命名(取消注释以下代码来执行)
|
||||
|
||||
print("\n=== 执行重命名 ===")
|
||||
# 确认预览结果无误后,取消下面的注释来执行重命名
|
||||
rename_files() # 重命名当前目录的文件
|
||||
|
||||
7
ui/src/assets/second/set1.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="设置 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 5" d="M6.09461 14.3904C4.97758 14.0578 3.98328 13.4404 3.19597 12.6223C3.48968 12.2742 3.66668 11.8244 3.66668 11.3333C3.66668 10.2288 2.77125 9.33333 1.66668 9.33333C1.59986 9.33333 1.53381 9.33663 1.46867 9.34303C1.37994 8.90919 1.33334 8.46006 1.33334 7.99999C1.33334 7.30313 1.44027 6.63123 1.63861 5.99979C1.64795 5.99993 1.6573 5.99999 1.66668 5.99999C2.77125 5.99999 3.66668 5.10456 3.66668 3.99999C3.66668 3.68289 3.59288 3.38306 3.46154 3.11666C4.23251 2.39979 5.17351 1.8633 6.21738 1.57434C6.54814 2.22269 7.22224 2.66667 8.00001 2.66667C8.77778 2.66667 9.45188 2.22269 9.78264 1.57434C10.8265 1.8633 11.7675 2.39979 12.5385 3.11666C12.4071 3.38306 12.3333 3.68289 12.3333 3.99999C12.3333 5.10456 13.2288 5.99999 14.3333 5.99999C14.3427 5.99999 14.3521 5.99993 14.3614 5.99979C14.5597 6.63123 14.6667 7.30313 14.6667 7.99999C14.6667 8.46006 14.6201 8.90919 14.5313 9.34303C14.4662 9.33663 14.4002 9.33333 14.3333 9.33333C13.2288 9.33333 12.3333 10.2288 12.3333 11.3333C12.3333 11.8244 12.5103 12.2742 12.804 12.6223C12.0167 13.4404 11.0224 14.0578 9.90541 14.3904C9.64761 13.584 8.89201 13 8.00001 13C7.10801 13 6.35241 13.584 6.09461 14.3904Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
<path id="矢量 5" d="M3.19597 12.6223C3.48968 12.2742 3.66668 11.8244 3.66668 11.3333C3.66668 10.2288 2.77125 9.33333 1.66668 9.33333C1.59986 9.33333 1.53381 9.33663 1.46867 9.34303C1.37994 8.90919 1.33334 8.46006 1.33334 7.99999C1.33334 7.30313 1.44027 6.63123 1.63861 5.99979C1.64795 5.99993 1.6573 5.99999 1.66668 5.99999C2.77125 5.99999 3.66668 5.10456 3.66668 3.99999C3.66668 3.68289 3.59288 3.38306 3.46154 3.11666C4.23251 2.39979 5.17351 1.8633 6.21738 1.57434C6.54814 2.22269 7.22224 2.66667 8.00001 2.66667C8.77778 2.66667 9.45188 2.22269 9.78264 1.57434C10.8265 1.8633 11.7675 2.39979 12.5385 3.11666C12.4071 3.38306 12.3333 3.68289 12.3333 3.99999C12.3333 5.10456 13.2288 5.99999 14.3333 5.99999C14.3427 5.99999 14.3521 5.99993 14.3614 5.99979C14.5597 6.63123 14.6667 7.30313 14.6667 7.99999C14.6667 8.46006 14.6201 8.90919 14.5313 9.34303C14.4662 9.33663 14.4002 9.33333 14.3333 9.33333C13.2288 9.33333 12.3333 10.2288 12.3333 11.3333C12.3333 11.8244 12.5103 12.2742 12.804 12.6223C12.0167 13.4404 11.0224 14.0578 9.90541 14.3904C9.64761 13.584 8.89201 13 8.00001 13C7.10801 13 6.35241 13.584 6.09461 14.3904C4.97758 14.0578 3.98328 13.4404 3.19597 12.6223Z" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 6" d="M7.99999 10.3333C9.28866 10.3333 10.3333 9.28863 10.3333 7.99996C10.3333 6.71129 9.28866 5.66663 7.99999 5.66663C6.71132 5.66663 5.66666 6.71129 5.66666 7.99996C5.66666 9.28863 6.71132 10.3333 7.99999 10.3333Z" fill="rgb(255,255,255)" fill-rule="nonzero" />
|
||||
<path id="矢量 6" d="M10.3333 7.99996C10.3333 6.71129 9.28866 5.66663 7.99999 5.66663C6.71132 5.66663 5.66666 6.71129 5.66666 7.99996C5.66666 9.28863 6.71132 10.3333 7.99999 10.3333C9.28866 10.3333 10.3333 9.28863 10.3333 7.99996Z" fill-rule="nonzero" stroke="rgb(255,255,255)" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
7
ui/src/assets/second/set2.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="设置 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 5" d="M6.09458 14.3904C4.97755 14.0578 3.98325 13.4404 3.19594 12.6223C3.48965 12.2742 3.66665 11.8244 3.66665 11.3333C3.66665 10.2288 2.77122 9.33333 1.66665 9.33333C1.59983 9.33333 1.53378 9.33663 1.46864 9.34303C1.37991 8.90919 1.33331 8.46006 1.33331 7.99999C1.33331 7.30313 1.44024 6.63123 1.63858 5.99979C1.64792 5.99993 1.65727 5.99999 1.66665 5.99999C2.77122 5.99999 3.66665 5.10456 3.66665 3.99999C3.66665 3.68289 3.59285 3.38306 3.46151 3.11666C4.23248 2.39979 5.17348 1.8633 6.21735 1.57434C6.54811 2.22269 7.22221 2.66667 7.99998 2.66667C8.77775 2.66667 9.45185 2.22269 9.78261 1.57434C10.8265 1.8633 11.7675 2.39979 12.5384 3.11666C12.4071 3.38306 12.3333 3.68289 12.3333 3.99999C12.3333 5.10456 13.2287 5.99999 14.3333 5.99999C14.3427 5.99999 14.352 5.99993 14.3614 5.99979C14.5597 6.63123 14.6666 7.30313 14.6666 7.99999C14.6666 8.46006 14.62 8.90919 14.5313 9.34303C14.4662 9.33663 14.4001 9.33333 14.3333 9.33333C13.2287 9.33333 12.3333 10.2288 12.3333 11.3333C12.3333 11.8244 12.5103 12.2742 12.804 12.6223C12.0167 13.4404 11.0224 14.0578 9.90538 14.3904C9.64758 13.584 8.89198 13 7.99998 13C7.10798 13 6.35238 13.584 6.09458 14.3904Z" fill="currentColor" fill-rule="nonzero" />
|
||||
<path id="矢量 5" d="M3.19594 12.6223C3.48965 12.2742 3.66665 11.8244 3.66665 11.3333C3.66665 10.2288 2.77122 9.33333 1.66665 9.33333C1.59983 9.33333 1.53378 9.33663 1.46864 9.34303C1.37991 8.90919 1.33331 8.46006 1.33331 7.99999C1.33331 7.30313 1.44024 6.63123 1.63858 5.99979C1.64792 5.99993 1.65727 5.99999 1.66665 5.99999C2.77122 5.99999 3.66665 5.10456 3.66665 3.99999C3.66665 3.68289 3.59285 3.38306 3.46151 3.11666C4.23248 2.39979 5.17348 1.8633 6.21735 1.57434C6.54811 2.22269 7.22221 2.66667 7.99998 2.66667C8.77775 2.66667 9.45185 2.22269 9.78261 1.57434C10.8265 1.8633 11.7675 2.39979 12.5384 3.11666C12.4071 3.38306 12.3333 3.68289 12.3333 3.99999C12.3333 5.10456 13.2287 5.99999 14.3333 5.99999C14.3427 5.99999 14.352 5.99993 14.3614 5.99979C14.5597 6.63123 14.6666 7.30313 14.6666 7.99999C14.6666 8.46006 14.62 8.90919 14.5313 9.34303C14.4662 9.33663 14.4001 9.33333 14.3333 9.33333C13.2287 9.33333 12.3333 10.2288 12.3333 11.3333C12.3333 11.8244 12.5103 12.2742 12.804 12.6223C12.0167 13.4404 11.0224 14.0578 9.90538 14.3904C9.64758 13.584 8.89198 13 7.99998 13C7.10798 13 6.35238 13.584 6.09458 14.3904C4.97755 14.0578 3.98325 13.4404 3.19594 12.6223Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 6" d="M7.99996 10.3333C9.28863 10.3333 10.3333 9.28863 10.3333 7.99996C10.3333 6.71129 9.28863 5.66663 7.99996 5.66663C6.71129 5.66663 5.66663 6.71129 5.66663 7.99996C5.66663 9.28863 6.71129 10.3333 7.99996 10.3333Z" fill="rgb(26,26,26)" fill-rule="nonzero" />
|
||||
<path id="矢量 6" d="M10.3333 7.99996C10.3333 6.71129 9.28863 5.66663 7.99996 5.66663C6.71129 5.66663 5.66663 6.71129 5.66663 7.99996C5.66663 9.28863 6.71129 10.3333 7.99996 10.3333C9.28863 10.3333 10.3333 9.28863 10.3333 7.99996Z" fill-rule="nonzero" stroke="rgb(26,26,26)" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
6
ui/src/assets/second/shuaxin.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="刷新 3" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 83" d="M14 2.6665L14 7.99984" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 84" d="M2 8L2 13.3333" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 85" d="M14 8C14 4.6863 11.3137 2 8 2C6.30483 2 4.77387 2.70299 3.6827 3.83333M2 8C2 11.3137 4.6863 14 8 14C9.61853 14 11.0874 13.3591 12.1667 12.3173" fill-rule="nonzero" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 804 B |
7
ui/src/assets/second/state.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="信号 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 12" d="M13.3334 2L13.3334 14" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 13" d="M9.66663 5.3335L9.66663 14.0002" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 14" d="M6.33337 8.6665L6.33337 13.9998" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
<path id="矢量 15" d="M2.66663 12L2.66663 14" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 816 B |
9
ui/src/assets/second/swich_dir2.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="转换文件夹 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 12" d="M1.66602 2.66667C1.66602 2.29848 1.96449 2 2.33268 2L6.33268 2L7.99935 4L13.666 4C14.0342 4 14.3327 4.29847 14.3327 4.66667L14.3327 13.3333C14.3327 13.7015 14.0342 14 13.666 14L2.33268 14C1.96449 14 1.66602 13.7015 1.66602 13.3333L1.66602 2.66667Z" fill="rgb(255,255,255)" fill-rule="nonzero" />
|
||||
<path id="矢量 12" d="M2.33268 2L6.33268 2L7.99935 4L13.666 4C14.0342 4 14.3327 4.29847 14.3327 4.66667L14.3327 13.3333C14.3327 13.7015 14.0342 14 13.666 14L2.33268 14C1.96449 14 1.66602 13.7015 1.66602 13.3333L1.66602 2.66667C1.66602 2.29848 1.96449 2 2.33268 2Z" fill-rule="nonzero" stroke="rgb(255,255,255)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M5.66602 8L10.3327 8" stroke="rgb(26,26,26)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M5.66602 10L10.3327 10" stroke="rgb(26,26,26)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M10.3327 8.00016L8.66602 6.3335" stroke="rgb(26,26,26)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 16" d="M7.33268 11.6667L5.66602 10" stroke="rgb(26,26,26)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
9
ui/src/assets/second/swich_dri1.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="转换文件夹 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 12" d="M1.66602 2.66667C1.66602 2.29848 1.96449 2 2.33268 2L6.33268 2L7.99935 4L13.666 4C14.0342 4 14.3327 4.29847 14.3327 4.66667L14.3327 13.3333C14.3327 13.7015 14.0342 14 13.666 14L2.33268 14C1.96449 14 1.66602 13.7015 1.66602 13.3333L1.66602 2.66667Z" fill="rgb(51,51,51)" fill-rule="nonzero" />
|
||||
<path id="矢量 12" d="M2.33268 2L6.33268 2L7.99935 4L13.666 4C14.0342 4 14.3327 4.29847 14.3327 4.66667L14.3327 13.3333C14.3327 13.7015 14.0342 14 13.666 14L2.33268 14C1.96449 14 1.66602 13.7015 1.66602 13.3333L1.66602 2.66667C1.66602 2.29848 1.96449 2 2.33268 2Z" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M5.66602 8L10.3327 8" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M5.66602 10L10.3327 10" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M10.3327 8.00016L8.66602 6.3335" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 16" d="M7.33268 11.6667L5.66602 10" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
5
ui/src/assets/second/tiaozhuan.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="箭头右 2" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 82" d="M14 8L2 8" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 83" d="M10 4L14 8L10 12" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 529 B |
5
ui/src/assets/second/to_down.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="下1 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 60" d="M1.66699 8L8.00033 14L14.3337 8L10.3337 8L10.3337 2L5.66699 2L5.66699 8L1.66699 8Z" fill="currentColor" fill-rule="nonzero" />
|
||||
<path id="矢量 60" d="M8.00033 14L14.3337 8L10.3337 8L10.3337 2L5.66699 2L5.66699 8L1.66699 8L8.00033 14Z" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 616 B |
5
ui/src/assets/second/to_up.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="下1 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" transform="matrix(1,0,0,-1,0,16)" />
|
||||
<path id="矢量 60" d="M0 6L6.33333 12L12.6667 6L8.66667 6L8.66667 0L4 0L4 6L0 6Z" fill="currentColor" fill-rule="nonzero" transform="matrix(1,0,0,-1,1.66699,14)" />
|
||||
<path id="矢量 60" d="M6.33333 12L12.6667 6L8.66667 6L8.66667 0L4 0L4 6L0 6L6.33333 12Z" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" transform="matrix(1,0,0,-1,1.66699,14)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 688 B |
5
ui/src/assets/second/up.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="下1 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" transform="matrix(1,0,0,-1,0,16)" />
|
||||
<path id="矢量 60" d="M0 6L6.33333 12L12.6667 6L8.66667 6L8.66667 0L4 0L4 6L0 6Z" fill="rgb(51,51,51)" fill-rule="nonzero" transform="matrix(1,0,0,-1,1.66699,14)" />
|
||||
<path id="矢量 60" d="M6.33333 12L12.6667 6L8.66667 6L8.66667 0L4 0L4 6L0 6L6.33333 12Z" fill-rule="nonzero" stroke="rgb(51,51,51)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" transform="matrix(1,0,0,-1,1.66699,14)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 690 B |
8
ui/src/assets/second/upload.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.000000" height="24.000000" fill="none">
|
||||
<rect id="收件上载 2" width="24.000000" height="24.000000" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 65" d="M2 15L4.5 3L19.5 3L22 15" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
|
||||
<path id="矢量 66" d="M2 15L7.45455 15L8.36365 18L15.6363 18L16.5455 15L22 15L22 21.5L2 21.5L2 15Z" fill="currentColor" fill-rule="nonzero" />
|
||||
<path id="矢量 66" d="M7.45455 15L8.36365 18L15.6363 18L16.5455 15L22 15L22 21.5L2 21.5L2 15L7.45455 15Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1.5" />
|
||||
<path id="矢量 67" d="M9 10L12 7L15 10" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
|
||||
<path id="矢量 68" d="M12 13L12 7" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
12
ui/src/assets/second/usb.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="数据接口 2" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 11" d="M4.00033 7.33317C4.73669 7.33317 5.33366 6.7362 5.33366 5.99984C5.33366 5.26347 4.73669 4.6665 4.00033 4.6665C3.26395 4.6665 2.66699 5.26347 2.66699 5.99984C2.66699 6.7362 3.26395 7.33317 4.00033 7.33317Z" fill="rgb(205,205,205)" fill-rule="nonzero" />
|
||||
<path id="矢量 11" d="M5.33366 5.99984C5.33366 5.26347 4.73669 4.6665 4.00033 4.6665C3.26395 4.6665 2.66699 5.26347 2.66699 5.99984C2.66699 6.7362 3.26395 7.33317 4.00033 7.33317C4.73669 7.33317 5.33366 6.7362 5.33366 5.99984Z" fill-rule="nonzero" stroke="rgb(205,205,205)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 12" d="M12.0003 9.33317C12.7367 9.33317 13.3337 8.7362 13.3337 7.99984C13.3337 7.26347 12.7367 6.6665 12.0003 6.6665C11.264 6.6665 10.667 7.26347 10.667 7.99984C10.667 8.7362 11.264 9.33317 12.0003 9.33317Z" fill="rgb(205,205,205)" fill-rule="nonzero" />
|
||||
<path id="矢量 12" d="M13.3337 7.99984C13.3337 7.26347 12.7367 6.6665 12.0003 6.6665C11.264 6.6665 10.667 7.26347 10.667 7.99984C10.667 8.7362 11.264 9.33317 12.0003 9.33317C12.7367 9.33317 13.3337 8.7362 13.3337 7.99984Z" fill-rule="nonzero" stroke="rgb(205,205,205)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M6.33301 3.00016L7.99967 1.3335L9.66634 3.00016" fill-rule="nonzero" stroke="rgb(205,205,205)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M8.33333 13.0002L4 9.42123L4 7.3335" fill-rule="nonzero" stroke="rgb(205,205,205)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M12 9.3335L12 10.93L8 13.6668" fill-rule="nonzero" stroke="rgb(205,205,205)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 16" d="M8 1.3335L8 14.3335" stroke="rgb(205,205,205)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 17" d="M7 14.6665L9 14.6665" stroke="rgb(205,205,205)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
12
ui/src/assets/second/usb2.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="数据接口 2" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 11" d="M4.00002 7.33329C4.73639 7.33329 5.33335 6.73633 5.33335 5.99996C5.33335 5.26359 4.73639 4.66663 4.00002 4.66663C3.26364 4.66663 2.66669 5.26359 2.66669 5.99996C2.66669 6.73633 3.26364 7.33329 4.00002 7.33329Z" fill="rgb(0,205,27)" fill-rule="nonzero" />
|
||||
<path id="矢量 11" d="M5.33335 5.99996C5.33335 5.26359 4.73639 4.66663 4.00002 4.66663C3.26364 4.66663 2.66669 5.26359 2.66669 5.99996C2.66669 6.73633 3.26364 7.33329 4.00002 7.33329C4.73639 7.33329 5.33335 6.73633 5.33335 5.99996Z" fill-rule="nonzero" stroke="rgb(0,205,27)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 12" d="M12 9.33329C12.7364 9.33329 13.3334 8.73633 13.3334 7.99996C13.3334 7.26359 12.7364 6.66663 12 6.66663C11.2637 6.66663 10.6667 7.26359 10.6667 7.99996C10.6667 8.73633 11.2637 9.33329 12 9.33329Z" fill="rgb(0,205,27)" fill-rule="nonzero" />
|
||||
<path id="矢量 12" d="M13.3334 7.99996C13.3334 7.26359 12.7364 6.66663 12 6.66663C11.2637 6.66663 10.6667 7.26359 10.6667 7.99996C10.6667 8.73633 11.2637 9.33329 12 9.33329C12.7364 9.33329 13.3334 8.73633 13.3334 7.99996Z" fill-rule="nonzero" stroke="rgb(0,205,27)" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 13" d="M6.33331 3.00004L7.99998 1.33337L9.66665 3.00004" fill-rule="nonzero" stroke="rgb(0,205,27)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 14" d="M8.33333 13L4 9.42111L4 7.33337" fill-rule="nonzero" stroke="rgb(0,205,27)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 15" d="M12 9.33337L12 10.9299L8 13.6667" fill-rule="nonzero" stroke="rgb(0,205,27)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 16" d="M8 1.33337L8 14.3334" stroke="rgb(0,205,27)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 17" d="M7 14.6666L9 14.6666" stroke="rgb(0,205,27)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
8
ui/src/assets/second/vedio.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="电脑 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<rect id="矩形 5" width="3.333334" height="3.000000" x="6.333008" y="10.666504" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<rect id="矩形 6" width="12.666668" height="8.000001" x="1.666992" y="2.666504" rx="0.666667" fill="currentColor" />
|
||||
<rect id="矩形 6" width="12.666668" height="8.000001" x="1.666992" y="2.666504" rx="0.666667" stroke="currentColor" stroke-width="1" />
|
||||
<path id="矢量 80" d="M7.33301 9L8.66634 9" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 81" d="M4.66699 13.6665L11.3337 13.6665" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 966 B |
8
ui/src/assets/second/vedio2.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="电脑 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<rect id="矩形 5" width="3.333334" height="3.000000" x="6.333374" y="10.666748" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<rect id="矩形 6" width="12.666668" height="8.000001" x="1.666626" y="2.666748" rx="0.666667" fill="currentColor" />
|
||||
<rect id="矩形 6" width="12.666668" height="8.000001" x="1.666626" y="2.666748" rx="0.666667" stroke="currentColor" stroke-width="1" />
|
||||
<path id="矢量 80" d="M7.33337 9L8.66671 9" stroke="rgb(26,26,26)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 81" d="M4.66663 13.6667L11.3333 13.6667" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 963 B |
7
ui/src/assets/second/version.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="信息 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 34" d="M12.714 12.714C13.9205 11.5075 14.6667 9.84085 14.6667 7.99992C14.6667 6.15899 13.9205 4.49232 12.714 3.28587C11.5076 2.07945 9.84094 1.33325 8.00001 1.33325C6.15908 1.33325 4.49241 2.07945 3.28596 3.28587C2.07954 4.49232 1.33334 6.15899 1.33334 7.99992C1.33334 9.84085 2.07954 11.5075 3.28596 12.714C4.49241 13.9204 6.15908 14.6666 8.00001 14.6666C9.84094 14.6666 11.5076 13.9204 12.714 12.714Z" fill-rule="nonzero" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 35" d="M7.99999 3.66675C8.46022 3.66675 8.83332 4.03985 8.83332 4.50008C8.83332 4.96031 8.46022 5.33342 7.99999 5.33342C7.53976 5.33342 7.16666 4.96031 7.16666 4.50008C7.16666 4.03985 7.53976 3.66675 7.99999 3.66675Z" fill="currentColor" fill-rule="evenodd" />
|
||||
<path id="矢量 36" d="M8.16667 11.3334L8.16667 6.66675L7.83333 6.66675L7.5 6.66675" fill-rule="nonzero" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 37" d="M7 11.3333L9.33333 11.3333" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
9
ui/src/assets/second/xinhao.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48.000000" height="48.000000" fill="none">
|
||||
<rect id="信号 3" width="48.000000" height="48.000000" x="0.000000" y="0.000000" />
|
||||
<path id="矢量 101" d="M40 6L40 42" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" />
|
||||
<path id="矢量 102" d="M29 16L29 42" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" />
|
||||
<path id="矢量 103" d="M19 26L19 42" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" />
|
||||
<path id="矢量 104" d="M8 36L8 42" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3" />
|
||||
<path id="矢量 105" d="M0.001 0L0 15.5565" stroke="rgb(255,0,0)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="matrix(0.707107,-0.707107,0.707107,0.707107,8,6)" />
|
||||
<path id="矢量 106" d="M0 0L0.001 15.5568" stroke="rgb(255,0,0)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="matrix(0.707107,0.707107,0.707107,-0.707107,7.99963,16.9995)" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
7
ui/src/assets/second/zhongduan.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="终端 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<rect id="矩形 1" width="13.333334" height="10.666668" x="1.333344" y="2.666626" rx="0.666667" fill="currentColor" />
|
||||
<rect id="矩形 1" width="13.333334" height="10.666668" x="1.333344" y="2.666626" rx="0.666667" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 7" d="M4 6L6.33333 8L4 10" fill-rule="nonzero" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 8" d="M7.66666 10.6666L12 10.6666" stroke="rgb(255,255,255)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 836 B |
7
ui/src/assets/second/zhongduan2.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16.000000" height="16.000000" fill="none">
|
||||
<rect id="终端 1" width="16.000002" height="16.000002" x="0.000000" y="0.000000" />
|
||||
<rect id="矩形 1" width="13.333334" height="10.666668" x="1.333344" y="2.666626" rx="0.666667" fill="currentColor" />
|
||||
<rect id="矩形 1" width="13.333334" height="10.666668" x="1.333344" y="2.666626" rx="0.666667" stroke="currentColor" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 7" d="M4 6L6.33333 8L4 10" fill-rule="nonzero" stroke="rgb(26,26,26)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
<path id="矢量 8" d="M7.66666 10.6666L12 10.6666" stroke="rgb(26,26,26)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 830 B |
@@ -1,331 +0,0 @@
|
||||
import { MdOutlineContentPasteGo } from "react-icons/md";
|
||||
import { LuCable, LuHardDrive, LuMaximize, LuSettings, LuSignal } from "react-icons/lu";
|
||||
import { FaKeyboard } from "react-icons/fa6";
|
||||
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
|
||||
import { Fragment, useCallback, useRef, useState, useEffect } from "react";
|
||||
import { CommandLineIcon } from "@heroicons/react/20/solid";
|
||||
|
||||
import { Button } from "@components/Button";
|
||||
import {
|
||||
useHidStore,
|
||||
useMountMediaStore,
|
||||
useSettingsStore,
|
||||
useUiStore,
|
||||
useAudioModeStore,
|
||||
} from "@/hooks/stores";
|
||||
import Container from "@components/Container";
|
||||
import { cx } from "@/cva.config";
|
||||
import PasteModal from "@/components/popovers/PasteModal";
|
||||
import WakeOnLanModal from "@/components/popovers/WakeOnLan/Index";
|
||||
import MountPopopover from "@/components/popovers/MountPopover";
|
||||
import ExtensionPopover from "@/components/popovers/ExtensionPopover";
|
||||
import { useDeviceUiNavigation } from "@/hooks/useAppNavigation";
|
||||
import VolumeControl from "./VolumeControl";
|
||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
import {useReactAt} from 'i18n-auto-extractor/react'
|
||||
|
||||
export default function Actionbar({
|
||||
requestFullscreen,
|
||||
}: {
|
||||
requestFullscreen: () => Promise<void>;
|
||||
}) {
|
||||
const { navigateTo } = useDeviceUiNavigation();
|
||||
const virtualKeyboard = useHidStore(state => state.isVirtualKeyboardEnabled);
|
||||
|
||||
const setVirtualKeyboard = useHidStore(state => state.setVirtualKeyboardEnabled);
|
||||
const toggleSidebarView = useUiStore(state => state.toggleSidebarView);
|
||||
const setDisableFocusTrap = useUiStore(state => state.setDisableVideoFocusTrap);
|
||||
const terminalType = useUiStore(state => state.terminalType);
|
||||
const setTerminalType = useUiStore(state => state.setTerminalType);
|
||||
const remoteVirtualMediaState = useMountMediaStore(
|
||||
state => state.remoteVirtualMediaState,
|
||||
);
|
||||
const developerMode = useSettingsStore(state => state.developerMode);
|
||||
|
||||
// Audio related
|
||||
const [send] = useJsonRpc();
|
||||
const audioMode = useAudioModeStore(state => state.audioMode);
|
||||
const setAudioMode = useAudioModeStore(state => state.setAudioMode);
|
||||
const { $at }= useReactAt();
|
||||
|
||||
// This is the only way to get a reliable state change for the popover
|
||||
// at time of writing this there is no mount, or unmount event for the popover
|
||||
const isOpen = useRef<boolean>(false);
|
||||
const checkIfStateChanged = useCallback(
|
||||
(open: boolean) => {
|
||||
if (open !== isOpen.current) {
|
||||
isOpen.current = open;
|
||||
if (!open) {
|
||||
setTimeout(() => {
|
||||
setDisableFocusTrap(false);
|
||||
console.log("Popover is closing. Returning focus trap to video");
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
[setDisableFocusTrap],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
send("getAudioMode", {}, resp => {
|
||||
if ("error" in resp) return;
|
||||
setAudioMode(String(resp.result));
|
||||
});
|
||||
}, [send]);
|
||||
|
||||
return (
|
||||
<Container className="border-b border-b-slate-800/20 bg-white dark:border-b-slate-300/20 dark:bg-slate-900">
|
||||
<div
|
||||
onKeyUp={e => e.stopPropagation()}
|
||||
onKeyDown={e => e.stopPropagation()}
|
||||
className="flex flex-wrap items-center justify-between gap-x-4 gap-y-2 py-1.5"
|
||||
>
|
||||
<div className="relative flex flex-wrap items-center gap-x-2 gap-y-2">
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={$at("Terminal")}
|
||||
LeadingIcon={({ className }) => <CommandLineIcon className={className} />}
|
||||
onClick={() => setTerminalType(terminalType === "kvm" ? "none" : "kvm")}
|
||||
/>
|
||||
<Popover>
|
||||
<PopoverButton as={Fragment}>
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={$at("Paste Text")}
|
||||
LeadingIcon={MdOutlineContentPasteGo}
|
||||
onClick={() => {
|
||||
setDisableFocusTrap(true);
|
||||
}}
|
||||
/>
|
||||
</PopoverButton>
|
||||
<PopoverPanel
|
||||
anchor="bottom start"
|
||||
transition
|
||||
className={cx(
|
||||
"z-10 flex w-[420px] origin-top flex-col overflow-visible!",
|
||||
"flex origin-top flex-col transition duration-300 ease-out data-closed:translate-y-8 data-closed:opacity-0",
|
||||
)}
|
||||
>
|
||||
{({ open }) => {
|
||||
checkIfStateChanged(open);
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-xl">
|
||||
<PasteModal />
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</PopoverPanel>
|
||||
</Popover>
|
||||
<div className="relative">
|
||||
<Popover>
|
||||
<PopoverButton as={Fragment}>
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={$at("Virtual Media")}
|
||||
LeadingIcon={({ className }) => {
|
||||
return (
|
||||
<>
|
||||
<LuHardDrive className={className} />
|
||||
{/*<div
|
||||
className={cx(className, "h-2 w-2 rounded-full bg-blue-700", {
|
||||
hidden: !remoteVirtualMediaState,
|
||||
})}
|
||||
/>*/}
|
||||
</>
|
||||
);
|
||||
}}
|
||||
onClick={() => {
|
||||
setDisableFocusTrap(true);
|
||||
}}
|
||||
/>
|
||||
</PopoverButton>
|
||||
<PopoverPanel
|
||||
anchor="bottom start"
|
||||
transition
|
||||
className={cx(
|
||||
"z-10 flex w-[420px] origin-top flex-col overflow-visible!",
|
||||
"flex origin-top flex-col transition duration-300 ease-out data-closed:translate-y-8 data-closed:opacity-0",
|
||||
)}
|
||||
>
|
||||
{({ open }) => {
|
||||
checkIfStateChanged(open);
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-xl">
|
||||
<MountPopopover />
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</PopoverPanel>
|
||||
</Popover>
|
||||
</div>
|
||||
<div>
|
||||
<Popover>
|
||||
<PopoverButton as={Fragment}>
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={$at("Wake")}
|
||||
onClick={() => {
|
||||
setDisableFocusTrap(true);
|
||||
}}
|
||||
LeadingIcon={({ className }) => (
|
||||
<svg
|
||||
className={className}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
>
|
||||
<path d="m15 20 3-3h2a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h2l3 3z" />
|
||||
<path d="M6 8v1" />
|
||||
<path d="M10 8v1" />
|
||||
<path d="M14 8v1" />
|
||||
<path d="M18 8v1" />
|
||||
</svg>
|
||||
)}
|
||||
/>
|
||||
</PopoverButton>
|
||||
<PopoverPanel
|
||||
anchor="bottom start"
|
||||
transition
|
||||
style={{
|
||||
transitionProperty: "opacity",
|
||||
}}
|
||||
className={cx(
|
||||
"z-10 flex w-[420px] origin-top flex-col overflow-visible!",
|
||||
"flex origin-top flex-col transition duration-300 ease-out data-closed:translate-y-8 data-closed:opacity-0",
|
||||
)}
|
||||
>
|
||||
{({ open }) => {
|
||||
checkIfStateChanged(open);
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-xl">
|
||||
<WakeOnLanModal />
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</PopoverPanel>
|
||||
</Popover>
|
||||
</div>
|
||||
<div className="hidden lg:block">
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={$at("Virtual Keyboard")}
|
||||
LeadingIcon={FaKeyboard}
|
||||
onClick={() => setVirtualKeyboard(!virtualKeyboard)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{(audioMode !== "disabled") && (
|
||||
<div className="hidden lg:block">
|
||||
<VolumeControl
|
||||
size="XS"
|
||||
theme="light"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-2">
|
||||
<Popover>
|
||||
<PopoverButton as={Fragment}>
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={$at("Extensions")}
|
||||
LeadingIcon={LuCable}
|
||||
onClick={() => {
|
||||
setDisableFocusTrap(true);
|
||||
}}
|
||||
/>
|
||||
</PopoverButton>
|
||||
<PopoverPanel
|
||||
anchor="bottom start"
|
||||
transition
|
||||
className={cx(
|
||||
"z-10 flex w-[420px] flex-col overflow-visible!",
|
||||
"flex origin-top flex-col transition duration-300 ease-out data-closed:translate-y-8 data-closed:opacity-0",
|
||||
)}
|
||||
>
|
||||
{({ open }) => {
|
||||
checkIfStateChanged(open);
|
||||
return <ExtensionPopover />;
|
||||
}}
|
||||
</PopoverPanel>
|
||||
</Popover>
|
||||
|
||||
<div className="block lg:hidden">
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={$at("Virtual Keyboard")}
|
||||
LeadingIcon={FaKeyboard}
|
||||
onClick={() => setVirtualKeyboard(!virtualKeyboard)}
|
||||
/>
|
||||
</div>
|
||||
<div className="hidden md:block">
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={$at("Connection")}
|
||||
LeadingIcon={({ className }) => (
|
||||
<LuSignal
|
||||
className={cx(className, "mb-0.5 text-green-500")}
|
||||
strokeWidth={4}
|
||||
/>
|
||||
)}
|
||||
onClick={() => {
|
||||
toggleSidebarView("connection-stats");
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/* {useSettingsStore().actionBarCtrlAltDel && (
|
||||
<div className="hidden lg:block">
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text="Ctrl + Alt + Del"
|
||||
LeadingIcon={FaLock}
|
||||
onClick={() => {
|
||||
sendKeyboardEvent(
|
||||
[keys["Delete"]],
|
||||
[modifiers["ControlLeft"], modifiers["AltLeft"]],
|
||||
);
|
||||
setTimeout(resetKeyboardState, 100);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)} */}
|
||||
<div>
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={$at("Settings")}
|
||||
LeadingIcon={LuSettings}
|
||||
onClick={() => navigateTo("/settings")}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="hidden items-center gap-x-2 lg:flex">
|
||||
<div className="h-4 w-px bg-slate-300 dark:bg-slate-600" />
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
text={$at("Fullscreen")}
|
||||
LeadingIcon={LuMaximize}
|
||||
onClick={() => requestFullscreen()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
79
ui/src/components/AdaptiveContainer.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||
|
||||
interface AdaptiveContainerProps {
|
||||
children: React.ReactNode;
|
||||
minHeight?: number | string;
|
||||
onKeyboardShow?: () => void;
|
||||
onKeyboardHide?: () => void;
|
||||
style?: React.CSSProperties;
|
||||
differenceRange?: number;
|
||||
}
|
||||
|
||||
const AdaptiveContainer: React.FC<AdaptiveContainerProps> = ({
|
||||
children,
|
||||
minHeight = 0,
|
||||
onKeyboardShow,
|
||||
onKeyboardHide,
|
||||
style = {},
|
||||
differenceRange = 50
|
||||
}) => {
|
||||
const [containerHeight, setContainerHeight] = useState<string | number>('100%');
|
||||
const [isKeyboardVisible, setIsKeyboardVisible] = useState(false);
|
||||
const originalHeight = useRef<number>(0);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const initHeight = useCallback(() => {
|
||||
originalHeight.current = document.documentElement.clientHeight || document.body.clientHeight;
|
||||
setContainerHeight('100%');
|
||||
}, []);
|
||||
|
||||
const handleResize = useCallback(() => {
|
||||
const currentHeight = document.documentElement.clientHeight || document.body.clientHeight;
|
||||
if (Math.abs(originalHeight.current - currentHeight) > differenceRange) {
|
||||
if (currentHeight < originalHeight.current) {
|
||||
setContainerHeight(currentHeight);
|
||||
setIsKeyboardVisible(true);
|
||||
onKeyboardShow?.();
|
||||
console.log("currentHeight = ",currentHeight)
|
||||
}
|
||||
} else {
|
||||
|
||||
if (isKeyboardVisible) {
|
||||
setContainerHeight('100%');
|
||||
setIsKeyboardVisible(false);
|
||||
onKeyboardHide?.();
|
||||
}
|
||||
originalHeight.current = currentHeight;
|
||||
}
|
||||
}, [differenceRange, isKeyboardVisible, onKeyboardShow, onKeyboardHide]);
|
||||
|
||||
useEffect(() => {
|
||||
initHeight();
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
};
|
||||
}, [initHeight, handleResize]);
|
||||
|
||||
const containerStyle: React.CSSProperties = {
|
||||
height: containerHeight,
|
||||
minHeight,
|
||||
overflow: 'auto',
|
||||
WebkitOverflowScrolling: 'touch',
|
||||
transition: 'height 0.3s ease',
|
||||
...style
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
style={containerStyle}
|
||||
className="adaptive-container"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AdaptiveContainer;
|
||||
@@ -1,66 +0,0 @@
|
||||
import { useLocation, useNavigation, useSearchParams } from "react-router-dom";
|
||||
|
||||
import { Button, LinkButton } from "@components/Button";
|
||||
import { GoogleIcon } from "@components/Icons";
|
||||
import SimpleNavbar from "@components/SimpleNavbar";
|
||||
import Container from "@components/Container";
|
||||
import Fieldset from "@components/Fieldset";
|
||||
import GridBackground from "@components/GridBackground";
|
||||
import StepCounter from "@components/StepCounter";
|
||||
|
||||
interface AuthLayoutProps {
|
||||
title: string;
|
||||
description: string;
|
||||
cta: string;
|
||||
ctaHref: string;
|
||||
showCounter?: boolean;
|
||||
}
|
||||
|
||||
export default function AuthLayout({
|
||||
title,
|
||||
description,
|
||||
cta,
|
||||
ctaHref,
|
||||
showCounter,
|
||||
}: AuthLayoutProps) {
|
||||
const [sq] = useSearchParams();
|
||||
const location = useLocation();
|
||||
|
||||
const returnTo = sq.get("returnTo") || location.state?.returnTo;
|
||||
const deviceId = sq.get("deviceId") || location.state?.deviceId;
|
||||
const navigation = useNavigation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<GridBackground />
|
||||
|
||||
<div className="grid min-h-screen grid-rows-(--grid-layout)">
|
||||
<SimpleNavbar
|
||||
logoHref="/"
|
||||
actionElement={
|
||||
<div>
|
||||
<LinkButton to={ctaHref} text={cta} theme="light" size="MD" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<Container>
|
||||
<div className="isolate flex h-full w-full items-center justify-center">
|
||||
<div className="-mt-16 max-w-2xl space-y-8">
|
||||
{showCounter ? (
|
||||
<div className="text-center">
|
||||
<StepCounter currStepIdx={0} nSteps={2} />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="space-y-2 text-center">
|
||||
<h1 className="text-4xl font-semibold text-black dark:text-white">
|
||||
{title}
|
||||
</h1>
|
||||
<p className="text-slate-600 dark:text-slate-400">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
import React, { JSX } from "react";
|
||||
import { FetcherWithComponents, Link, LinkProps, useNavigation } from "react-router-dom";
|
||||
|
||||
import ExtLink from "@/components/ExtLink";
|
||||
import LoadingSpinner from "@/components/LoadingSpinner";
|
||||
import ExtLink from "@components/ExtLink";
|
||||
import LoadingSpinner from "@components/LoadingSpinner";
|
||||
import { cva, cx } from "@/cva.config";
|
||||
import { button_primary_color } from "@/layout/theme_color";
|
||||
|
||||
const sizes = {
|
||||
SS: "h-[24px] px-2 text-xs",
|
||||
XS: "h-[28px] px-2 text-xs",
|
||||
SM: "h-[36px] px-3 text-[13px]",
|
||||
MD: "h-[40px] px-3.5 text-sm",
|
||||
@@ -15,8 +17,8 @@ const sizes = {
|
||||
|
||||
const themes = {
|
||||
primary: cx(
|
||||
// Base styles
|
||||
"bg-blue-700 dark:border-blue-600 border border-blue-900/60 text-white shadow-sm",
|
||||
// Base styles bg-blue-700
|
||||
`${button_primary_color} dark:border-blue-600 border border-transparent text-white shadow-sm`,
|
||||
// Hover states
|
||||
"group-hover:bg-blue-800",
|
||||
// Active states
|
||||
@@ -73,7 +75,7 @@ const btnVariants = cva({
|
||||
// Text classes
|
||||
"font-display text-center font-medium leading-tight",
|
||||
// States
|
||||
"group-focus:outline-hidden group-focus:ring-2 group-focus:ring-offset-2 group-focus:ring-blue-700",
|
||||
"group-focus:outline-hidden group-focus:ring-2 group-focus:ring-offset-2 group-focus:ring-blue-400 dark:group-focus:ring-blue-700",
|
||||
"group-disabled:opacity-50 group-disabled:pointer-events-none",
|
||||
),
|
||||
|
||||
@@ -86,6 +88,7 @@ const btnVariants = cva({
|
||||
const iconVariants = cva({
|
||||
variants: {
|
||||
size: {
|
||||
SS: "h-2.5",
|
||||
XS: "h-3.5",
|
||||
SM: "h-3.5",
|
||||
MD: "h-5",
|
||||
@@ -112,23 +115,41 @@ interface ButtonContentPropsType {
|
||||
size: keyof typeof sizes;
|
||||
theme: keyof typeof themes;
|
||||
loading?: boolean;
|
||||
hideBorder?: boolean;
|
||||
}
|
||||
|
||||
function ButtonContent(props: ButtonContentPropsType) {
|
||||
const { text, LeadingIcon, TrailingIcon, fullWidth, className, textAlign, loading } =
|
||||
props;
|
||||
const {
|
||||
text,
|
||||
LeadingIcon,
|
||||
TrailingIcon,
|
||||
fullWidth,
|
||||
className,
|
||||
textAlign,
|
||||
loading,
|
||||
hideBorder
|
||||
} = props;
|
||||
|
||||
// Based on the size prop, we'll use the corresponding variant classnames
|
||||
const iconClassName = iconVariants(props);
|
||||
const btnClassName = btnVariants(props);
|
||||
|
||||
return (
|
||||
<div className={cx(className, fullWidth ? "flex" : "inline-flex", btnClassName)}>
|
||||
<div
|
||||
className={cx(
|
||||
className,
|
||||
fullWidth ? "flex" : "inline-flex",
|
||||
btnClassName,
|
||||
hideBorder ? "border-none" : ""
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cx(
|
||||
"flex w-full min-w-0 items-center gap-x-1.5 text-center",
|
||||
textAlign === "left" ? "text-left!" : "",
|
||||
textAlign === "center" ? "text-center!" : "",
|
||||
textAlign === "right" ? "text-right!" : "",
|
||||
hideBorder ? "border-0" : ""
|
||||
)}
|
||||
>
|
||||
{loading ? (
|
||||
@@ -137,7 +158,7 @@ function ButtonContent(props: ButtonContentPropsType) {
|
||||
</div>
|
||||
) : (
|
||||
LeadingIcon && (
|
||||
<LeadingIcon className={cx(iconClassName, "shrink-0 justify-start")} />
|
||||
<LeadingIcon className={cx(iconClassName, "shrink-0 justify-start","dark:text-white")} />
|
||||
)
|
||||
)}
|
||||
|
||||
@@ -154,7 +175,6 @@ function ButtonContent(props: ButtonContentPropsType) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type ButtonPropsType = Pick<
|
||||
JSX.IntrinsicElements["button"],
|
||||
| "type"
|
||||
@@ -169,25 +189,30 @@ type ButtonPropsType = Pick<
|
||||
| "onMouseLeave"
|
||||
> &
|
||||
React.ComponentProps<typeof ButtonContent> & {
|
||||
fetcher?: FetcherWithComponents<unknown>;
|
||||
};
|
||||
|
||||
fetcher?: FetcherWithComponents<unknown>;
|
||||
hideBorder?: boolean;
|
||||
className?: string;
|
||||
};
|
||||
export const Button = React.forwardRef<HTMLButtonElement, ButtonPropsType>(
|
||||
({ type, disabled, onClick, formNoValidate, loading, fetcher, ...props }, ref) => {
|
||||
({ className,type, onClick, formNoValidate, loading, fetcher, hideBorder, ...props }, ref) => {
|
||||
const classes = cx(
|
||||
"group outline-hidden",
|
||||
props.fullWidth ? "w-full" : "",
|
||||
loading ? "pointer-events-none" : "",
|
||||
hideBorder ? "border-none" : "",
|
||||
className
|
||||
);
|
||||
|
||||
const navigation = useNavigation();
|
||||
const loader = fetcher ? fetcher : navigation;
|
||||
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
formNoValidate={formNoValidate}
|
||||
className={classes}
|
||||
type={type}
|
||||
disabled={disabled}
|
||||
disabled={false}
|
||||
onClick={onClick}
|
||||
onMouseDown={props?.onMouseDown}
|
||||
onMouseUp={props?.onMouseUp}
|
||||
@@ -197,6 +222,7 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonPropsType>(
|
||||
>
|
||||
<ButtonContent
|
||||
{...props}
|
||||
hideBorder={hideBorder}
|
||||
loading={
|
||||
loading ??
|
||||
(type === "submit" &&
|
||||
@@ -209,6 +235,7 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonPropsType>(
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
Button.displayName = "Button";
|
||||
|
||||
type LinkPropsType = Pick<LinkProps, "to"> &
|
||||
@@ -255,4 +282,4 @@ export const LabelButton = ({ htmlFor, ...props }: LabelPropsType) => {
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
@@ -1,12 +1,13 @@
|
||||
import React, { forwardRef } from "react";
|
||||
|
||||
import { cx } from "@/cva.config";
|
||||
import { dark_bg2_style } from "@/layout/theme_color";
|
||||
|
||||
interface CardPropsType {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
//bg-linear-to-tr
|
||||
export const GridCard = ({
|
||||
children,
|
||||
cardClassName,
|
||||
@@ -15,11 +16,11 @@ export const GridCard = ({
|
||||
cardClassName?: string;
|
||||
}) => {
|
||||
return (
|
||||
<Card className={cx("overflow-hidden", cardClassName)}>
|
||||
<Card className={cx(`overflow-hidden ${dark_bg2_style}`, cardClassName)}>
|
||||
<div className="relative h-full">
|
||||
<div className="absolute inset-0 z-0 h-full w-full bg-linear-to-tr from-blue-50/30 to-blue-50/20 transition-colors duration-300 ease-in-out dark:from-slate-800/30 dark:to-slate-800/20" />
|
||||
<div className="absolute inset-0 z-0 h-full w-full rotate-0 bg-grid-blue-100/25 dark:bg-grid-slate-700/7" />
|
||||
<div className="isolate h-full">{children}</div>
|
||||
<div className="absolute inset-0 z-0 h-full w-full from-blue-50/30 to-blue-50/20 transition-colors duration-300 ease-in-out dark:from-slate-800/30 dark:to-slate-800/20" />
|
||||
<div className="absolute inset-0 z-0 h-full w-full rotate-0" />
|
||||
<div className="isolate h-full w-full">{children}</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
@@ -30,7 +31,7 @@ const Card = forwardRef<HTMLDivElement, CardPropsType>(({ children, className },
|
||||
<div
|
||||
ref={ref}
|
||||
className={cx(
|
||||
"w-full rounded-sm border-none bg-white shadow-xs outline-1 outline-slate-800/30 dark:bg-slate-800 dark:outline-slate-300/20",
|
||||
"w-full rounded-sm border-none shadow-xs outline-1 outline-slate-800/30 dark:outline-slate-300/20",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
headline: string;
|
||||
description?: string | React.ReactNode;
|
||||
Button?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const CardHeader = ({ headline, description, Button }: Props) => {
|
||||
return (
|
||||
<div className="flex items-center justify-between pb-0 gap-x-4">
|
||||
<div className="space-y-1 grow">
|
||||
<h3 className="text-lg font-bold leading-none text-black dark:text-white">{headline}</h3>
|
||||
{description && <div className="text-sm text-slate-700 dark:text-slate-300">{description}</div>}
|
||||
</div>
|
||||
{Button && <div>{Button}</div>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,80 +0,0 @@
|
||||
import type { Ref } from "react";
|
||||
import React, { forwardRef, JSX } from "react";
|
||||
import clsx from "clsx";
|
||||
|
||||
import FieldLabel from "@/components/FieldLabel";
|
||||
import { cva, cx } from "@/cva.config";
|
||||
|
||||
const sizes = {
|
||||
SM: "w-4 h-4",
|
||||
MD: "w-5 h-5",
|
||||
};
|
||||
|
||||
const checkboxVariants = cva({
|
||||
base: cx(
|
||||
"form-checkbox block rounded",
|
||||
|
||||
// Colors
|
||||
"border-slate-300 dark:border-slate-600 bg-slate-50 dark:bg-slate-800 checked:accent-blue-700 checked:dark:accent-blue-500 transition-colors",
|
||||
|
||||
// Hover
|
||||
"hover:bg-slate-200/50 dark:hover:bg-slate-700/50",
|
||||
|
||||
// Active
|
||||
"active:bg-slate-200 dark:active:bg-slate-700",
|
||||
|
||||
// Focus
|
||||
"focus:border-slate-300 dark:focus:border-slate-600 focus:outline-hidden focus:ring-2 focus:ring-blue-700 dark:focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-slate-900",
|
||||
|
||||
// Disabled
|
||||
"disabled:pointer-events-none disabled:opacity-30",
|
||||
),
|
||||
variants: { size: sizes },
|
||||
});
|
||||
|
||||
type CheckBoxProps = {
|
||||
size?: keyof typeof sizes;
|
||||
} & Omit<JSX.IntrinsicElements["input"], "size" | "type">;
|
||||
|
||||
const Checkbox = forwardRef<HTMLInputElement, CheckBoxProps>(function Checkbox(
|
||||
{ size = "MD", className, ...props },
|
||||
ref,
|
||||
) {
|
||||
const classes = checkboxVariants({ size });
|
||||
return (
|
||||
<input ref={ref} {...props} type="checkbox" className={clsx(classes, className)} />
|
||||
);
|
||||
});
|
||||
Checkbox.displayName = "Checkbox";
|
||||
|
||||
type CheckboxWithLabelProps = React.ComponentProps<typeof FieldLabel> &
|
||||
CheckBoxProps & {
|
||||
fullWidth?: boolean;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const CheckboxWithLabel = forwardRef<HTMLInputElement, CheckboxWithLabelProps>(
|
||||
function CheckboxWithLabel(
|
||||
{ label, id, description, fullWidth, readOnly, ...props },
|
||||
ref: Ref<HTMLInputElement>,
|
||||
) {
|
||||
return (
|
||||
<label
|
||||
className={clsx(
|
||||
"flex shrink-0 items-center justify-between gap-x-2",
|
||||
fullWidth ? "flex" : "inline-flex",
|
||||
readOnly ? "pointer-events-none opacity-50" : "",
|
||||
)}
|
||||
>
|
||||
<Checkbox ref={ref as never} {...props} />
|
||||
<div className="max-w-md">
|
||||
<FieldLabel label={label} id={id} description={description} as="span" />
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
},
|
||||
);
|
||||
CheckboxWithLabel.displayName = "CheckboxWithLabel";
|
||||
|
||||
export default Checkbox;
|
||||
export { CheckboxWithLabel, Checkbox };
|
||||
@@ -3,9 +3,12 @@ import {
|
||||
ExclamationTriangleIcon,
|
||||
InformationCircleIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { Dialog, DialogBackdrop, DialogPanel } from "@headlessui/react";
|
||||
import React from "react";
|
||||
|
||||
import { Button } from "@/components/Button";
|
||||
import Modal from "@/components/Modal";
|
||||
import { Button } from "@components/Button";
|
||||
import Modal from "@components/Modal";
|
||||
import { cx } from "@/cva.config";
|
||||
|
||||
type Variant = "danger" | "success" | "warning" | "info";
|
||||
@@ -70,10 +73,73 @@ export function ConfirmDialog({
|
||||
}: ConfirmDialogProps) {
|
||||
const { icon: Icon, iconClass, iconBgClass, buttonTheme } = variantConfig[variant];
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
if (isMobile) {
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose} className="relative z-[99999]">
|
||||
<DialogBackdrop
|
||||
transition
|
||||
className="fixed inset-0 bg-gray-500/75 transition-opacity data-closed:opacity-0 data-enter:duration-300 data-leave:duration-200 data-enter:ease-out data-leave:ease-in dark:bg-slate-900/90"
|
||||
/>
|
||||
<div className="fixed inset-0 z-[99999] w-screen overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4">
|
||||
<DialogPanel
|
||||
transition
|
||||
className="relative w-full max-w-sm transform overflow-hidden rounded-lg bg-white p-6 text-left shadow-xl transition-all data-closed:translate-y-4 data-closed:opacity-0 data-enter:duration-300 data-leave:duration-200 data-enter:ease-out data-leave:ease-in dark:bg-[rgb(26,26,26)]"
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-col items-center text-center">
|
||||
<div
|
||||
className={cx(
|
||||
"mx-auto flex size-12 shrink-0 items-center justify-center rounded-full",
|
||||
iconBgClass,
|
||||
)}
|
||||
>
|
||||
<Icon aria-hidden="true" className={cx("size-6", iconClass)} />
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<h2 className="text-lg font-bold leading-6 text-gray-900 dark:text-white">
|
||||
{title}
|
||||
</h2>
|
||||
<div className="mt-2">
|
||||
<div className="text-sm text-gray-500 dark:text-gray-300">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-6 sm:grid sm:grid-flow-row-dense sm:grid-cols-2 sm:gap-3">
|
||||
<Button
|
||||
size="LG"
|
||||
theme={buttonTheme}
|
||||
text={isConfirming ? `${confirmText}...` : confirmText}
|
||||
onClick={onConfirm}
|
||||
disabled={isConfirming}
|
||||
className="w-full justify-center"
|
||||
/>
|
||||
{cancelText && (
|
||||
<Button
|
||||
size="LG"
|
||||
theme="light"
|
||||
text={cancelText}
|
||||
onClick={onClose}
|
||||
className="mt-3 w-full justify-center sm:mt-0"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</DialogPanel>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={onClose}>
|
||||
<div className="mx-auto max-w-xl px-4 transition-all duration-300 ease-in-out">
|
||||
<div className="pointer-events-auto relative w-full overflow-hidden rounded-lg bg-white p-6 text-left align-middle shadow-xl transition-all dark:bg-slate-800">
|
||||
<div className="pointer-events-auto relative w-full overflow-hidden rounded-lg bg-white p-6 text-left align-middle shadow-xl transition-all dark:bg-[rgb(26,26,26)]">
|
||||
<div className="space-y-4">
|
||||
<div className="sm:flex sm:items-start">
|
||||
<div
|
||||
@@ -88,7 +154,7 @@ export function ConfirmDialog({
|
||||
<h2 className="text-lg leading-tight font-bold text-black dark:text-white">
|
||||
{title}
|
||||
</h2>
|
||||
<div className="mt-2 text-sm leading-snug text-slate-600 dark:text-slate-400">
|
||||
<div className="mt-2 text-sm leading-snug text-slate-600 dark:text-[#ffffff]">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
@@ -96,7 +162,7 @@ export function ConfirmDialog({
|
||||
|
||||
<div className="flex justify-end gap-x-2">
|
||||
{cancelText && (
|
||||
<Button size="SM" theme="blank" text={cancelText} onClick={onClose} />
|
||||
<Button size="SM" theme="light" text={cancelText} onClick={onClose} />
|
||||
)}
|
||||
<Button
|
||||
size="SM"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useInterval } from "usehooks-ts";
|
||||
|
||||
import SidebarHeader from "@/components/SidebarHeader";
|
||||
import { GridCard } from "@/components/Card";
|
||||
import { useRTCStore, useUiStore } from "@/hooks/stores";
|
||||
import StatChart from "@/components/StatChart";
|
||||
import {useReactAt} from 'i18n-auto-extractor/react'
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import { GridCard } from "@components/Card";
|
||||
import { useRTCStore, useUiStore } from "@/hooks/stores";
|
||||
import StatChart from "@components/StatChart";
|
||||
|
||||
function createChartArray<T, K extends keyof T>(
|
||||
stream: Map<number, T>,
|
||||
@@ -39,9 +39,7 @@ function createChartArray<T, K extends keyof T>(
|
||||
|
||||
export default function ConnectionStatsSidebar() {
|
||||
const inboundRtpStats = useRTCStore(state => state.inboundRtpStats);
|
||||
|
||||
const candidatePairStats = useRTCStore(state => state.candidatePairStats);
|
||||
const setSidebarView = useUiStore(state => state.setSidebarView);
|
||||
|
||||
function isMetricSupported<T, K extends keyof T>(
|
||||
stream: Map<number, T>,
|
||||
@@ -100,17 +98,18 @@ export default function ConnectionStatsSidebar() {
|
||||
})();
|
||||
}, 500);
|
||||
|
||||
|
||||
return (
|
||||
<div className="grid h-full grid-rows-(--grid-headerBody) shadow-xs">
|
||||
<SidebarHeader title={$at("Connection Stats")} setSidebarView={setSidebarView} />
|
||||
<div className="h-full space-y-4 overflow-y-scroll bg-white px-4 py-2 pb-8 dark:bg-slate-900">
|
||||
{/*<SidebarHeader title={$at("Connection Stats")} setSidebarView={setSidebarView} />*/}
|
||||
<div className="h-full space-y-4 px-0 py-2 pb-8">
|
||||
<div className="space-y-4">
|
||||
{/*
|
||||
The entire sidebar component is always rendered, with a display none when not visible
|
||||
The charts below, need a height and width, otherwise they throw. So simply don't render them unless the thing is visible
|
||||
*/}
|
||||
{sidebarView === "connection-stats" && (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-4 px-0.5">
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-black dark:text-white">
|
||||
@@ -121,7 +120,7 @@ export default function ConnectionStatsSidebar() {
|
||||
</p>
|
||||
</div>
|
||||
<GridCard>
|
||||
<div className="flex h-[127px] w-full items-center justify-center text-sm text-slate-500">
|
||||
<div className="flex h-[153px] w-full items-center justify-center text-sm text-slate-500">
|
||||
{inboundRtpStats.size === 0 ? (
|
||||
<div className="flex flex-col items-center space-y-1">
|
||||
<p className="text-slate-700">Waiting for data...</p>
|
||||
@@ -130,7 +129,7 @@ export default function ConnectionStatsSidebar() {
|
||||
<StatChart
|
||||
data={createChartArray(inboundRtpStats, "packetsLost")}
|
||||
domain={[0, 100]}
|
||||
unit=" packets"
|
||||
unit="packets"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex flex-col items-center space-y-1">
|
||||
@@ -242,6 +241,7 @@ export default function ConnectionStatsSidebar() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{isMobile&&<div className="h-[30px]"></div>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -1,10 +1,9 @@
|
||||
/* eslint-disable react-refresh/only-export-components */
|
||||
import React, { ReactNode } from "react";
|
||||
|
||||
import { cx } from "@/cva.config";
|
||||
|
||||
function Container({ children, className }: { children: ReactNode; className?: string }) {
|
||||
return <div className={cx("mx-auto h-full w-full px-8 ", className)}>{children}</div>;
|
||||
return <div className={cx("mx-auto h-full w-full px-4 ", className)}>{children}</div>;
|
||||
}
|
||||
|
||||
function Article({ children }: { children: React.ReactNode }) {
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
import { LuRefreshCcw } from "react-icons/lu";
|
||||
|
||||
import { Button } from "@/components/Button";
|
||||
import { GridCard } from "@/components/Card";
|
||||
import { LifeTimeLabel } from "@/routes/devices.$id.settings.network";
|
||||
import { NetworkState } from "@/hooks/stores";
|
||||
import {useReactAt} from 'i18n-auto-extractor/react'
|
||||
|
||||
export default function DhcpLeaseCard({
|
||||
networkState,
|
||||
setShowRenewLeaseConfirm,
|
||||
}: {
|
||||
networkState: NetworkState;
|
||||
setShowRenewLeaseConfirm: (show: boolean) => void;
|
||||
}) {
|
||||
const { $at }= useReactAt();
|
||||
return (
|
||||
<GridCard>
|
||||
<div className="animate-fadeIn p-4 opacity-0 animation-duration-500 text-black dark:text-white">
|
||||
<div className="space-y-3">
|
||||
<h3 className="text-base font-bold text-slate-900 dark:text-white">
|
||||
{$at("DHCP Lease Information")}
|
||||
</h3>
|
||||
|
||||
<div className="flex gap-x-6 gap-y-2">
|
||||
<div className="flex-1 space-y-2">
|
||||
{networkState?.dhcp_lease?.ip && (
|
||||
<div className="flex justify-between border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("IP Address")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ip}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.netmask && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("Subnet Mask")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.netmask}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.dns && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("DNS Servers")}
|
||||
</span>
|
||||
<span className="text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.dns.map(dns => <div key={dns}>{dns}</div>)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.broadcast && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("Broadcast Address")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.broadcast}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.domain && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("Domain")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.domain}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.ntp_servers &&
|
||||
networkState?.dhcp_lease?.ntp_servers.length > 0 && (
|
||||
<div className="flex justify-between gap-x-8 border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<div className="w-full grow text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("NTP Servers")}
|
||||
</div>
|
||||
<div className="shrink text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ntp_servers.map(server => (
|
||||
<div key={server}>{server}</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.hostname && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("Hostname")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.hostname}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex-1 space-y-2">
|
||||
{networkState?.dhcp_lease?.routers &&
|
||||
networkState?.dhcp_lease?.routers.length > 0 && (
|
||||
<div className="flex justify-between pt-2">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("Gateways")}
|
||||
</span>
|
||||
<span className="text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.routers.map(router => (
|
||||
<div key={router}>{router}</div>
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.server_id && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("DHCP Server")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.server_id}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.lease_expiry && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("Lease Expiry")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
<LifeTimeLabel
|
||||
lifetime={`${networkState?.dhcp_lease?.lease_expiry}`}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.mtu && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">MTU</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.mtu}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.ttl && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">TTL</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ttl}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.bootp_next_server && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("Boot Next Server")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_next_server}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.bootp_server_name && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("Boot Server Name")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_server_name}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.bootp_file && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
{$at("Boot File")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_file}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Button
|
||||
size="SM"
|
||||
theme="light"
|
||||
className="text-red-500"
|
||||
text={$at("Renew DHCP Lease")}
|
||||
LeadingIcon={LuRefreshCcw}
|
||||
onClick={() => setShowRenewLeaseConfirm(true)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GridCard>
|
||||
);
|
||||
}
|
||||
299
ui/src/components/Drawer.tsx
Normal file
@@ -0,0 +1,299 @@
|
||||
import React, { useState, useEffect, useRef, ReactNode, CSSProperties } from 'react';
|
||||
import { createStyles } from 'antd-style';
|
||||
|
||||
import { dark_bg2_style } from "@/layout/theme_color";
|
||||
|
||||
interface DrawerProps {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
children: ReactNode;
|
||||
bottomOffset?: number;
|
||||
height?: number | string;
|
||||
mask?: boolean;
|
||||
maskClosable?: boolean;
|
||||
style?: CSSProperties;
|
||||
className?: string;
|
||||
maskStyle?: CSSProperties;
|
||||
title?: ReactNode;
|
||||
closable?: boolean;
|
||||
closeIcon?: ReactNode;
|
||||
afterOpen?: () => void;
|
||||
afterClose?: () => void;
|
||||
placement?: 'bottom' | 'right' | 'left' | 'top';
|
||||
width?: number | string;
|
||||
getContainer?: HTMLElement | false;
|
||||
}
|
||||
|
||||
const useStyles = createStyles(({ css }) => ({
|
||||
drawerContainer: css`
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
`,
|
||||
drawerContainerAbsolute: css`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
`,
|
||||
drawerMask: css`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.45);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s;
|
||||
pointer-events: auto;
|
||||
`,
|
||||
drawerMaskVisible: css`
|
||||
opacity: 1;
|
||||
`,
|
||||
drawerContentWrapper: css`
|
||||
position: absolute;
|
||||
background: #fff;
|
||||
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.15);
|
||||
transition: transform 0.3s cubic-bezier(0.23, 1, 0.32, 1);
|
||||
pointer-events: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`,
|
||||
// Bottom specific styles
|
||||
drawerWrapperBottom: css`
|
||||
left: 0;
|
||||
width: 100%;
|
||||
transform: translateY(100%);
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
`,
|
||||
drawerOpenBottom: css`
|
||||
transform: translateY(0);
|
||||
`,
|
||||
// Right specific styles
|
||||
drawerWrapperRight: css`
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
transform: translateX(100%);
|
||||
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
|
||||
`,
|
||||
drawerOpenRight: css`
|
||||
transform: translateX(0);
|
||||
`,
|
||||
// Left specific styles
|
||||
drawerWrapperLeft: css`
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
transform: translateX(-100%);
|
||||
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);
|
||||
`,
|
||||
drawerOpenLeft: css`
|
||||
transform: translateX(0);
|
||||
`,
|
||||
// Top specific styles
|
||||
drawerWrapperTop: css`
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
transform: translateY(-100%);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
`,
|
||||
drawerOpenTop: css`
|
||||
transform: translateY(0);
|
||||
`,
|
||||
drawerHeader: css`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 4px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
background: #fff;
|
||||
border-radius: 8px 8px 0 0;
|
||||
flex-shrink: 0;
|
||||
`,
|
||||
drawerTitle: css`
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
flex: 1;
|
||||
`,
|
||||
drawerClose: css`
|
||||
line-height: 1;
|
||||
text-align: center;
|
||||
text-transform: none;
|
||||
text-decoration: none;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
cursor: pointer;
|
||||
transition: color 0.3s;
|
||||
padding: 0;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:hover: {
|
||||
color: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
`,
|
||||
drawerBody: css`
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5715;
|
||||
word-wrap: break-word;
|
||||
height: calc(100% - 54px);
|
||||
`,
|
||||
}));
|
||||
|
||||
// 抽屉组件
|
||||
const Drawer: React.FC<DrawerProps> = ({
|
||||
visible = false,
|
||||
onClose,
|
||||
children,
|
||||
bottomOffset = 0,
|
||||
height = 378,
|
||||
mask = true,
|
||||
maskClosable = true,
|
||||
style = {},
|
||||
className = '',
|
||||
maskStyle = {},
|
||||
title,
|
||||
closable = true,
|
||||
closeIcon,
|
||||
afterOpen,
|
||||
afterClose,
|
||||
placement = 'bottom',
|
||||
width = 378,
|
||||
getContainer
|
||||
}) => {
|
||||
const { styles } = useStyles();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
const drawerRef = useRef<HTMLDivElement>(null);
|
||||
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
setIsMounted(true);
|
||||
timerRef.current = setTimeout(() => {
|
||||
setIsOpen(true);
|
||||
afterOpen?.();
|
||||
}, 10);
|
||||
} else {
|
||||
setIsOpen(false);
|
||||
timerRef.current = setTimeout(() => {
|
||||
setIsMounted(false);
|
||||
afterClose?.();
|
||||
}, 300);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (timerRef.current) {
|
||||
clearTimeout(timerRef.current);
|
||||
}
|
||||
};
|
||||
}, [visible, afterOpen, afterClose]);
|
||||
|
||||
const handleMaskClick = () => {
|
||||
if (maskClosable) {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
|
||||
const handleContentClick = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
onClose();
|
||||
};
|
||||
|
||||
const getPlacementClass = () => {
|
||||
switch (placement) {
|
||||
case 'left':
|
||||
return `${styles.drawerWrapperLeft} ${isOpen ? styles.drawerOpenLeft : ''}`;
|
||||
case 'right':
|
||||
return `${styles.drawerWrapperRight} ${isOpen ? styles.drawerOpenRight : ''}`;
|
||||
case 'top':
|
||||
return `${styles.drawerWrapperTop} ${isOpen ? styles.drawerOpenTop : ''}`;
|
||||
case 'bottom':
|
||||
default:
|
||||
return `${styles.drawerWrapperBottom} ${isOpen ? styles.drawerOpenBottom : ''}`;
|
||||
}
|
||||
};
|
||||
|
||||
const getDrawerStyle = (): CSSProperties => {
|
||||
const baseStyle: CSSProperties = {};
|
||||
|
||||
if (placement === 'left' || placement === 'right') {
|
||||
baseStyle.width = typeof width === 'number' ? `${width}px` : width;
|
||||
} else {
|
||||
baseStyle.height = typeof height === 'number' ? `${height}px` : height;
|
||||
if (placement === 'bottom') {
|
||||
baseStyle.bottom = `${bottomOffset}px`;
|
||||
}
|
||||
}
|
||||
|
||||
return baseStyle;
|
||||
};
|
||||
|
||||
if (!isMounted && !visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const getContainerStyle = (): CSSProperties => {
|
||||
if (getContainer === false) {
|
||||
return { position: 'absolute' };
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${getContainer === false ? styles.drawerContainerAbsolute : styles.drawerContainer} ${className || ''}`} style={{...style, ...getContainerStyle()}}>
|
||||
{mask && (
|
||||
<div
|
||||
className={`${styles.drawerMask} ${isOpen ? styles.drawerMaskVisible : ''}`}
|
||||
style={maskStyle}
|
||||
onClick={handleMaskClick}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
ref={drawerRef}
|
||||
className={`${styles.drawerContentWrapper} ${getPlacementClass()} ${dark_bg2_style}`}
|
||||
style={getDrawerStyle()}
|
||||
onClick={handleContentClick}
|
||||
>
|
||||
<div className={`${styles.drawerHeader} ${dark_bg2_style}`}>
|
||||
<div className={styles.drawerTitle}>{title}</div>
|
||||
{closable && (
|
||||
<button type="button" onClick={handleClose} className={styles.drawerClose}>
|
||||
{closeIcon || <span className={styles.drawerClose}>×</span>}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.drawerBody}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Drawer;
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
|
||||
import { GridCard } from "@/components/Card";
|
||||
import { GridCard } from "@components/Card";
|
||||
|
||||
import { cx } from "../cva.config";
|
||||
|
||||
@@ -10,6 +10,7 @@ interface Props {
|
||||
description?: string | React.ReactNode;
|
||||
BtnElm?: React.ReactNode;
|
||||
className?: string;
|
||||
iconClassName?: string;
|
||||
}
|
||||
|
||||
export default function EmptyCard({
|
||||
@@ -18,6 +19,7 @@ export default function EmptyCard({
|
||||
description,
|
||||
BtnElm,
|
||||
className,
|
||||
iconClassName,
|
||||
}: Props) {
|
||||
return (
|
||||
<GridCard>
|
||||
@@ -30,13 +32,13 @@ export default function EmptyCard({
|
||||
<div className="max-w-[90%] space-y-1.5 text-center md:max-w-[60%]">
|
||||
<div className="space-y-2">
|
||||
{IconElm && (
|
||||
<IconElm className="mx-auto h-5 w-5 text-blue-600 dark:text-blue-600" />
|
||||
<IconElm className={cx("mx-auto h-5 w-5 text-blue-600 dark:text-blue-600", iconClassName)} />
|
||||
)}
|
||||
<h4 className="text-base font-bold leading-none text-black dark:text-white">
|
||||
{headline}
|
||||
</h4>
|
||||
</div>
|
||||
<p className="mx-auto text-sm text-slate-600 dark:text-slate-400">
|
||||
<p className="mx-auto text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import React from "react";
|
||||
|
||||
import { cx } from "@/cva.config";
|
||||
|
||||
export default function ExtLink({
|
||||
className,
|
||||
href,
|
||||
id,
|
||||
target,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
href: string;
|
||||
id?: string;
|
||||
target?: string;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<a
|
||||
className={cx(className)}
|
||||
target={target ?? "_blank"}
|
||||
id={id}
|
||||
rel="noopener noreferrer"
|
||||
href={href}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
import React from "react";
|
||||
|
||||
import { cx } from "@/cva.config";
|
||||
|
||||
export default function ExtLink({
|
||||
className,
|
||||
href,
|
||||
id,
|
||||
target,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
href: string;
|
||||
id?: string;
|
||||
target?: string;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<a
|
||||
className={cx(className)}
|
||||
target={target ?? "_blank"}
|
||||
id={id}
|
||||
rel="noopener noreferrer"
|
||||
href={href}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { useFeatureFlag } from "../hooks/useFeatureFlag";
|
||||
|
||||
export function FeatureFlag({
|
||||
minAppVersion,
|
||||
name = "unnamed",
|
||||
fallback = null,
|
||||
children,
|
||||
}: {
|
||||
minAppVersion: string;
|
||||
name?: string;
|
||||
fallback?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
const { isEnabled, appVersion } = useFeatureFlag(minAppVersion);
|
||||
|
||||
useEffect(() => {
|
||||
if (!appVersion) return;
|
||||
console.log(
|
||||
`Feature '${name}' ${isEnabled ? "ENABLED" : "DISABLED"}: ` +
|
||||
`Current version: ${appVersion}, ` +
|
||||
`Required min version: ${minAppVersion || "N/A"}`,
|
||||
);
|
||||
}, [isEnabled, name, minAppVersion, appVersion]);
|
||||
|
||||
return isEnabled ? children : fallback;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export default function FieldLabel({
|
||||
>
|
||||
{label}
|
||||
{description && (
|
||||
<span className="my-0.5 text-[13px] font-normal text-slate-600 dark:text-slate-400">
|
||||
<span className="my-0.5 text-[13px] font-normal text-slate-600 dark:text-[#ffffff]">
|
||||
{description}
|
||||
</span>
|
||||
)}
|
||||
@@ -40,7 +40,7 @@ export default function FieldLabel({
|
||||
{label}
|
||||
</span>
|
||||
{description && (
|
||||
<span className="my-0.5 text-[13px] font-normal text-slate-600 dark:text-slate-400">
|
||||
<span className="my-0.5 text-[13px] font-normal text-slate-600 dark:text-[#ffffff]">
|
||||
{description}
|
||||
</span>
|
||||
)}
|
||||
|
||||
469
ui/src/components/FileManager/FileUploader.tsx
Normal file
@@ -0,0 +1,469 @@
|
||||
import { useReactAt } from "i18n-auto-extractor/react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { LuCheck, LuUpload } from "react-icons/lu";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
import { useRTCStore } from "@/hooks/stores";
|
||||
import notifications from "@/notifications";
|
||||
import { DEVICE_API } from "@/ui.config";
|
||||
import { isOnDevice } from "@/main";
|
||||
import Card from "@components/Card";
|
||||
import { cx } from "@/cva.config";
|
||||
import { formatters } from "@/utils";
|
||||
import { text_primary_color } from "@/layout/theme_color";
|
||||
|
||||
import UploadSvg from "@/assets/second/upload.svg?react";
|
||||
|
||||
|
||||
export function FileUploader({
|
||||
onBack,
|
||||
incompleteFileName,
|
||||
media,
|
||||
}: {
|
||||
onBack: () => void;
|
||||
incompleteFileName?: string;
|
||||
media?: string;
|
||||
})
|
||||
{
|
||||
const { $at }= useReactAt();
|
||||
const [uploadState, setUploadState] = useState<"idle" | "uploading" | "success">(
|
||||
"idle",
|
||||
);
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
const [uploadedFileName, setUploadedFileName] = useState<string | null>(null);
|
||||
const [uploadedFileSize, setUploadedFileSize] = useState<number | null>(null);
|
||||
const [uploadSpeed, setUploadSpeed] = useState<number | null>(null);
|
||||
const [fileError, setFileError] = useState<string | null>(null);
|
||||
const [uploadError, setUploadError] = useState<string | null>(null);
|
||||
|
||||
const [send] = useJsonRpc();
|
||||
const rtcDataChannelRef = useRef<RTCDataChannel | null>(null);
|
||||
|
||||
const xhrRef = useRef<XMLHttpRequest | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const ref = rtcDataChannelRef.current;
|
||||
return () => {
|
||||
if (ref) {
|
||||
ref.onopen = null;
|
||||
ref.onerror = null;
|
||||
ref.onmessage = null;
|
||||
ref.onclose = null;
|
||||
ref.close();
|
||||
}
|
||||
if (xhrRef.current) {
|
||||
xhrRef.current.abort();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
function handleWebRTCUpload(
|
||||
file: File,
|
||||
alreadyUploadedBytes: number,
|
||||
dataChannel: string,
|
||||
) {
|
||||
const rtcDataChannel = useRTCStore
|
||||
.getState()
|
||||
.peerConnection?.createDataChannel(dataChannel);
|
||||
|
||||
if (!rtcDataChannel) {
|
||||
console.error("Failed to create data channel for file upload");
|
||||
notifications.error("Failed to create data channel for file upload");
|
||||
setUploadState("idle");
|
||||
console.log("Upload state set to 'idle'");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
rtcDataChannelRef.current = rtcDataChannel;
|
||||
|
||||
const lowWaterMark = 256 * 1024;
|
||||
const highWaterMark = 1 * 1024 * 1024;
|
||||
rtcDataChannel.bufferedAmountLowThreshold = lowWaterMark;
|
||||
|
||||
let lastUploadedBytes = alreadyUploadedBytes;
|
||||
let lastUpdateTime = Date.now();
|
||||
const speedHistory: number[] = [];
|
||||
|
||||
rtcDataChannel.onmessage = e => {
|
||||
try {
|
||||
const { AlreadyUploadedBytes, Size } = JSON.parse(e.data) as {
|
||||
AlreadyUploadedBytes: number;
|
||||
Size: number;
|
||||
};
|
||||
|
||||
const now = Date.now();
|
||||
const timeDiff = (now - lastUpdateTime) / 1000; // in seconds
|
||||
const bytesDiff = AlreadyUploadedBytes - lastUploadedBytes;
|
||||
|
||||
if (timeDiff > 0) {
|
||||
const instantSpeed = bytesDiff / timeDiff; // bytes per second
|
||||
|
||||
// Add to speed history, keeping last 5 readings
|
||||
speedHistory.push(instantSpeed);
|
||||
if (speedHistory.length > 5) {
|
||||
speedHistory.shift();
|
||||
}
|
||||
|
||||
// Calculate average speed
|
||||
const averageSpeed =
|
||||
speedHistory.reduce((a, b) => a + b, 0) / speedHistory.length;
|
||||
|
||||
setUploadSpeed(averageSpeed);
|
||||
setUploadProgress((AlreadyUploadedBytes / Size) * 100);
|
||||
}
|
||||
|
||||
lastUploadedBytes = AlreadyUploadedBytes;
|
||||
lastUpdateTime = now;
|
||||
} catch (e) {
|
||||
console.error("Error processing RTC Data channel message:", e);
|
||||
}
|
||||
};
|
||||
|
||||
rtcDataChannel.onopen = () => {
|
||||
let pauseSending = false; // Pause sending when the buffered amount is high
|
||||
const chunkSize = 4 * 1024; // 4KB chunks
|
||||
|
||||
let offset = alreadyUploadedBytes;
|
||||
const sendNextChunk = () => {
|
||||
if (offset >= file.size) {
|
||||
rtcDataChannel.close();
|
||||
setUploadState("success");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pauseSending) return;
|
||||
|
||||
const chunk = file.slice(offset, offset + chunkSize);
|
||||
chunk.arrayBuffer().then(buffer => {
|
||||
rtcDataChannel.send(buffer);
|
||||
|
||||
if (rtcDataChannel.bufferedAmount >= highWaterMark) {
|
||||
pauseSending = true;
|
||||
}
|
||||
|
||||
offset += buffer.byteLength;
|
||||
console.log(`Chunk sent: ${offset} / ${file.size} bytes`);
|
||||
sendNextChunk();
|
||||
});
|
||||
};
|
||||
|
||||
sendNextChunk();
|
||||
rtcDataChannel.onbufferedamountlow = () => {
|
||||
console.log("RTC Data channel buffered amount low");
|
||||
pauseSending = false; // Now the data channel is ready to send more data
|
||||
sendNextChunk();
|
||||
};
|
||||
};
|
||||
|
||||
rtcDataChannel.onerror = error => {
|
||||
console.error("RTC Data channel error:", error);
|
||||
notifications.error(`Upload failed: ${error}`);
|
||||
setUploadState("idle");
|
||||
console.log("Upload state set to 'idle'");
|
||||
};
|
||||
}
|
||||
|
||||
async function handleHttpUpload(
|
||||
file: File,
|
||||
alreadyUploadedBytes: number,
|
||||
dataChannel: string,
|
||||
) {
|
||||
const uploadUrl = `${DEVICE_API}/storage/upload?uploadId=${dataChannel}`;
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhrRef.current = xhr;
|
||||
xhr.open("POST", uploadUrl, true);
|
||||
xhr.setRequestHeader('Content-Range', `bytes ${alreadyUploadedBytes}-${file.size-1}/${file.size}`);
|
||||
|
||||
let lastUploadedBytes = alreadyUploadedBytes;
|
||||
let lastUpdateTime = Date.now();
|
||||
const speedHistory: number[] = [];
|
||||
|
||||
xhr.upload.onprogress = event => {
|
||||
if (event.lengthComputable) {
|
||||
const totalUploaded = alreadyUploadedBytes + event.loaded;
|
||||
const totalSize = file.size;
|
||||
|
||||
const now = Date.now();
|
||||
const timeDiff = (now - lastUpdateTime) / 1000; // in seconds
|
||||
const bytesDiff = totalUploaded - lastUploadedBytes;
|
||||
|
||||
if (timeDiff > 0) {
|
||||
const instantSpeed = bytesDiff / timeDiff; // bytes per second
|
||||
|
||||
// Add to speed history, keeping last 5 readings
|
||||
speedHistory.push(instantSpeed);
|
||||
if (speedHistory.length > 5) {
|
||||
speedHistory.shift();
|
||||
}
|
||||
|
||||
// Calculate average speed
|
||||
const averageSpeed =
|
||||
speedHistory.reduce((a, b) => a + b, 0) / speedHistory.length;
|
||||
|
||||
setUploadSpeed(averageSpeed);
|
||||
setUploadProgress((totalUploaded / totalSize) * 100);
|
||||
}
|
||||
|
||||
lastUploadedBytes = totalUploaded;
|
||||
lastUpdateTime = now;
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = () => {
|
||||
if (xhr.status === 200) {
|
||||
setUploadState("success");
|
||||
setTimeout(() => {
|
||||
onBack()
|
||||
}, 1000)
|
||||
} else {
|
||||
console.error("Upload error:", xhr.statusText);
|
||||
setUploadError(xhr.statusText);
|
||||
setUploadState("idle");
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = () => {
|
||||
console.error("XHR error:", xhr.statusText);
|
||||
setUploadError(xhr.statusText);
|
||||
setUploadState("idle");
|
||||
};
|
||||
|
||||
xhr.onabort = () => {
|
||||
console.log("Upload aborted");
|
||||
setUploadState("idle");
|
||||
}
|
||||
|
||||
// Prepare the data to send
|
||||
const blob = file.slice(alreadyUploadedBytes);
|
||||
|
||||
// Send the file data
|
||||
xhr.send(blob);
|
||||
}
|
||||
|
||||
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (file) {
|
||||
// Reset the upload error when a new file is selected
|
||||
setUploadError(null);
|
||||
|
||||
if (
|
||||
incompleteFileName &&
|
||||
file.name !== incompleteFileName.replace(".incomplete", "")
|
||||
) {
|
||||
setFileError(
|
||||
$at("Please select the file {{fileName}} to continue the upload.").replace("{{fileName}}", incompleteFileName.replace(".incomplete", "")),
|
||||
);
|
||||
// Clear the input value to allow selecting the same file again if needed
|
||||
event.target.value = "";
|
||||
return;
|
||||
}
|
||||
|
||||
setFileError(null);
|
||||
console.log(`File selected: ${file.name}, size: ${file.size} bytes`);
|
||||
setUploadedFileName(file.name);
|
||||
setUploadedFileSize(file.size);
|
||||
setUploadState("uploading");
|
||||
console.log("Upload state set to 'uploading'");
|
||||
|
||||
if ( media === "sd" ) {
|
||||
send("startSDStorageFileUpload", { filename: file.name, size: file.size }, resp => {
|
||||
console.log("startSDStorageFileUpload response:", resp);
|
||||
if ("error" in resp) {
|
||||
console.error("Upload error:", resp.error.message);
|
||||
setUploadError(resp.error.data || resp.error.message);
|
||||
setUploadState("idle");
|
||||
console.log("Upload state set to 'idle'");
|
||||
return;
|
||||
}
|
||||
|
||||
const { alreadyUploadedBytes, dataChannel } = resp.result as {
|
||||
alreadyUploadedBytes: number;
|
||||
dataChannel: string;
|
||||
};
|
||||
|
||||
console.log(
|
||||
`Already uploaded bytes: ${alreadyUploadedBytes}, Data channel: ${dataChannel}`,
|
||||
);
|
||||
|
||||
if (isOnDevice) {
|
||||
handleHttpUpload(file, alreadyUploadedBytes, dataChannel);
|
||||
} else {
|
||||
handleWebRTCUpload(file, alreadyUploadedBytes, dataChannel);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
send("startStorageFileUpload", { filename: file.name, size: file.size }, resp => {
|
||||
console.log("startStorageFileUpload response:", resp);
|
||||
if ("error" in resp) {
|
||||
console.error("Upload error:", resp.error.message);
|
||||
setUploadError(resp.error.data || resp.error.message);
|
||||
setUploadState("idle");
|
||||
console.log("Upload state set to 'idle'");
|
||||
return;
|
||||
}
|
||||
|
||||
const { alreadyUploadedBytes, dataChannel } = resp.result as {
|
||||
alreadyUploadedBytes: number;
|
||||
dataChannel: string;
|
||||
};
|
||||
|
||||
console.log(
|
||||
`Already uploaded bytes: ${alreadyUploadedBytes}, Data channel: ${dataChannel}`,
|
||||
);
|
||||
|
||||
if (isOnDevice) {
|
||||
handleHttpUpload(file, alreadyUploadedBytes, dataChannel);
|
||||
} else {
|
||||
handleWebRTCUpload(file, alreadyUploadedBytes, dataChannel);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Clear the input value to allow selecting the same file again if needed
|
||||
event.target.value = "";
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full space-y-4 my-4">
|
||||
<div
|
||||
className="animate-fadeIn space-y-2 opacity-0"
|
||||
style={{
|
||||
animationDuration: "0.7s",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onClick={() => {
|
||||
if (uploadState === "idle") {
|
||||
document.getElementById("file-upload")?.click();
|
||||
}
|
||||
}}
|
||||
className="block select-none"
|
||||
>
|
||||
<div className="group">
|
||||
<Card
|
||||
className={cx("transition-all duration-300", {
|
||||
"cursor-pointer hover:bg-blue-50/50 dark:hover:bg-blue-900/50":
|
||||
uploadState === "idle",
|
||||
})}
|
||||
>
|
||||
<div className="h-[146px] w-full px-4">
|
||||
<div className="flex h-full flex-col items-center justify-center text-center">
|
||||
{uploadState === "idle" && (
|
||||
<div className="space-y-1">
|
||||
<div className="inline-block">
|
||||
|
||||
<div className="p-1">
|
||||
<UploadSvg className={`h-[24px] w-[24px] shrink-0 ${text_primary_color}`} />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div style={{fontSize: "14px",fontWeight: "400"}} className=" text-[rgba(22,152,217,1)] dark:text-white">
|
||||
{incompleteFileName
|
||||
? (
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<span className="font-semibold">{$at("Resume Upload")}</span>
|
||||
<span>{$at("Click here to select {{fileName}} to resume upload").replace("{{fileName}}", formatters.truncateMiddle(incompleteFileName.replace(".incomplete", ""), 30))}</span>
|
||||
</div>
|
||||
)
|
||||
: $at("Click here to upload a new image")
|
||||
}
|
||||
</div>
|
||||
{/*<p className="text-xs leading-none text-slate-700 dark:text-slate-300">*/}
|
||||
{/* {$at("Do not support directories")}*/}
|
||||
{/*</p>*/}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{uploadState === "uploading" && (
|
||||
<div className="w-full max-w-sm space-y-2 text-left">
|
||||
<div className="inline-block">
|
||||
<Card>
|
||||
<div className="p-1">
|
||||
<LuUpload className="h-4 w-4 shrink-0 text-[rgba(22,152,217,1)] dark:text-[rgba(45,106,229,1)]" />
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<h3 className="leading-non text-lg font-semibold text-black dark:text-white">
|
||||
{$at("Uploading")} {formatters.truncateMiddle(uploadedFileName, 30)}
|
||||
</h3>
|
||||
<p className="text-xs leading-none text-slate-700 dark:text-slate-300">
|
||||
{formatters.bytes(uploadedFileSize || 0)}
|
||||
</p>
|
||||
<div className="w-full space-y-2">
|
||||
<div className="h-3.5 w-full overflow-hidden rounded-full bg-slate-300 dark:bg-slate-700">
|
||||
<div
|
||||
className="h-3.5 rounded-full bg-[rgba(22,152,217,1)] transition-all duration-500 ease-linear dark:bg-[rgba(45,106,229,1)]"
|
||||
style={{ width: `${uploadProgress}%` }}
|
||||
></div>
|
||||
</div>
|
||||
<div className="flex justify-between text-xs text-slate-600 dark:text-[#ffffff]">
|
||||
<span>{$at("Uploading...")}...</span>
|
||||
<span>
|
||||
{uploadSpeed !== null
|
||||
? `${formatters.bytes(uploadSpeed)}/s`
|
||||
: $at("Calculating...")}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{uploadState === "success" && (
|
||||
<div className="space-y-1">
|
||||
<div className="inline-block">
|
||||
<Card>
|
||||
<div className="p-1">
|
||||
<LuCheck className="h-4 w-4 shrink-0 text-blue-500 dark:text-blue-400" />
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<h3 className="text-sm leading-none font-semibold text-black dark:text-white">
|
||||
{$at("Upload Successful")}
|
||||
</h3>
|
||||
<p className="text-xs leading-none text-slate-700 dark:text-slate-300">
|
||||
{formatters.truncateMiddle(uploadedFileName, 40)} {$at("Uploaded")}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
id="file-upload"
|
||||
type="file"
|
||||
onChange={handleFileChange}
|
||||
className="hidden"
|
||||
/>
|
||||
{fileError && (
|
||||
<p className="mt-2 text-sm text-red-600 dark:text-red-400">{fileError}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Display upload error if present */}
|
||||
{uploadError && (
|
||||
<div
|
||||
className="mt-2 animate-fadeIn truncate text-sm text-red-600 dark:text-red-400 opacity-0"
|
||||
style={{ animationDuration: "0.7s" }}
|
||||
>
|
||||
Error: {uploadError}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
className="flex w-full animate-fadeIn items-end opacity-0"
|
||||
style={{
|
||||
animationDuration: "0.7s",
|
||||
animationDelay: "0.1s",
|
||||
}}
|
||||
>
|
||||
</div>
|
||||
{isMobile&&<div className="h-[30px]"></div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
LuGlobe,
|
||||
LuLink,
|
||||
LuRadioReceiver,
|
||||
LuHardDrive,
|
||||
LuCheck,
|
||||
@@ -11,36 +9,36 @@ import {
|
||||
import { PlusCircleIcon, ExclamationTriangleIcon } from "@heroicons/react/20/solid";
|
||||
import { TrashIcon } from "@heroicons/react/16/solid";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import {Checkbox} from "antd";
|
||||
import { useReactAt } from 'i18n-auto-extractor/react'
|
||||
|
||||
import Card, { GridCard } from "@/components/Card";
|
||||
import Card, { GridCard } from "@components/Card";
|
||||
import { Button } from "@components/Button";
|
||||
import LogoLuckfox from "@/assets/logo-luckfox.png";
|
||||
import { formatters } from "@/utils";
|
||||
import AutoHeight from "@components/AutoHeight";
|
||||
import { InputFieldWithLabel } from "@/components/InputField";
|
||||
import { InputFieldWithLabel } from "@components/InputField";
|
||||
import DebianIcon from "@/assets/debian-icon.png";
|
||||
import UbuntuIcon from "@/assets/ubuntu-icon.png";
|
||||
import FedoraIcon from "@/assets/fedora-icon.png";
|
||||
import OpenSUSEIcon from "@/assets/opensuse-icon.png";
|
||||
import ArchIcon from "@/assets/arch-icon.png";
|
||||
import NetBootIcon from "@/assets/netboot-icon.svg";
|
||||
import Fieldset from "@/components/Fieldset";
|
||||
import Fieldset from "@components/Fieldset";
|
||||
import { DEVICE_API } from "@/ui.config";
|
||||
import { UploadDialog } from "@components/FileManager/UploadDialog";
|
||||
import { SettingsItem } from "@components/Settings/SettingsView";
|
||||
|
||||
import { useJsonRpc } from "../hooks/useJsonRpc";
|
||||
import notifications from "../notifications";
|
||||
import { isOnDevice } from "../main";
|
||||
import { cx } from "../cva.config";
|
||||
import { useJsonRpc } from "../../hooks/useJsonRpc";
|
||||
import notifications from "../../notifications";
|
||||
import { isOnDevice } from "../../main";
|
||||
import { cx } from "../../cva.config";
|
||||
import {
|
||||
MountMediaState,
|
||||
RemoteVirtualMediaState,
|
||||
useMountMediaStore,
|
||||
useRTCStore,
|
||||
} from "../hooks/stores";
|
||||
import { UploadDialog } from "@/components/UploadDialog";
|
||||
import { SettingsItem } from "./devices.$id.settings";
|
||||
import { Checkbox } from "@/components/Checkbox";
|
||||
import { useReactAt } from 'i18n-auto-extractor/react'
|
||||
} from "../../hooks/stores";
|
||||
|
||||
export default function MountRoute() {
|
||||
const navigate = useNavigate();
|
||||
@@ -360,28 +358,12 @@ function ModeSelectionView({
|
||||
<h2 className="text-lg leading-tight font-bold dark:text-white">
|
||||
{$at("Virtual Media Source")}
|
||||
</h2>
|
||||
<div className="text-sm leading-snug text-slate-600 dark:text-slate-400">
|
||||
<div className="text-sm leading-snug text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Choose how you want to mount your virtual media")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
{[
|
||||
//{
|
||||
// label: "Browser Mount",
|
||||
// value: "browser",
|
||||
// description: "Stream files directly from your browser",
|
||||
// icon: LuGlobe,
|
||||
// tag: "Coming Soon",
|
||||
// disabled: true,
|
||||
//},
|
||||
//{
|
||||
// label: "URL Mount",
|
||||
// value: "url",
|
||||
// description: "Mount files from any public web address",
|
||||
// icon: LuLink,
|
||||
// tag: "Experimental",
|
||||
// disabled: false,
|
||||
//},
|
||||
{
|
||||
label: "KVM Storage Mount",
|
||||
value: "device",
|
||||
@@ -436,7 +418,7 @@ function ModeSelectionView({
|
||||
</p>
|
||||
|
||||
<h3 className="text-sm font-medium dark:text-white">{label}</h3>
|
||||
<p className="text-sm text-gray-700 dark:text-slate-400">
|
||||
<p className="text-sm text-gray-700 dark:text-[#ffffff]">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
@@ -720,7 +702,7 @@ function UrlView({
|
||||
{formatters.truncateMiddle(image.name, 40)}
|
||||
</h3>
|
||||
{image.description && (
|
||||
<p className="text-xs text-slate-600 dark:text-slate-400">
|
||||
<p className="text-xs text-slate-600 dark:text-[#ffffff]">
|
||||
{image.description}
|
||||
</p>
|
||||
)}
|
||||
@@ -748,12 +730,13 @@ function DeviceFileView({
|
||||
mountInProgress,
|
||||
onBack,
|
||||
onNewImageClick,
|
||||
}: {
|
||||
}: {
|
||||
onMountStorageFile: (name: string, mode: RemoteVirtualMediaState["mode"]) => void;
|
||||
mountInProgress: boolean;
|
||||
onBack: () => void;
|
||||
onNewImageClick: (incompleteFileName?: string) => void;
|
||||
}) {
|
||||
})
|
||||
{
|
||||
const [onStorageFiles, setOnStorageFiles] = useState<
|
||||
{
|
||||
name: string;
|
||||
@@ -1114,7 +1097,8 @@ function SDFileView({
|
||||
mountInProgress: boolean;
|
||||
onBack: () => void;
|
||||
onNewImageClick: (incompleteFileName?: string) => void;
|
||||
}) {
|
||||
})
|
||||
{
|
||||
const [onStorageFiles, setOnStorageFiles] = useState<
|
||||
{
|
||||
name: string;
|
||||
@@ -1528,12 +1512,14 @@ function UploadFileView({
|
||||
onCancelUpload,
|
||||
incompleteFileName,
|
||||
media,
|
||||
}: {
|
||||
}:
|
||||
{
|
||||
onBack: () => void;
|
||||
onCancelUpload: () => void;
|
||||
incompleteFileName?: string;
|
||||
media?: string;
|
||||
}) {
|
||||
})
|
||||
{
|
||||
const [uploadState, setUploadState] = useState<"idle" | "uploading" | "success">(
|
||||
"idle",
|
||||
);
|
||||
@@ -1547,11 +1533,10 @@ function UploadFileView({
|
||||
|
||||
const [send] = useJsonRpc();
|
||||
const rtcDataChannelRef = useRef<RTCDataChannel | null>(null);
|
||||
|
||||
console.log("incompleteFileName",incompleteFileName)
|
||||
useEffect(() => {
|
||||
const ref = rtcDataChannelRef.current;
|
||||
return () => {
|
||||
console.log("unmounting");
|
||||
if (ref) {
|
||||
ref.onopen = null;
|
||||
ref.onerror = null;
|
||||
@@ -1893,7 +1878,7 @@ function UploadFileView({
|
||||
style={{ width: `${uploadProgress}%` }}
|
||||
></div>
|
||||
</div>
|
||||
<div className="flex justify-between text-xs text-slate-600 dark:text-slate-400">
|
||||
<div className="flex justify-between text-xs text-slate-600 dark:text-[#ffffff]">
|
||||
<span>{$at("Uploading...")}</span>
|
||||
<span>
|
||||
{uploadSpeed !== null
|
||||
@@ -1994,7 +1979,8 @@ function ErrorView({
|
||||
errorMessage: string | null;
|
||||
onClose: () => void;
|
||||
onRetry: () => void;
|
||||
}) {
|
||||
})
|
||||
{
|
||||
return (
|
||||
<div className="w-full space-y-4">
|
||||
<div className="space-y-2">
|
||||
@@ -2019,7 +2005,7 @@ function ErrorView({
|
||||
);
|
||||
}
|
||||
|
||||
function PreUploadedImageItem({
|
||||
export function PreUploadedImageItem({
|
||||
name,
|
||||
size,
|
||||
uploadedAt,
|
||||
@@ -2065,11 +2051,11 @@ function PreUploadedImageItem({
|
||||
{formatters.truncateMiddle(name, 45)}
|
||||
</div>
|
||||
<div className="flex items-center text-sm">
|
||||
<div className="flex items-center gap-x-1 text-slate-600 dark:text-slate-400">
|
||||
<div className="flex items-center gap-x-1 text-slate-600 dark:text-[#ffffff]">
|
||||
{formatters.date(new Date(uploadedAt), { month: "short" })}
|
||||
</div>
|
||||
<div className="mx-1 h-[10px] w-px bg-slate-300 text-slate-300 dark:bg-slate-600"></div>
|
||||
<div className="text-gray-600 dark:text-slate-400">{size}</div>
|
||||
<div className="text-gray-600 dark:text-[#ffffff]">{size}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2122,14 +2108,14 @@ function ViewHeader({ title, description }: { title: string; description: string
|
||||
<h2 className="text-lg leading-tight font-bold text-black dark:text-white">
|
||||
{title}
|
||||
</h2>
|
||||
<div className="text-sm leading-snug text-slate-600 dark:text-slate-400">
|
||||
<div className="text-sm leading-snug text-slate-600 dark:text-[#ffffff]">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function UsbModeSelector({
|
||||
export function UsbModeSelector({
|
||||
usbMode,
|
||||
setUsbMode,
|
||||
}: {
|
||||
@@ -2150,7 +2136,7 @@ function UsbModeSelector({
|
||||
name="mountType"
|
||||
onChange={() => setUsbMode("CDROM")}
|
||||
checked={usbMode === "CDROM"}
|
||||
className="form-radio h-3 w-3 rounded-full border-slate-800/30 bg-white text-blue-700 transition-opacity focus:ring-blue-500 disabled:opacity-30 dark:bg-slate-800"
|
||||
className="form-radio h-3 w-3 rounded-full border-slate-800/30 bg-white text-[rgba(22,152,217,1)] transition-opacity focus:ring-[rgba(45,106,229,1)] disabled:opacity-30 dark:text-[rgba(45,106,229,1)]"
|
||||
/>
|
||||
<span className="ml-2 text-sm font-medium text-slate-900 dark:text-white">
|
||||
CD/DVD
|
||||
@@ -2163,7 +2149,7 @@ function UsbModeSelector({
|
||||
name="mountType"
|
||||
checked={usbMode === "Disk"}
|
||||
onChange={() => setUsbMode("Disk")}
|
||||
className="form-radio h-3 w-3 rounded-full border-slate-800/30 bg-white text-blue-700 transition-opacity focus:ring-blue-500 disabled:opacity-30 dark:bg-slate-800"
|
||||
className="form-radio h-3 w-3 rounded-full border-slate-800/30 bg-white text-[rgba(22,152,217,1)] transition-opacity focus:ring-[rgba(45,106,229,1)] disabled:opacity-30 dark:text-[rgba(45,106,229,1)]"
|
||||
/>
|
||||
<span className="ml-2 text-sm font-medium text-slate-900 dark:text-white">
|
||||
Disk
|
||||
@@ -1,10 +1,10 @@
|
||||
import Modal from "@/components/Modal";
|
||||
import Modal from "@components/Modal";
|
||||
|
||||
interface UploadDialogProps {
|
||||
open: boolean;
|
||||
title: string;
|
||||
description: React.ReactNode
|
||||
children?: React.ReactNode;
|
||||
description: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ export function UploadDialog({
|
||||
}: UploadDialogProps) {
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={ () => {} }>
|
||||
<Modal open={open} onClose={() => undefined}>
|
||||
<div className="mx-auto max-w-xl px-4 transition-all duration-300 ease-in-out">
|
||||
<div className="pointer-events-auto relative w-full overflow-hidden rounded-lg bg-white p-6 text-left align-middle shadow-xl transition-all dark:bg-slate-800">
|
||||
<div className="space-y-4">
|
||||
@@ -25,7 +25,7 @@ export function UploadDialog({
|
||||
<h2 className="text-lg leading-tight font-bold text-black dark:text-white">
|
||||
{title}
|
||||
</h2>
|
||||
<div className="text-sm leading-snug text-slate-600 dark:text-slate-400">
|
||||
<div className="text-sm leading-snug text-slate-600 dark:text-[#ffffff]">
|
||||
{description}
|
||||
</div>
|
||||
</div>
|
||||
@@ -36,4 +36,4 @@ export function UploadDialog({
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
export default function GridBackground() {
|
||||
return (
|
||||
<div className="absolute isolate h-screen w-screen overflow-hidden opacity-60">
|
||||
<svg
|
||||
className="absolute inset-x-0 top-0 -z-10 h-full w-full mask-radial-[32rem_32rem] mask-radial-from-white mask-radial-to-transparent mask-radial-at-center stroke-gray-300 dark:stroke-slate-300/20"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<defs>
|
||||
<pattern
|
||||
id="1f932ae7-37de-4c0a-a8b0-a6e3b4d44b84"
|
||||
width={200}
|
||||
height={200}
|
||||
x="50%"
|
||||
y={-1}
|
||||
patternUnits="userSpaceOnUse"
|
||||
>
|
||||
<path d="M.5 200V.5H200" fill="none" />
|
||||
</pattern>
|
||||
</defs>
|
||||
|
||||
<svg
|
||||
x="50%"
|
||||
y={-1}
|
||||
className="overflow-visible fill-blue-100 dark:fill-blue-900/30"
|
||||
>
|
||||
<path
|
||||
d="M-200 0h201v201h-201Z M600 0h201v201h-201Z M-400 600h201v201h-201Z M200 800h201v201h-201Z"
|
||||
strokeWidth={0}
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<rect
|
||||
width="100%"
|
||||
height="100%"
|
||||
strokeWidth={0}
|
||||
fill="url(#1f932ae7-37de-4c0a-a8b0-a6e3b4d44b84)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,28 +1,24 @@
|
||||
import { use, useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useEffect} from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { ArrowLeftEndOnRectangleIcon, ChevronDownIcon } from "@heroicons/react/16/solid";
|
||||
import { Button, Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
|
||||
import { LuMonitorSmartphone } from "react-icons/lu";
|
||||
|
||||
import Container from "@/components/Container";
|
||||
import Card from "@/components/Card";
|
||||
import { useHidStore, useRTCStore, useUserStore, useVpnStore } from "@/hooks/stores";
|
||||
import LogoLuckfox from "@/assets/logo-luckfox.png";
|
||||
import USBStateStatus from "@components/USBStateStatus";
|
||||
import PeerConnectionStatusCard from "@components/PeerConnectionStatusCard";
|
||||
import VpnConnectionStatusCard from "@components/VpnConnectionStatusCard";
|
||||
import { SelectMenuBasic } from "./SelectMenuBasic";
|
||||
import { DEVICE_API } from "@/ui.config";
|
||||
import { useSettingsStore } from "@/hooks/stores";
|
||||
|
||||
import api from "../api";
|
||||
import { isOnDevice } from "../main";
|
||||
|
||||
import { LinkButton } from "./Button";
|
||||
|
||||
import { useReactAt } from 'i18n-auto-extractor/react'
|
||||
import enJSON from '../locales/en.json'
|
||||
import zhJSON from '../locales/zh.json'
|
||||
|
||||
import Container from "@components/Container";
|
||||
import Card from "@components/Card";
|
||||
import { useHidStore, useRTCStore, useUserStore, useVpnStore , useSettingsStore } from "@/hooks/stores";
|
||||
import LogoLuckfox from "@/assets/logo-luckfox.png";
|
||||
import USBStateStatus from "@components/Header/USBStateStatus";
|
||||
import PeerConnectionStatusCard from "@components/Header/PeerConnectionStatusCard";
|
||||
import VpnConnectionStatusCard from "@components/Header/VpnConnectionStatusCard";
|
||||
import { DEVICE_API } from "@/ui.config";
|
||||
|
||||
import { SelectMenuBasic } from "../SelectMenuBasic";
|
||||
import api from "../../api";
|
||||
import { LinkButton } from "../Button";
|
||||
import enJSON from '../../locales/en.json'
|
||||
import zhJSON from '../../locales/zh.json'
|
||||
|
||||
interface NavbarProps {
|
||||
isLoggedIn: boolean;
|
||||
@@ -67,7 +63,7 @@ export default function DashboardNavbar({
|
||||
];
|
||||
|
||||
// default language
|
||||
const {setCurrentLang,$at,langSet}= useReactAt();
|
||||
const { setCurrentLang }= useReactAt();
|
||||
|
||||
const handleLangChange = (lang: string) => {
|
||||
setLanguage(lang)
|
||||
@@ -89,9 +85,9 @@ export default function DashboardNavbar({
|
||||
<div className="flex shrink-0 items-center gap-x-8">
|
||||
<div className="inline-block shrink-0">
|
||||
<div className="flex items-center gap-4">
|
||||
<a
|
||||
href="https://wiki.luckfox.com/intro/"
|
||||
target="_blank"
|
||||
<a
|
||||
href="https://wiki.luckfox.com/intro/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-4"
|
||||
>
|
||||
@@ -1,4 +1,4 @@
|
||||
import StatusCard from "@components/StatusCards";
|
||||
import StatusCard from "@components/Header/StatusCards";
|
||||
|
||||
const PeerConnectionStatusMap = {
|
||||
connected: "Connected",
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
import { cx } from "@/cva.config";
|
||||
import KeyboardAndMouseConnectedIcon from "@/assets/keyboard-and-mouse-connected.png";
|
||||
import LoadingSpinner from "@components/LoadingSpinner";
|
||||
import StatusCard from "@components/StatusCards";
|
||||
import StatusCard from "@components/Header/StatusCards";
|
||||
import { HidState } from "@/hooks/stores";
|
||||
|
||||
type USBStates = HidState["usbState"];
|
||||
@@ -1,5 +1,4 @@
|
||||
import StatusCard from "@components/StatusCards";
|
||||
|
||||
import StatusCard from "@components/Header/StatusCards";
|
||||
import TailscaleIcon from "@/assets/tailscale.png";
|
||||
import ZeroTierIcon from "@/assets/zerotier.png";
|
||||
|
||||
@@ -13,11 +12,9 @@ const VpnConnectionStatusMap = {
|
||||
|
||||
export type VpnConnections = keyof typeof VpnConnectionStatusMap;
|
||||
|
||||
type StatusProps = {
|
||||
[key in VpnConnections]: {
|
||||
type StatusProps = Record<VpnConnections, {
|
||||
statusIndicatorClassName: string;
|
||||
};
|
||||
};
|
||||
}>;
|
||||
|
||||
export default function VpnConnectionStatusCard({
|
||||
state,
|
||||
@@ -46,24 +43,6 @@ export default function VpnConnectionStatusCard({
|
||||
};
|
||||
const props = StatusCardProps[state];
|
||||
if (!props) return;
|
||||
|
||||
const Icon = () => {
|
||||
if (title === "ZeroTier") {
|
||||
return (
|
||||
<span className="flex h-5 w-5 items-center justify-center rounded-md bg-gray-300 dark:bg-gray-800">
|
||||
<img src={ZeroTierIcon} alt="zerotier" className="h-4 w-4" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (title === "TailScale") {
|
||||
return (
|
||||
<span className="flex h-5 w-5 items-center justify-center rounded-md bg-gray-800 dark:bg-gray-800">
|
||||
<img src={TailscaleIcon} alt="tailscale" className="h-4 w-4" />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<StatusCard
|
||||
@@ -1,184 +0,0 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { cx } from "@/cva.config";
|
||||
import {
|
||||
useHidStore,
|
||||
useMouseStore,
|
||||
useRTCStore,
|
||||
useSettingsStore,
|
||||
useVideoStore,
|
||||
} from "@/hooks/stores";
|
||||
import { keys, modifiers } from "@/keyboardMappings";
|
||||
import { useReactAt } from 'i18n-auto-extractor/react'
|
||||
|
||||
export default function InfoBar() {
|
||||
const { $at } = useReactAt();
|
||||
const activeKeys = useHidStore(state => state.activeKeys);
|
||||
const activeModifiers = useHidStore(state => state.activeModifiers);
|
||||
const mouseX = useMouseStore(state => state.mouseX);
|
||||
const mouseY = useMouseStore(state => state.mouseY);
|
||||
const mouseMove = useMouseStore(state => state.mouseMove);
|
||||
|
||||
const videoClientSize = useVideoStore(
|
||||
state => `${Math.round(state.clientWidth)}x${Math.round(state.clientHeight)}`,
|
||||
);
|
||||
|
||||
const videoSize = useVideoStore(
|
||||
state => `${Math.round(state.width)}x${Math.round(state.height)}`,
|
||||
);
|
||||
|
||||
const rpcDataChannel = useRTCStore(state => state.rpcDataChannel);
|
||||
|
||||
const settings = useSettingsStore();
|
||||
const showPressedKeys = useSettingsStore(state => state.showPressedKeys);
|
||||
|
||||
useEffect(() => {
|
||||
if (!rpcDataChannel) return;
|
||||
rpcDataChannel.onclose = () => console.log("rpcDataChannel has closed");
|
||||
rpcDataChannel.onerror = e =>
|
||||
console.log(`Error on DataChannel '${rpcDataChannel.label}': ${e}`);
|
||||
}, [rpcDataChannel]);
|
||||
|
||||
const keyboardLedState = useHidStore(state => state.keyboardLedState);
|
||||
const keyboardLedStateSyncAvailable = useHidStore(state => state.keyboardLedStateSyncAvailable);
|
||||
const keyboardLedSync = useSettingsStore(state => state.keyboardLedSync);
|
||||
|
||||
const isTurnServerInUse = useRTCStore(state => state.isTurnServerInUse);
|
||||
|
||||
const usbState = useHidStore(state => state.usbState);
|
||||
const hdmiState = useVideoStore(state => state.hdmiState);
|
||||
|
||||
return (
|
||||
<div className="bg-white border-t border-t-slate-800/30 text-slate-800 dark:border-t-slate-300/20 dark:bg-slate-900 dark:text-slate-300">
|
||||
<div className="flex flex-wrap items-stretch justify-between gap-1">
|
||||
<div className="flex items-center">
|
||||
<div className="flex flex-wrap items-center pl-2 gap-x-4">
|
||||
{settings.debugMode ? (
|
||||
<div className="flex">
|
||||
<span className="text-xs font-semibold">{$at("Resolution")}:</span>{" "}
|
||||
<span className="text-xs">{videoSize}</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{settings.debugMode ? (
|
||||
<div className="flex">
|
||||
<span className="text-xs font-semibold">{$at("Video Size")}: </span>
|
||||
<span className="text-xs">{videoClientSize}</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{(settings.debugMode && settings.mouseMode == "absolute") ? (
|
||||
<div className="flex w-[118px] items-center gap-x-1">
|
||||
<span className="text-xs font-semibold">{$at("Pointer")}:</span>
|
||||
<span className="text-xs">
|
||||
{mouseX},{mouseY}
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{(settings.debugMode && settings.mouseMode == "relative") ? (
|
||||
<div className="flex w-[118px] items-center gap-x-1">
|
||||
<span className="text-xs font-semibold">{$at("Last Move")}:</span>
|
||||
<span className="text-xs">
|
||||
{mouseMove ?
|
||||
`${mouseMove.x},${mouseMove.y} ${mouseMove.buttons ? `(${mouseMove.buttons})` : ""}` :
|
||||
"N/A"}
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{settings.debugMode && (
|
||||
<div className="flex w-[156px] items-center gap-x-1">
|
||||
<span className="text-xs font-semibold">{$at("USB State")}:</span>
|
||||
<span className="text-xs">{usbState}</span>
|
||||
</div>
|
||||
)}
|
||||
{settings.debugMode && (
|
||||
<div className="flex w-[156px] items-center gap-x-1">
|
||||
<span className="text-xs font-semibold">{$at("HDMI State")}:</span>
|
||||
<span className="text-xs">{hdmiState}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showPressedKeys && (
|
||||
<div className="flex items-center gap-x-1">
|
||||
<span className="text-xs font-semibold">{$at("Keys")}:</span>
|
||||
<h2 className="text-xs">
|
||||
{[
|
||||
...activeKeys.map(
|
||||
x => Object.entries(keys).filter(y => y[1] === x)[0][0],
|
||||
),
|
||||
activeModifiers.map(
|
||||
x => Object.entries(modifiers).filter(y => y[1] === x)[0][0],
|
||||
),
|
||||
].join(", ")}
|
||||
</h2>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center divide-x first:divide-l divide-slate-800/20 dark:divide-slate-300/20">
|
||||
{isTurnServerInUse && (
|
||||
<div className="shrink-0 p-1 px-1.5 text-xs text-black dark:text-white">
|
||||
Relayed by Cloudflare
|
||||
</div>
|
||||
)}
|
||||
|
||||
{keyboardLedStateSyncAvailable ? (
|
||||
<div
|
||||
className={cx(
|
||||
"shrink-0 p-1 px-1.5 text-xs",
|
||||
keyboardLedSync !== "browser"
|
||||
? "text-black dark:text-white"
|
||||
: "text-slate-800/20 dark:text-slate-300/20",
|
||||
)}
|
||||
title={"Your keyboard LED state is managed by" + (keyboardLedSync === "browser" ? " the browser" : " the host")}
|
||||
>
|
||||
{keyboardLedSync === "browser" ? "Browser" : "Host"}
|
||||
</div>
|
||||
) : null}
|
||||
<div
|
||||
className={cx(
|
||||
"shrink-0 p-1 px-1.5 text-xs",
|
||||
keyboardLedState?.caps_lock
|
||||
? "text-black dark:text-white"
|
||||
: "text-slate-800/20 dark:text-slate-300/20",
|
||||
)}
|
||||
>
|
||||
Caps Lock
|
||||
</div>
|
||||
<div
|
||||
className={cx(
|
||||
"shrink-0 p-1 px-1.5 text-xs",
|
||||
keyboardLedState?.num_lock
|
||||
? "text-black dark:text-white"
|
||||
: "text-slate-800/20 dark:text-slate-300/20",
|
||||
)}
|
||||
>
|
||||
Num Lock
|
||||
</div>
|
||||
<div
|
||||
className={cx(
|
||||
"shrink-0 p-1 px-1.5 text-xs",
|
||||
keyboardLedState?.scroll_lock
|
||||
? "text-black dark:text-white"
|
||||
: "text-slate-800/20 dark:text-slate-300/20",
|
||||
)}
|
||||
>
|
||||
Scroll Lock
|
||||
</div>
|
||||
{keyboardLedState?.compose ? (
|
||||
<div className="shrink-0 p-1 px-1.5 text-xs">
|
||||
Compose
|
||||
</div>
|
||||
) : null}
|
||||
{keyboardLedState?.kana ? (
|
||||
<div className="shrink-0 p-1 px-1.5 text-xs">
|
||||
Kana
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import type { Ref } from "react";
|
||||
import React, { forwardRef, JSX } from "react";
|
||||
import clsx from "clsx";
|
||||
|
||||
import FieldLabel from "@/components/FieldLabel";
|
||||
import Card from "@/components/Card";
|
||||
import FieldLabel from "@components/FieldLabel";
|
||||
import Card from "@components/Card";
|
||||
import { cva } from "@/cva.config";
|
||||
|
||||
const sizes = {
|
||||
|
||||
@@ -2,10 +2,10 @@ import { MdConnectWithoutContact } from "react-icons/md";
|
||||
import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { LuEllipsisVertical } from "react-icons/lu";
|
||||
import {useReactAt} from 'i18n-auto-extractor/react'
|
||||
|
||||
import Card from "@components/Card";
|
||||
import { Button, LinkButton } from "@components/Button";
|
||||
import {useReactAt} from 'i18n-auto-extractor/react'
|
||||
|
||||
function getRelativeTimeString(date: Date | number, lang = navigator.language): string {
|
||||
// Allow dates or times to be passed
|
||||
|
||||
@@ -21,7 +21,6 @@ export default function LoadingSpinner({
|
||||
strokeWidth="4"
|
||||
/>
|
||||
<path
|
||||
// className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
/>
|
||||
|
||||
@@ -3,9 +3,12 @@ import {
|
||||
ExclamationTriangleIcon,
|
||||
InformationCircleIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { Dialog, DialogBackdrop, DialogPanel } from "@headlessui/react";
|
||||
import React from "react";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import { Button } from "@/components/Button";
|
||||
import Modal from "@/components/Modal";
|
||||
import { Button } from "@components/Button";
|
||||
import Modal from "@components/Modal";
|
||||
import { cx } from "@/cva.config";
|
||||
|
||||
type Variant = "danger" | "success" | "warning" | "info";
|
||||
@@ -72,6 +75,7 @@ export default function Ansi({ children, className }: AnsiProps) {
|
||||
|
||||
const lines: { text: string; style: (React.CSSProperties | undefined)[] }[] = [];
|
||||
let col = 0;
|
||||
const ESC = "\u001b";
|
||||
|
||||
const applyCode = (code: number) => {
|
||||
if (code === 0) { curColor = undefined; curBold = false; }
|
||||
@@ -94,11 +98,49 @@ export default function Ansi({ children, className }: AnsiProps) {
|
||||
return stylePool[key];
|
||||
};
|
||||
|
||||
const tokens = children.split(/(\x1b\[[0-9;]*m|\r\n?|\n)/g);
|
||||
const tokens: string[] = [];
|
||||
let i = 0;
|
||||
while (i < children.length) {
|
||||
const ch = children[i];
|
||||
if (ch === "\r") {
|
||||
if (children[i + 1] === "\n") {
|
||||
tokens.push("\r\n");
|
||||
i += 2;
|
||||
continue;
|
||||
}
|
||||
tokens.push("\r");
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (ch === "\n") {
|
||||
tokens.push("\n");
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
if (ch === ESC && children[i + 1] === "[") {
|
||||
let j = i + 2;
|
||||
while (j < children.length && children[j] !== "m") j += 1;
|
||||
if (j < children.length) {
|
||||
tokens.push(children.slice(i, j + 1));
|
||||
i = j + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let j = i;
|
||||
while (j < children.length) {
|
||||
const c = children[j];
|
||||
const isNewline = c === "\n" || c === "\r";
|
||||
const isEsc = c === ESC && children[j + 1] === "[";
|
||||
if (isNewline || isEsc) break;
|
||||
j += 1;
|
||||
}
|
||||
tokens.push(children.slice(i, j));
|
||||
i = j;
|
||||
}
|
||||
let currentLine = { text: '', style: [] as (React.CSSProperties | undefined)[] };
|
||||
|
||||
for (const chunk of tokens) {
|
||||
if (chunk.startsWith('\x1b[') && chunk.endsWith('m')) {
|
||||
if (chunk.startsWith(`${ESC}[`) && chunk.endsWith('m')) {
|
||||
const codes = chunk.slice(2, -1).split(';').map(Number);
|
||||
codes.forEach(applyCode);
|
||||
} else if (chunk === '\r\n' || chunk === '\n') {
|
||||
@@ -153,10 +195,63 @@ export function LogDialog({
|
||||
}: LogDialogProps) {
|
||||
const { icon: Icon, iconClass, iconBgClass } = variantConfig[variant];
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
if (isMobile) {
|
||||
return (
|
||||
<Dialog open={open} onClose={onClose} className="relative z-[99999]">
|
||||
<DialogBackdrop
|
||||
transition
|
||||
className="fixed inset-0 bg-gray-500/75 transition-opacity data-closed:opacity-0 data-enter:duration-300 data-leave:duration-200 data-enter:ease-out data-leave:ease-in dark:bg-slate-900/90"
|
||||
/>
|
||||
<div className="fixed inset-0 z-[99999] w-screen overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4">
|
||||
<DialogPanel
|
||||
transition
|
||||
className="relative w-full max-w-sm transform overflow-hidden rounded-lg bg-white p-6 text-left shadow-xl transition-all data-closed:translate-y-4 data-closed:opacity-0 data-enter:duration-300 data-leave:duration-200 data-enter:ease-out data-leave:ease-in dark:bg-[rgb(26,26,26)]"
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-col items-center text-center">
|
||||
<div
|
||||
className={cx(
|
||||
"mx-auto flex size-12 shrink-0 items-center justify-center rounded-full",
|
||||
iconBgClass,
|
||||
)}
|
||||
>
|
||||
<Icon aria-hidden="true" className={cx("size-6", iconClass)} />
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<h2 className="text-lg font-bold leading-6 text-gray-900 dark:text-white">
|
||||
{title}
|
||||
</h2>
|
||||
<div className="mt-2">
|
||||
<div className="text-sm text-gray-500 dark:text-gray-300">
|
||||
<Ansi>{description}</Ansi>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-6 sm:grid sm:grid-flow-row-dense sm:grid-cols-2 sm:gap-3">
|
||||
<Button
|
||||
size="LG"
|
||||
theme="light"
|
||||
text={cancelText || "Close"}
|
||||
onClick={onClose}
|
||||
className="w-full justify-center col-span-2"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DialogPanel>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={onClose}>
|
||||
<div className="mx-auto max-w-4xl px-3 transition-all duration-300 ease-in-out">
|
||||
<div className="pointer-events-auto relative w-full overflow-hidden rounded-lg bg-white p-5 text-left align-middle shadow-xl transition-all dark:bg-slate-800">
|
||||
<div className="pointer-events-auto relative w-full overflow-hidden rounded-lg bg-white p-5 text-left align-middle shadow-xl transition-all dark:bg-[rgb(26,26,26)]">
|
||||
<div className="space-y-3">
|
||||
<div className="sm:flex sm:items-start">
|
||||
<div
|
||||
@@ -171,7 +266,7 @@ export function LogDialog({
|
||||
<h3 className="text-lg leading-tight font-bold text-black dark:text-white">
|
||||
{title}
|
||||
</h3>
|
||||
<div className="mt-2 text-sm leading-snug text-slate-600 dark:text-slate-400">
|
||||
<div className="mt-2 text-sm leading-snug text-slate-600 dark:text-[#ffffff]">
|
||||
<Ansi>{description}</Ansi>
|
||||
</div>
|
||||
</div>
|
||||
@@ -179,7 +274,7 @@ export function LogDialog({
|
||||
|
||||
<div className="flex justify-end gap-x-1">
|
||||
{cancelText && (
|
||||
<Button size="SM" theme="blank" text={cancelText} onClick={onClose} />
|
||||
<Button size="SM" theme="light" text={cancelText} onClick={onClose} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
|
||||
import { cva } from "@/cva.config";
|
||||
|
||||
import Card from "./Card";
|
||||
import Card from "../Card";
|
||||
|
||||
export interface ComboboxOption {
|
||||
value: string;
|
||||
@@ -78,7 +78,7 @@ export function Combobox({
|
||||
|
||||
// Disabled
|
||||
disabled &&
|
||||
"pointer-events-none select-none bg-slate-50 text-slate-500/80 disabled:hover:bg-white dark:bg-slate-800 dark:text-slate-400/80 dark:disabled:hover:bg-slate-800",
|
||||
"pointer-events-none select-none bg-slate-50 text-slate-500/80 disabled:hover:bg-white dark:bg-slate-800 dark:text-[#ffffff]/80 dark:disabled:hover:bg-slate-800",
|
||||
)}
|
||||
placeholder={disabled ? disabledMessage : placeholder}
|
||||
displayValue={displayValue}
|
||||
@@ -112,7 +112,7 @@ export function Combobox({
|
||||
|
||||
{options().length === 0 && inputRef.current?.value && (
|
||||
<div className="absolute left-0 z-100 mt-1 w-full rounded-md bg-white px-4 py-2 text-sm shadow-lg ring-1 ring-black/5 dark:bg-slate-800 dark:ring-slate-700">
|
||||
<div className="text-slate-500 dark:text-slate-400">{emptyMessage}</div>
|
||||
<div className="text-slate-500 dark:text-[#ffffff]">{emptyMessage}</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
@@ -1,19 +1,20 @@
|
||||
import { useState } from "react";
|
||||
import { LuPlus } from "react-icons/lu";
|
||||
import {useReactAt} from 'i18n-auto-extractor/react'
|
||||
import {Button as AntdButton} from "antd";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import { KeySequence } from "@/hooks/stores";
|
||||
import { Button } from "@/components/Button";
|
||||
import { InputFieldWithLabel, FieldError } from "@/components/InputField";
|
||||
import Fieldset from "@/components/Fieldset";
|
||||
import { MacroStepCard } from "@/components/MacroStepCard";
|
||||
import { Button } from "@components/Button";
|
||||
import { InputFieldWithLabel, FieldError } from "@components/InputField";
|
||||
import Fieldset from "@components/Fieldset";
|
||||
import { MacroStepCard } from "@components/Macro/MacroStepCard";
|
||||
import {
|
||||
DEFAULT_DELAY,
|
||||
MAX_STEPS_PER_MACRO,
|
||||
MAX_KEYS_PER_STEP,
|
||||
} from "@/constants/macros";
|
||||
import FieldLabel from "@/components/FieldLabel";
|
||||
import {useReactAt} from 'i18n-auto-extractor/react'
|
||||
|
||||
import FieldLabel from "@components/FieldLabel";
|
||||
interface ValidationErrors {
|
||||
name?: string;
|
||||
steps?: Record<
|
||||
@@ -173,6 +174,7 @@ export function MacroForm({
|
||||
return (
|
||||
<>
|
||||
<div className="space-y-4">
|
||||
|
||||
<Fieldset>
|
||||
<InputFieldWithLabel
|
||||
type="text"
|
||||
@@ -189,6 +191,7 @@ export function MacroForm({
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
</Fieldset>
|
||||
|
||||
<div>
|
||||
@@ -199,7 +202,7 @@ export function MacroForm({
|
||||
description={$at("Keys/modifiers executed in sequence with a delay between each step.")}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-slate-500 dark:text-slate-400">
|
||||
<span className="text-slate-500 dark:text-[#ffffff]">
|
||||
{macro.steps?.length || 0}/{MAX_STEPS_PER_MACRO} steps
|
||||
</span>
|
||||
</div>
|
||||
@@ -218,10 +221,10 @@ export function MacroForm({
|
||||
onDelete={
|
||||
macro.steps && macro.steps.length > 1
|
||||
? () => {
|
||||
const newSteps = [...(macro.steps || [])];
|
||||
newSteps.splice(stepIndex, 1);
|
||||
setMacro(prev => ({ ...prev, steps: newSteps }));
|
||||
}
|
||||
const newSteps = [...(macro.steps || [])];
|
||||
newSteps.splice(stepIndex, 1);
|
||||
setMacro(prev => ({ ...prev, steps: newSteps }));
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
onMoveUp={() => handleStepMove(stepIndex, "up")}
|
||||
@@ -273,17 +276,26 @@ export function MacroForm({
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-6 flex items-center gap-x-2">
|
||||
<Button
|
||||
size="SM"
|
||||
theme="primary"
|
||||
text={isSubmitting ? $at("Saving...") : $at("Save")}
|
||||
|
||||
<div className={` ${isMobile ? "w-full flex justify-between mt-2" : "mt-6 flex items-center gap-x-2"}`}>
|
||||
<AntdButton
|
||||
type="primary"
|
||||
onClick={handleSubmit}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
<Button size="SM" theme="light" text={$at("Cancel")} onClick={onCancel} />
|
||||
className={isMobile ? "w-[49%]" : ""}
|
||||
disabled={isSubmitting}>
|
||||
|
||||
{isSubmitting ? $at("Saving...") : $at("Save")}
|
||||
</AntdButton>
|
||||
<AntdButton
|
||||
className={isMobile ? "w-[49%]" : ""}
|
||||
onClick={onCancel}>
|
||||
|
||||
{$at("Cancel")}
|
||||
</AntdButton>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{isMobile&&<div className="h-[50px]"></div>}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
@@ -1,13 +1,17 @@
|
||||
import { LuArrowUp, LuArrowDown, LuX, LuTrash2 } from "react-icons/lu";
|
||||
import { LuX } from "react-icons/lu";
|
||||
import { Button as AntdButton } from "antd";
|
||||
import { useReactAt } from 'i18n-auto-extractor/react'
|
||||
import UpSVG from "@assets/second/up.svg?react";
|
||||
import DownSVG from "@assets/second/down.svg?react";
|
||||
import DeleteSVG from "@assets/second/delete.svg?react";
|
||||
|
||||
import { Button } from "@/components/Button";
|
||||
import { Combobox } from "@/components/Combobox";
|
||||
import { SelectMenuBasic } from "@/components/SelectMenuBasic";
|
||||
import Card from "@/components/Card";
|
||||
import { Button } from "@components/Button";
|
||||
import { Combobox } from "@components/Macro/Combobox";
|
||||
import { SelectMenuBasic } from "@components/SelectMenuBasic";
|
||||
import Card from "@components/Card";
|
||||
import { keys, modifiers, keyDisplayMap } from "@/keyboardMappings";
|
||||
import { MAX_KEYS_PER_STEP, DEFAULT_DELAY } from "@/constants/macros";
|
||||
import FieldLabel from "@/components/FieldLabel";
|
||||
import {useReactAt} from 'i18n-auto-extractor/react'
|
||||
import FieldLabel from "@components/FieldLabel";
|
||||
|
||||
// Filter out modifier keys since they're handled in the modifiers section
|
||||
const modifierKeyPrefixes = ['Alt', 'Control', 'Shift', 'Meta'];
|
||||
@@ -104,9 +108,11 @@ export function MacroStepCard({
|
||||
<Card className="p-4">
|
||||
<div className="mb-2 flex items-center justify-between">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="flex h-6 w-5 items-center justify-center rounded-full bg-blue-100 text-xs font-semibold text-blue-700 dark:bg-blue-900/40 dark:text-blue-200">
|
||||
{stepIndex + 1}
|
||||
</span>
|
||||
<AntdButton
|
||||
type={"primary"}
|
||||
shape="circle"
|
||||
>{stepIndex + 1}
|
||||
</AntdButton>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
@@ -116,25 +122,23 @@ export function MacroStepCard({
|
||||
theme="light"
|
||||
onClick={onMoveUp}
|
||||
disabled={stepIndex === 0}
|
||||
LeadingIcon={LuArrowUp}
|
||||
LeadingIcon={UpSVG}
|
||||
/>
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
onClick={onMoveDown}
|
||||
disabled={isLastStep}
|
||||
LeadingIcon={LuArrowDown}
|
||||
LeadingIcon={DownSVG}
|
||||
/>
|
||||
</div>
|
||||
{onDelete && (
|
||||
<Button
|
||||
size="XS"
|
||||
theme="light"
|
||||
className="text-red-500 dark:text-red-400"
|
||||
text={$at("Delete")}
|
||||
LeadingIcon={LuTrash2}
|
||||
{(onDelete && stepIndex!==0) &&(
|
||||
<div
|
||||
onClick={onDelete}
|
||||
/>
|
||||
className={"w-[26px] h-[26px] flex items-center justify-center bg-[red] rounded"}
|
||||
>
|
||||
<DeleteSVG />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -145,7 +149,7 @@ export function MacroStepCard({
|
||||
<div className="inline-flex flex-wrap gap-3">
|
||||
{Object.entries(groupedModifiers).map(([group, mods]) => (
|
||||
<div key={group} className="relative min-w-[120px] rounded-md border border-slate-200 dark:border-slate-700 p-2">
|
||||
<span className="absolute -top-2.5 left-2 px-1 text-xs font-medium bg-white dark:bg-slate-800 text-slate-500 dark:text-slate-400">
|
||||
<span className="absolute -top-2.5 left-2 px-1 text-xs font-medium bg-white dark:bg-slate-800 text-slate-500 dark:text-[#ffffff]">
|
||||
{group}
|
||||
</span>
|
||||
<div className="flex flex-wrap gap-4 pt-1">
|
||||
211
ui/src/components/MousePanel.tsx
Normal file
@@ -0,0 +1,211 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Divider } from "antd";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { useReactAt } from "i18n-auto-extractor/react";
|
||||
|
||||
import ScrollThrottlingSelect, { Option } from "@components/ScrollThrottlingSelect";
|
||||
import { useSettingsStore } from "@/hooks/stores";
|
||||
import { useFeatureFlag } from "@/hooks/useFeatureFlag";
|
||||
import { useJsonRpc } from "@/hooks/useJsonRpc";
|
||||
import notifications from "@/notifications";
|
||||
import { dark_bd_style, dark_bg2_style, dark_line_style, dark_bg_style_fun } from "@/layout/theme_color";
|
||||
import { useThemeSettings } from "@routes/login_page/useLocalAuth";
|
||||
|
||||
|
||||
const scrollThrottlingOptions = [
|
||||
{ value: "0", label: "Off" },
|
||||
{ value: "10", label: "Low" },
|
||||
{ value: "25", label: "Medium" },
|
||||
{ value: "50", label: "High" },
|
||||
{ value: "100", label: "Very High" },
|
||||
];
|
||||
|
||||
const inputModeOptions: Option[] = [
|
||||
{ label: "Absolute", value: "absolute" },
|
||||
{ label: "Relative", value: "relative" },
|
||||
];
|
||||
|
||||
const othersOptions: Option[] = [
|
||||
{ label: "Hide Cursor", value: "hide-cursor" },
|
||||
{ label: "Jiggler", value: "jiggler" },
|
||||
];
|
||||
|
||||
const MousePanel: React.FC = () => {
|
||||
const { $at } = useReactAt();
|
||||
const hideCursor: boolean = useSettingsStore(state => state.isCursorHidden);
|
||||
const setHideCursor = useSettingsStore(state => state.setCursorVisibility);
|
||||
const { isEnabled: isScrollSensitivityEnabled } = useFeatureFlag("0.3.8");
|
||||
const [send] = useJsonRpc();
|
||||
const [others, setOthers] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
send("getJigglerState", {}, (resp) => {
|
||||
if (!("error" in resp) && resp.result) {
|
||||
setOthers((prevItems: string[]) => [...prevItems, "jiggler"]);
|
||||
} else {
|
||||
setOthers((prevItems) => prevItems.filter(item => item !== "jiggler"));
|
||||
}
|
||||
});
|
||||
}, [isScrollSensitivityEnabled, send]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hideCursor) {
|
||||
setOthers((prevItems: string[]) => [...prevItems, "hide-cursor"]);
|
||||
} else {
|
||||
setOthers((prevItems) => prevItems.filter(item => item !== "hide-cursor"));
|
||||
}
|
||||
}, [hideCursor]);
|
||||
|
||||
const handleOtherChange = (data: string[] | string) => {
|
||||
console.log(data);
|
||||
console.log(data.includes("jiggler"));
|
||||
console.log(others.includes("jiggler"));
|
||||
if (data.includes("hide-cursor") != others.includes("hide-cursor")) {
|
||||
handlehideCursorChange(data.includes("hide-cursor"));
|
||||
}
|
||||
if (data.includes("jiggler") != others.includes("jiggler")) {
|
||||
handleJigglerChange(data.includes("jiggler"));
|
||||
}
|
||||
};
|
||||
|
||||
const handlehideCursorChange = (enabled: boolean) => {
|
||||
console.log("handlehideCursorChange", enabled);
|
||||
setHideCursor(enabled);
|
||||
};
|
||||
|
||||
const handleJigglerChange = (enabled: boolean) => {
|
||||
console.log("handleJigglerChange", enabled);
|
||||
send("setJigglerState", { enabled }, resp => {
|
||||
if ("error" in resp) {
|
||||
notifications.error(
|
||||
`Failed to set jiggler state: ${resp.error.data || "Unknown error"}`,
|
||||
);
|
||||
} else {
|
||||
if (enabled) {
|
||||
console.log("handleJigglerChange if", enabled);
|
||||
setOthers((prevItems: string[]) => [...prevItems, "jiggler"]);
|
||||
} else {
|
||||
console.log("handleJigglerChange el", enabled);
|
||||
setOthers((prevItems) => prevItems.filter(item => item !== "jiggler"));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const mouseMode = useSettingsStore(state => state.mouseMode);
|
||||
const setMouseMode = useSettingsStore(state => state.setMouseMode);
|
||||
const [modeData, setModeData] = useState<string>(mouseMode);
|
||||
|
||||
useEffect(() => {
|
||||
setModeData(mouseMode);
|
||||
}, [mouseMode]);
|
||||
|
||||
const handleModeChange = (data: string[] | string) => {
|
||||
setMouseMode(data as string);
|
||||
};
|
||||
const scrollThrottling = useSettingsStore(state => state.scrollThrottling);
|
||||
const setScrollThrottling = useSettingsStore(state => state.setScrollThrottling);
|
||||
const [scrollData, setScrollData] = useState<string>(String(scrollThrottling));
|
||||
|
||||
useEffect(() => {
|
||||
setScrollData(String(scrollThrottling));
|
||||
}, [scrollThrottling]);
|
||||
|
||||
const handleScrollChange = (data: string[] | string) => {
|
||||
setScrollThrottling(Number(data as string));
|
||||
};
|
||||
const DividerLine = ({isMobile = false}: {isMobile?: boolean}) => {
|
||||
if (isMobile) {
|
||||
return (
|
||||
<div className="px-[20px] w-full">
|
||||
<Divider size={"small"} className="my-0" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <div className={`w-full h-px my-2 ${dark_line_style}`} />
|
||||
};
|
||||
|
||||
const { isDark } = useThemeSettings();
|
||||
|
||||
if (isMobile) {
|
||||
return (
|
||||
<div className={`w-full h-full flex flex-col ${dark_bg_style_fun(isDark)}`}>
|
||||
<div className={`
|
||||
flex flex-col w-full mx-auto
|
||||
${isDark ? 'text-white' : 'text-black'}
|
||||
`}>
|
||||
<div className="px-[20px] pt-4">
|
||||
<ScrollThrottlingSelect
|
||||
mode="single"
|
||||
title={$at("Scroll Throttling")}
|
||||
options={scrollThrottlingOptions}
|
||||
value={scrollData}
|
||||
onChange={handleScrollChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DividerLine isMobile={true} />
|
||||
|
||||
{/* Input Modes */}
|
||||
<div className="px-[20px]">
|
||||
<ScrollThrottlingSelect
|
||||
mode="single"
|
||||
title={$at("Input Modes")}
|
||||
options={inputModeOptions}
|
||||
value={modeData}
|
||||
onChange={handleModeChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<DividerLine isMobile={true} />
|
||||
|
||||
{/* Others */}
|
||||
<div className="px-[20px]">
|
||||
<ScrollThrottlingSelect
|
||||
mode="multiple"
|
||||
title={$at("Others")}
|
||||
options={othersOptions}
|
||||
value={others}
|
||||
onChange={handleOtherChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
<div className="flex flex-col justify-between w-full h-full"></div>
|
||||
return (
|
||||
<div style={{boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)'}} className={` ${isMobile ? 'px-[20px] pt-5 h-full w-full' : 'p-4 w-[240px] rounded'} font-sans ${dark_bg2_style} border ${dark_bd_style}`}>
|
||||
<div className={`w-full h-full flex flex-col justify-between`}>
|
||||
<ScrollThrottlingSelect
|
||||
mode="single"
|
||||
title={$at("Scroll Throttling")}
|
||||
options={scrollThrottlingOptions}
|
||||
value={scrollData}
|
||||
onChange={handleScrollChange}
|
||||
/>
|
||||
|
||||
<DividerLine />
|
||||
<ScrollThrottlingSelect
|
||||
mode="single"
|
||||
title={$at("Input Modes")}
|
||||
options={inputModeOptions}
|
||||
value={modeData}
|
||||
onChange={handleModeChange}
|
||||
/>
|
||||
|
||||
<DividerLine />
|
||||
<ScrollThrottlingSelect
|
||||
mode="multiple"
|
||||
title={$at("Others")}
|
||||
options={othersOptions}
|
||||
value={others}
|
||||
onChange={handleOtherChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MousePanel;
|
||||
389
ui/src/components/Network/DhcpLeaseCard.tsx
Normal file
@@ -0,0 +1,389 @@
|
||||
import { Button } from "antd";
|
||||
import {useReactAt} from 'i18n-auto-extractor/react'
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import { GridCard } from "@components/Card";
|
||||
import { LifeTimeLabel } from "@/layout/components_setting/network/NetworkContent";
|
||||
import { NetworkState } from "@/hooks/stores";
|
||||
|
||||
export default function DhcpLeaseCard({
|
||||
networkState,
|
||||
setShowRenewLeaseConfirm,
|
||||
}: {
|
||||
networkState: NetworkState;
|
||||
setShowRenewLeaseConfirm: (show: boolean) => void;
|
||||
}) {
|
||||
const { $at }= useReactAt();
|
||||
return (
|
||||
<GridCard>
|
||||
<div className="animate-fadeIn p-4 opacity-0 animation-duration-500 text-black dark:text-white">
|
||||
<div className="space-y-3">
|
||||
<h3 className="text-base font-bold text-slate-900 dark:text-white">
|
||||
{$at("DHCP Lease Information")}
|
||||
</h3>
|
||||
{isMobile ?
|
||||
<div className="flex gap-x-6 gap-y-2">
|
||||
<div className="flex-1 space-y-2">
|
||||
{networkState?.dhcp_lease?.ip && (
|
||||
<div className="flex justify-between border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("IP Address")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ip}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.netmask && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Subnet Mask")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.netmask}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.dns && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("DNS Servers")}
|
||||
</span>
|
||||
<span className="text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.dns.map(dns => <div key={dns}>{dns}</div>)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.broadcast && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Broadcast Address")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.broadcast}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.domain && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Domain")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.domain}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.ntp_servers &&
|
||||
networkState?.dhcp_lease?.ntp_servers.length > 0 && (
|
||||
<div
|
||||
className="flex justify-between gap-x-8 border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<div className="w-full grow text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("NTP Servers")}
|
||||
</div>
|
||||
<div className="shrink text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ntp_servers.map(server => (
|
||||
<div key={server}>{server}</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.hostname && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Hostname")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.hostname}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.routers &&
|
||||
networkState?.dhcp_lease?.routers.length > 0 && (
|
||||
<div className="flex justify-between pt-2">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Gateways")}
|
||||
</span>
|
||||
<span className="text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.routers.map(router => (
|
||||
<div key={router}>{router}</div>
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.server_id && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("DHCP Server")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.server_id}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.lease_expiry && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Lease Expiry")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
<LifeTimeLabel
|
||||
lifetime={`${networkState?.dhcp_lease?.lease_expiry}`}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.mtu && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">MTU</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.mtu}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.ttl && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">TTL</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ttl}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.bootp_next_server && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Boot Next Server")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_next_server}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.bootp_server_name && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Boot Server Name")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_server_name}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.bootp_file && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Boot File")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_file}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="flex gap-x-6 gap-y-2">
|
||||
<div className="flex-1 space-y-2">
|
||||
{networkState?.dhcp_lease?.ip && (
|
||||
<div className="flex justify-between border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("IP Address")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ip}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.netmask && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Subnet Mask")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.netmask}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.dns && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("DNS Servers")}
|
||||
</span>
|
||||
<span className="text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.dns.map(dns => <div key={dns}>{dns}</div>)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.broadcast && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Broadcast Address")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.broadcast}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.domain && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Domain")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.domain}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.ntp_servers &&
|
||||
networkState?.dhcp_lease?.ntp_servers.length > 0 && (
|
||||
<div
|
||||
className="flex justify-between gap-x-8 border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<div className="w-full grow text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("NTP Servers")}
|
||||
</div>
|
||||
<div className="shrink text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ntp_servers.map(server => (
|
||||
<div key={server}>{server}</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.hostname && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Hostname")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.hostname}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex-1 space-y-2">
|
||||
{networkState?.dhcp_lease?.routers &&
|
||||
networkState?.dhcp_lease?.routers.length > 0 && (
|
||||
<div className="flex justify-between pt-2">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Gateways")}
|
||||
</span>
|
||||
<span className="text-right text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.routers.map(router => (
|
||||
<div key={router}>{router}</div>
|
||||
))}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.server_id && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("DHCP Server")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.server_id}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.lease_expiry && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Lease Expiry")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
<LifeTimeLabel
|
||||
lifetime={`${networkState?.dhcp_lease?.lease_expiry}`}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.mtu && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">MTU</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.mtu}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.ttl && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">TTL</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.ttl}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.bootp_next_server && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Boot Next Server")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_next_server}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.bootp_server_name && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Boot Server Name")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_server_name}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{networkState?.dhcp_lease?.bootp_file && (
|
||||
<div className="flex justify-between border-t border-slate-800/10 pt-2 dark:border-slate-300/20">
|
||||
<span className="text-sm text-slate-600 dark:text-[#ffffff]">
|
||||
{$at("Boot File")}
|
||||
</span>
|
||||
<span className="text-sm font-medium">
|
||||
{networkState?.dhcp_lease?.bootp_file}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
<div>
|
||||
<Button
|
||||
className={"!h-[36px] !text-[rgba(20,204,45,1)] !border-[rgba(20,204,45,1)]"}
|
||||
|
||||
onClick={() => setShowRenewLeaseConfirm(true)}>
|
||||
{$at("Renew DHCP Lease")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GridCard>
|
||||
);
|
||||
}
|
||||