feat: add new brand logos
Desktop Client Build / Resolve Build Metadata (push) Successful in 26s
Frontend CI / Frontend (push) Successful in 3m23s
Backend CI / Backend (push) Successful in 16m58s
Desktop Client Build / Build Desktop Client (push) Successful in 24m56s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 36s

- Introduced icon-color.svg featuring a colorful gradient design.
- Added icon-with-title.svg that includes a title and multiple gradient elements.
This commit is contained in:
2026-05-31 23:05:27 +08:00
parent e490a267ff
commit e07a87224d
21 changed files with 787 additions and 135 deletions
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 900 900">
<defs>
<style>
.cls-1 {
fill: url(#_未命名的渐变_117);
}
.cls-2 {
fill: #fff;
}
.cls-3 {
fill: url(#_未命名的渐变_117-4);
}
.cls-4 {
fill: url(#_未命名的渐变_117-3);
}
.cls-5 {
fill: url(#_未命名的渐变_117-2);
}
</style>
<linearGradient id="_未命名的渐变_117" data-name="未命名的渐变 117" x1="648.54" y1="275.8" x2="291.97" y2="632.36" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1fbdff"/>
<stop offset=".21" stop-color="#1f95ff"/>
<stop offset=".39" stop-color="#1f7aff"/>
<stop offset=".5" stop-color="#1f70ff"/>
<stop offset=".56" stop-color="#346aff"/>
<stop offset=".68" stop-color="#5363ff"/>
<stop offset=".8" stop-color="#695dff"/>
<stop offset=".9" stop-color="#775aff"/>
<stop offset="1" stop-color="#7c59ff"/>
</linearGradient>
<linearGradient id="_未命名的渐变_117-2" data-name="未命名的渐变 117" x1="334.48" y1="300.38" x2="237.75" y2="397.11" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-3" data-name="未命名的渐变 117" x1="334.48" y1="513.55" x2="237.75" y2="610.28" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-4" data-name="未命名的渐变 117" x1="184.94" y1="406.97" x2="88.21" y2="503.7" xlink:href="#_未命名的渐变_117"/>
</defs>
<g>
<path class="cls-1" d="M431.78,191.83c47.7,29.16,93.74,61.17,140.75,91.31,61.67,39.54,123.67,78.46,185.08,118.08,13.94,8.99,28.96,17.08,42.33,26.88,12.45,9.12,19.73,22.01,16.27,37.98-4.67,21.53-27.1,27.57-42.33,39.67l-350.42,210.03c-24.63,12.54-61.03,3.3-64.37-27.48-1.37-12.57-1.04-39.06-.02-51.93,1.15-14.55,11.18-21.89,25.2-22.94,34.84-2.61,81.1,13.67,80.94-37.98-.05-14.61-2.02-30.28-.77-45.08,2.62-31.16,29.16-25.73,52.31-25.93,3.52-.03,6.99.03,10.47,0,19.47-.17,43.14,2.83,50.21-20.57,2.55-8.42,2.37-45.83,1.35-55.79-1.4-13.75-13.53-22.62-26.71-23.69-21.73-1.77-45.71,1.28-67.69,0-8.26.75-15.57,4.92-17.51,13.33-2.1,24.07,2.19,51.34-.19,75.02-1.14,11.38-11.1,16.21-21.4,16.96-18.66,1.35-42.17.21-60.94-.81-9.52-.52-19.57,1.52-24.63-9.22-2.87-6.08-1.31-10.84-1.32-16.66-.04-19.48-1.84-41.36-.82-60.24.63-11.61,5.81-21.54,18.46-22.91,17.86-1.94,62.96,4.03,76.3-2.7,8.55-4.32,11.53-11.78,12.15-20.95,1.3-19.12-2.01-39.36-.85-58.64-9.13-39.63-59.23-18.6-87.4-25.44-10.01-2.43-16.6-10.46-17.79-20.58-2.2-18.85,1.42-41.52-.02-60.78,3.48-16.54,13.78-27.93,30.59-31.09,17.72-3.33,28.57,3.48,42.77,12.16Z"/>
<rect class="cls-5" x="232.47" y="295.46" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
<rect class="cls-4" x="232.47" y="508.63" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
<rect class="cls-3" x="82.93" y="402.04" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 900 900">
<!-- Generator: Adobe Illustrator 30.0.0, SVG Export Plug-In . SVG Version: 2.1.1 Build 123) -->
<defs>
<style>
.st0 {
fill: #fff;
}
</style>
</defs>
<path class="st0" d="M431.78,191.83c47.7,29.16,93.74,61.17,140.75,91.31,61.67,39.54,123.67,78.46,185.08,118.08,13.94,8.99,28.96,17.08,42.33,26.88,12.45,9.12,19.73,22.01,16.27,37.98-4.67,21.53-27.1,27.57-42.33,39.67l-350.42,210.03c-24.63,12.54-61.03,3.3-64.37-27.48-1.37-12.57-1.04-39.06-.02-51.93,1.15-14.55,11.18-21.89,25.2-22.94,34.84-2.61,81.1,13.67,80.94-37.98-.05-14.61-2.02-30.28-.77-45.08,2.62-31.16,29.16-25.73,52.31-25.93,3.52-.03,6.99.03,10.47,0,19.47-.17,43.14,2.83,50.21-20.57,2.55-8.42,2.37-45.83,1.35-55.79-1.4-13.75-13.53-22.62-26.71-23.69-21.73-1.77-45.71,1.28-67.69,0-8.26.75-15.57,4.92-17.51,13.33-2.1,24.07,2.19,51.34-.19,75.02-1.14,11.38-11.1,16.21-21.4,16.96-18.66,1.35-42.17.21-60.94-.81-9.52-.52-19.57,1.52-24.63-9.22-2.87-6.08-1.31-10.84-1.32-16.66-.04-19.48-1.84-41.36-.82-60.24.63-11.61,5.81-21.54,18.46-22.91,17.86-1.94,62.96,4.03,76.3-2.7,8.55-4.32,11.53-11.78,12.15-20.95,1.3-19.12-2.01-39.36-.85-58.64-9.13-39.63-59.23-18.6-87.4-25.44-10.01-2.43-16.6-10.46-17.79-20.58-2.2-18.85,1.42-41.52-.02-60.78,3.48-16.54,13.78-27.93,30.59-31.09,17.72-3.33,28.57,3.48,42.77,12.16h0Z"/>
<rect class="st0" x="232.47" y="295.46" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
<rect class="st0" x="232.47" y="508.63" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
<rect class="st0" x="82.93" y="402.04" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 800.3 239.55">
<defs>
<style>
.cls-1 {
fill: url(#_未命名的渐变_117);
}
.cls-2 {
fill: #000000;
}
.cls-3 {
fill: url(#_未命名的渐变_117-4);
}
.cls-4 {
fill: url(#_未命名的渐变_117-3);
}
.cls-5 {
fill: url(#_未命名的渐变_117-2);
}
</style>
<linearGradient id="_未命名的渐变_117" data-name="未命名的渐变 117" x1="731.38" y1="39.67" x2="585.56" y2="185.48" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1fbdff"/>
<stop offset=".21" stop-color="#1f95ff"/>
<stop offset=".39" stop-color="#1f7aff"/>
<stop offset=".5" stop-color="#1f70ff"/>
<stop offset=".56" stop-color="#346aff"/>
<stop offset=".68" stop-color="#5363ff"/>
<stop offset=".8" stop-color="#695dff"/>
<stop offset=".9" stop-color="#775aff"/>
<stop offset="1" stop-color="#7c59ff"/>
</linearGradient>
<linearGradient id="_未命名的渐变_117-2" data-name="未命名的渐变 117" x1="602.95" y1="49.72" x2="563.39" y2="89.28" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-3" data-name="未命名的渐变 117" x1="602.95" y1="136.9" x2="563.39" y2="176.45" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-4" data-name="未命名的渐变 117" x1="541.8" y1="93.31" x2="502.24" y2="132.87" xlink:href="#_未命名的渐变_117"/>
</defs>
<g>
<path class="cls-1" d="M642.74,5.33c19.51,11.92,38.33,25.02,57.56,37.34,25.22,16.17,50.57,32.09,75.69,48.29,5.7,3.68,11.84,6.98,17.31,10.99,5.09,3.73,8.07,9,6.65,15.53-1.91,8.8-11.08,11.27-17.31,16.22l-143.3,85.89c-10.07,5.13-24.96,1.35-26.32-11.24-.56-5.14-.42-15.97,0-21.24.47-5.95,4.57-8.95,10.31-9.38,14.25-1.07,33.17,5.59,33.1-15.53-.02-5.97-.82-12.38-.32-18.44,1.07-12.74,11.92-10.52,21.39-10.6,1.44-.01,2.86.01,4.28,0,7.96-.07,17.64,1.16,20.53-8.41,1.04-3.45.97-18.74.55-22.82-.57-5.62-5.53-9.25-10.92-9.69-8.89-.72-18.69.53-27.68,0-3.38.31-6.37,2.01-7.16,5.45-.86,9.84.89,21-.08,30.68-.47,4.65-4.54,6.63-8.75,6.94-7.63.55-17.25.09-24.92-.33-3.89-.21-8,.62-10.07-3.77-1.17-2.49-.54-4.43-.54-6.81-.02-7.97-.75-16.92-.33-24.63.26-4.75,2.38-8.81,7.55-9.37,7.3-.79,25.75,1.65,31.2-1.1,3.5-1.77,4.71-4.82,4.97-8.57.53-7.82-.82-16.09-.35-23.98-3.74-16.21-24.22-7.61-35.74-10.41-4.09-.99-6.79-4.28-7.27-8.42-.9-7.71.58-16.98,0-24.85,1.42-6.76,5.64-11.42,12.51-12.71,7.25-1.36,11.68,1.42,17.49,4.97Z"/>
<rect class="cls-5" x="561.23" y="47.71" width="43.88" height="43.59" rx="7.13" ry="7.13"/>
<rect class="cls-4" x="561.23" y="134.88" width="43.88" height="43.59" rx="7.13" ry="7.13"/>
<rect class="cls-3" x="500.08" y="91.29" width="43.88" height="43.59" rx="7.13" ry="7.13"/>
</g>
<g>
<path class="cls-2" d="M0,57.64l.46-.27c7.68-.44,15.43-1.77,22.99-3.16,29.23-5.4,57.7-14.17,85.16-25.32l.7.14,8.7,10.87c.31.39.14.65-.19.94-13.33,5.8-26.75,11.41-40.25,16.8l61.01.27.28,1c-.6,23.72.76,47.8,0,71.47-.01.43-.15.75-.18,1.11-.03.46.43.91-.2,1.26l-121.8.07-.02-61.2H.27l-.27-.27v-13.71ZM119.81,72.53H36.22v7.32h83.59v-7.32ZM119.81,91.73H36.22v7.13h83.59v-7.13ZM36.02,110.91v7.68h83.79v-7.68H36.02Z"/>
<path class="cls-2" d="M461.32,21.55v15.08l-.27.27h-25.88v16.27l23.78.27v14.62s-.28.32-.37.36c-6.58.03-13.26.28-19.85.1-1.07-.03-2.59-.58-3.56.08v16.36h23.69l.27.27v14.89h-23.96v16.45h28.9v15.44s-.29.51-.37.55l-72.51-.26c-.61.15-.25,2.26-1.13,2.49l-18.36.04-.19-76.94c-4.3.04-8.6-.05-12.9,0-.7,0-1.04.34-1.85.03-.19-.07-.31.09-.25-.29.76-.63,1.19-1.5,1.68-2.35,9.24-16.15,16.46-33.39,25.14-49.81.37-.69.71-1.45,1.26-2.03h18.57l-8.6,18.09,24.33.18-8.39-18.15c.18-.54.9-.12,1.34-.11,4.54.12,9.37.09,13.92,0,1.02-.02,2.6-.65,3.35.29l8.53,17.79h23.69ZM417.24,36.9h-26.71l.08,79.51,26.63.36.18-16.63h-23.69c-.1,0-.4.29-.64.18l.09-14.98c.04-.09.33-.37.36-.37h23.6l.27-.27v-16.17h-24.24c-.09,0-.3-.3-.28-.45l.36-14.63,23.98-.08v-16.45Z"/>
<path class="cls-2" d="M216.94,114.57h62.28c.06,0,.28.24.46.18v17.45l-.27.27h-81.4c-.33,0-.44-.72-.47-.99-.26-2.63.19-5.44.19-8.05.06-30.55.11-61.36-.07-91.89-.02-4.2-.41-8.86-.12-13.01.03-.41.04-1.36.65-1.36h18.47l.27.27v97.13Z"/>
<path class="cls-2" d="M332.91,22.28l.18-18.37.3-.43c.72.12,1.55-.2,2.17-.21,4.46-.03,9.05.17,13.55.19.48,0,1.54-.3,1.87.04l.32,18.78h12.16v14.53c0,.06-.24.28-.18.46h-12.16l-.09,30.88,12.07-3.94.75.22-.42,15.74-12.37,4.36-.17,36.38c-2.21,3.76-4.14,7.75-6.48,11.44-.19.3-.5.91-.82,1.01l-23.12-.26c-.19-.38-.02-.6.16-.93,1.2-2.24,3.04-4.7,4.39-6.95,2.67-4.42,5.27-8.89,7.86-13.35.4-7.12.17-14.28.23-21.43-1.93.18-15.14,5.42-15.8,4.93-.24-.18-.33-.31-.31-.62l.05-14.78.34-.39,15.73-5.31v-36.73l-.27-.27h-15.64v-14.99h15.73Z"/>
<path class="cls-2" d="M288.69,111.42l-10.73-49.68c-1.69-8.32-4.13-16.51-5.91-24.8-.12-.54-.44-1.88-.43-2.33.04-1.17,1.42-.44,2.12-.44,4.77,0,9.62.04,14.46,0,1.5-.01,2.03-.7,2.59,1.23,2.1,7.24,3.38,15.34,5.04,22.75,3.83,17.13,8.11,34.26,11.61,51.45.1.47.46,1.68.07,1.97l-18.81-.15Z"/>
<path class="cls-2" d="M177.61,111.46c-.64-.14-1.36.14-1.92.15-4.1.01-8.17-.03-12.25.04-.77.01-5.31.11-5.51-.18l-.07-.63c7.4-25.03,11.48-50.88,16.36-76.5.49-.8,2.75-.17,3.48-.18,2.08-.03,4.12-.01,6.2,0,2.63.02,5.23-.12,7.85-.17.84.27-.1,2.46-.21,3.03-3.24,18.04-6.5,36-9.78,54.01l-4.16,20.42Z"/>
<path class="cls-2" d="M246.12,3.45c.1.02.42.18.46.32.76,3.3,1.34,6.65,2.06,9.96,4.04,18.57,7.87,37.58,12.2,55.82l.37,3.71h-18.66l-6.08-30.93c-2.12-12.11-5.79-24.42-7.73-36.5-.07-.44-.56-2.38.19-2.38h17.19Z"/>
<path class="cls-2" d="M51.4,8.39c.23.93-.74,1.44-1.28,2.11-8.38,10.34-17.21,20.34-25.8,30.51l-22.08-.04-.23-.31c.24-.8,1.01-1.13,1.56-1.74,9.05-10.08,18.02-20.25,26.89-30.52h20.94Z"/>
<path class="cls-2" d="M129.04,16.35c6.55,7.97,13.06,16.05,19.68,23.93,0,.9-1.81.42-2.48.45-5.46.28-10.96.09-16.46.17l-.72.57-.1-.53c-.37-.05-.72.05-1.09-.11-.25-.11-2.68-3.02-3.11-3.52-7.85-9.15-15.2-18.73-23.13-27.82l-.28-1.09,20.68-.1.62.3c2.18,2.55,4.27,5.18,6.4,7.77Z"/>
<path class="cls-2" d="M62.92,3.55c.1-.58.89-.61,1.37-.65,5.5-.43,11.59.3,17.16.05,1.52.17,1.09,3.18,1.06,4.44-.18,8.19.11,16.48-.18,24.67-.03.92,0,1.88-.35,2.75-.38.47-10.46,2.05-11.95,2.32-1.34.24-5.67,1.41-6.64,1.23-.2-.04-.34-.09-.46-.28V3.55Z"/>
<g>
<path class="cls-2" d="M58.37,156.95l-3.17,12.69h-25.13l-2.92,11.84h21.36l-3.26,12.87h-21.36l-3.35,13.55h26.08l-3.17,12.87H2.01l15.87-63.82h40.49Z"/>
<path class="cls-2" d="M101.76,193.75l-6.69,27.02h-12.35v-4.37c-4.98,3.6-9.86,5.58-14.67,5.58-9.61,0-13.81-7.38-11.67-16.3,2.4-9.52,11.15-14.49,30.88-17.24,1.2-3.86.09-5.49-4.29-5.49s-9.01,1.89-14.32,4.63l-3.95-10.72c7.46-3.86,14.84-6.09,21.87-6.09,13.21,0,18.96,7.72,15.18,22.99ZM85.89,198.55c-9.86,1.29-14.32,4.63-15.35,8.84-.6,2.06.77,2.74,3.34,2.74,3.69,0,6.43-1.97,9.18-4.37l2.83-7.21Z"/>
<path class="cls-2" d="M133.15,183.89h-17.33l2.92-11.92h36.63l-1.8,8.15-26.93,28.73h20.16l-2.92,11.92h-39.46l1.8-8.15,26.93-28.73Z"/>
<path class="cls-2" d="M146.44,238.44l4.46-11.24c.86.17,2.06.43,2.57.43,5.23,0,8.83-3.09,10.64-6.52l1.46-1.8-6.69-47.35h15.01l1.29,20.93c.34,4.46.26,9.01.09,13.81l1.03-1.37c2.14-4.63,4.37-9.18,6.52-13.81l10.64-19.56h14.75l-28.99,49.58c-7.89,12.52-14.15,18.01-25.13,18.01-3.77,0-5.66-.51-7.63-1.12Z"/>
<path class="cls-2" d="M242.16,156.95c14.07,0,24.87,5.66,20.76,22.22-3.6,14.41-16.3,20.41-29.76,20.41h-8.06l-5.23,21.19h-15.35l15.87-63.82h21.79ZM248.68,176.25c1.46-5.66-1.72-7.2-9.09-7.2h-6.86l-4.63,18.44h6.09c7.46,0,12.78-4.2,14.5-11.24Z"/>
<path class="cls-2" d="M266.51,201.47l7.29-29.51h15.27l-7.2,28.99c-1.72,6.78-.77,7.98,2.49,7.98,4.03,0,6.95-1.97,10.38-5.58l8.15-31.39h15.27l-12.09,48.8h-12.35l.51-6.69-.17.51c-5.23,4.8-10.21,7.38-16.3,7.38-11.24,0-14.32-8.32-11.24-20.5Z"/>
<path class="cls-2" d="M315.83,214.68l8.23-8.66c3.6,3.43,7.21,4.72,10.46,4.72,4.63,0,7.46-2.14,8.23-5.32.6-2.14-3.34-3.17-7.29-5.4-5.83-1.97-12.18-6.35-9.95-15.18,2.14-8.49,10.46-14.07,21.19-14.07,8.32,0,13.04,3.52,16.81,6.69l-8.23,8.23c-2.83-2.4-5.83-3.69-8.49-3.69-4.03,0-6.78,1.89-7.55,4.98-.51,2.14,3.17,2.83,7.21,4.89,6.09,2.06,12.44,6,10.04,15.61-2.06,8.23-10.04,14.5-22.73,14.5-6.95,0-13.81-3.17-17.93-7.29Z"/>
<path class="cls-2" d="M394.31,152.24l-4.03,16.47-3.26,8.15c4.38-3.26,9.69-6.09,15.7-6.09,11.24,0,14.32,8.32,11.24,20.5l-7.29,29.51h-15.27l7.2-28.99c1.63-6.69.77-7.98-2.49-7.98-4.03,0-6.78,2.06-10.46,4.89l-8.41,32.08h-15.18l17.07-68.53h15.18Z"/>
<path class="cls-2" d="M426.04,210.91c1.2-4.55,5.75-7.98,10.98-7.98,6.43,0,10.04,4.8,8.58,10.89-1.2,4.72-5.66,7.98-10.98,7.98-6.35,0-10.12-4.63-8.58-10.89ZM440.36,156.61h18.78l-3.95,14.24-10.29,27.1h-10.72l3.26-27.1,2.92-14.24Z"/>
</g>
<g>
<path class="cls-2" d="M477.32,5.77h-7.2v-2.53h17.41v2.53h-7.2v21.23h-3.01V5.77Z"/>
<path class="cls-2" d="M491.77,3.24h3.63l4.57,12.71c.55,1.65,1.1,3.31,1.69,4.96h.16c.55-1.65,1.07-3.31,1.62-4.96l4.54-12.71h3.63v23.76h-2.82v-13.16c0-2.04.23-4.93.39-7h-.13l-1.88,5.41-4.51,12.35h-2.01l-4.51-12.35-1.88-5.41h-.13c.13,2.07.36,4.96.36,7v13.16h-2.72V3.24Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.0 KiB

+48 -21
View File
@@ -522,9 +522,19 @@ onBeforeUnmount(() => {
class="admin-sider" class="admin-sider"
:class="{ 'admin-sider--collapsed': siderCollapsed }" :class="{ 'admin-sider--collapsed': siderCollapsed }"
> >
<div class="admin-brand"> <div class="admin-brand" :aria-label="t('app.name')">
<span class="admin-brand__full">{{ t('app.name') }}</span> <img
<span class="admin-brand__short"></span> class="admin-brand__logo admin-brand__logo--full"
src="/logos/icon-with-title.svg"
alt=""
aria-hidden="true"
/>
<img
class="admin-brand__logo admin-brand__logo--icon"
src="/logos/icon-color.svg"
alt=""
aria-hidden="true"
/>
</div> </div>
<a-menu <a-menu
@@ -804,8 +814,13 @@ onBeforeUnmount(() => {
:closable="false" :closable="false"
:body-style="{ padding: 0 }" :body-style="{ padding: 0 }"
> >
<div class="admin-brand admin-brand--drawer"> <div class="admin-brand admin-brand--drawer" :aria-label="t('app.name')">
{{ t('app.name') }} <img
class="admin-brand__logo admin-brand__logo--full"
src="/logos/icon-with-title.svg"
alt=""
aria-hidden="true"
/>
</div> </div>
<a-menu mode="inline" theme="light" :selected-keys="selectedKeys" class="admin-menu"> <a-menu mode="inline" theme="light" :selected-keys="selectedKeys" class="admin-menu">
@@ -921,40 +936,52 @@ onBeforeUnmount(() => {
} }
.admin-brand { .admin-brand {
height: 40px; height: 38px;
background: #f0f8ff; margin: 14px 24px 18px;
border: 1px solid #bae0ff; padding: 0;
margin: 16px;
border-radius: 6px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
color: #1677ff; overflow: hidden;
font-weight: 800;
font-size: 16px;
letter-spacing: 0.05em;
white-space: nowrap;
transition: transition:
margin 0.2s ease, margin 0.2s ease,
width 0.2s ease; width 0.2s ease;
} }
.admin-brand__short { .admin-brand__logo {
display: block;
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.admin-brand__logo--full {
width: 128px;
height: 38px;
}
.admin-brand__logo--icon {
display: none; display: none;
letter-spacing: 0; width: 34px;
height: 34px;
} }
.admin-sider--collapsed .admin-brand { .admin-sider--collapsed .admin-brand {
width: 40px; width: 40px;
margin-inline: auto; margin: 14px auto 18px;
justify-content: center;
} }
.admin-sider--collapsed .admin-brand__full { .admin-sider--collapsed .admin-brand__logo--full {
display: none; display: none;
} }
.admin-sider--collapsed .admin-brand__short { .admin-sider--collapsed .admin-brand__logo--icon {
display: inline; display: block;
}
.admin-brand--drawer {
margin: 16px 20px;
} }
.admin-menu { .admin-menu {
+17 -21
View File
@@ -7,8 +7,7 @@
}" }"
> >
<div class="brand"> <div class="brand">
<div class="brand-icon"><StarOutlined :style="{ fontSize: '16px' }" /></div> <img class="brand-logo brand-logo--white" src="/logos/icon-with-title.svg" :alt="t('app.name')" />
<span>{{ t('app.name') }}</span>
</div> </div>
<div class="characters-area"> <div class="characters-area">
<AnimatedCharacters <AnimatedCharacters
@@ -29,8 +28,7 @@
<div class="right"> <div class="right">
<div class="form-wrapper"> <div class="form-wrapper">
<div class="mobile-brand"> <div class="mobile-brand">
<div class="brand-icon"><StarOutlined :style="{ fontSize: '16px' }" /></div> <img class="brand-logo brand-logo--mobile" src="/logos/icon-with-title.svg" :alt="t('app.name')" />
<span>{{ t('app.name') }}</span>
</div> </div>
<div class="header"> <div class="header">
<h1>{{ t('auth.welcomeBack') }}</h1> <h1>{{ t('auth.welcomeBack') }}</h1>
@@ -88,7 +86,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { EyeInvisibleOutlined, EyeOutlined, StarOutlined } from '@ant-design/icons-vue' import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { onMounted, reactive, ref } from 'vue' import { onMounted, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
@@ -202,19 +200,17 @@ async function handleSubmit(): Promise<void> {
z-index: 20; z-index: 20;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px;
font-size: 18px;
font-weight: 600;
} }
.brand-icon {
width: 32px; .brand-logo {
height: 32px; display: block;
border-radius: 8px; width: 184px;
background: rgba(255, 255, 255, 0.1); height: auto;
backdrop-filter: blur(8px); object-fit: contain;
display: flex; }
align-items: center;
justify-content: center; .brand-logo--white {
filter: brightness(0) invert(1);
} }
.characters-area { .characters-area {
position: relative; position: relative;
@@ -410,11 +406,11 @@ async function handleSubmit(): Promise<void> {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 8px;
font-size: 18px;
font-weight: 600;
margin-bottom: 48px; margin-bottom: 48px;
color: #18181b; }
.brand-logo--mobile {
width: 156px;
} }
} }
</style> </style>
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 30 KiB

@@ -97,6 +97,7 @@ export default defineConfig({
// Single source of truth for the brand mark; lives in public/ so the // Single source of truth for the brand mark; lives in public/ so the
// main process and electron-builder can read the same file. // main process and electron-builder can read the same file.
'@brand-logo': resolve(rootDir, 'public/logo.svg'), '@brand-logo': resolve(rootDir, 'public/logo.svg'),
'@brand-logo-full': resolve(rootDir, 'public/icon-with-title.svg'),
...workspaceAliases, ...workspaceAliases,
}, },
}, },
+46
View File
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 900 900">
<defs>
<style>
.cls-1 {
fill: url(#_未命名的渐变_117);
}
.cls-2 {
fill: #fff;
}
.cls-3 {
fill: url(#_未命名的渐变_117-4);
}
.cls-4 {
fill: url(#_未命名的渐变_117-3);
}
.cls-5 {
fill: url(#_未命名的渐变_117-2);
}
</style>
<linearGradient id="_未命名的渐变_117" data-name="未命名的渐变 117" x1="648.54" y1="275.8" x2="291.97" y2="632.36" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1fbdff"/>
<stop offset=".21" stop-color="#1f95ff"/>
<stop offset=".39" stop-color="#1f7aff"/>
<stop offset=".5" stop-color="#1f70ff"/>
<stop offset=".56" stop-color="#346aff"/>
<stop offset=".68" stop-color="#5363ff"/>
<stop offset=".8" stop-color="#695dff"/>
<stop offset=".9" stop-color="#775aff"/>
<stop offset="1" stop-color="#7c59ff"/>
</linearGradient>
<linearGradient id="_未命名的渐变_117-2" data-name="未命名的渐变 117" x1="334.48" y1="300.38" x2="237.75" y2="397.11" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-3" data-name="未命名的渐变 117" x1="334.48" y1="513.55" x2="237.75" y2="610.28" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-4" data-name="未命名的渐变 117" x1="184.94" y1="406.97" x2="88.21" y2="503.7" xlink:href="#_未命名的渐变_117"/>
</defs>
<g>
<path class="cls-1" d="M431.78,191.83c47.7,29.16,93.74,61.17,140.75,91.31,61.67,39.54,123.67,78.46,185.08,118.08,13.94,8.99,28.96,17.08,42.33,26.88,12.45,9.12,19.73,22.01,16.27,37.98-4.67,21.53-27.1,27.57-42.33,39.67l-350.42,210.03c-24.63,12.54-61.03,3.3-64.37-27.48-1.37-12.57-1.04-39.06-.02-51.93,1.15-14.55,11.18-21.89,25.2-22.94,34.84-2.61,81.1,13.67,80.94-37.98-.05-14.61-2.02-30.28-.77-45.08,2.62-31.16,29.16-25.73,52.31-25.93,3.52-.03,6.99.03,10.47,0,19.47-.17,43.14,2.83,50.21-20.57,2.55-8.42,2.37-45.83,1.35-55.79-1.4-13.75-13.53-22.62-26.71-23.69-21.73-1.77-45.71,1.28-67.69,0-8.26.75-15.57,4.92-17.51,13.33-2.1,24.07,2.19,51.34-.19,75.02-1.14,11.38-11.1,16.21-21.4,16.96-18.66,1.35-42.17.21-60.94-.81-9.52-.52-19.57,1.52-24.63-9.22-2.87-6.08-1.31-10.84-1.32-16.66-.04-19.48-1.84-41.36-.82-60.24.63-11.61,5.81-21.54,18.46-22.91,17.86-1.94,62.96,4.03,76.3-2.7,8.55-4.32,11.53-11.78,12.15-20.95,1.3-19.12-2.01-39.36-.85-58.64-9.13-39.63-59.23-18.6-87.4-25.44-10.01-2.43-16.6-10.46-17.79-20.58-2.2-18.85,1.42-41.52-.02-60.78,3.48-16.54,13.78-27.93,30.59-31.09,17.72-3.33,28.57,3.48,42.77,12.16Z"/>
<rect class="cls-5" x="232.47" y="295.46" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
<rect class="cls-4" x="232.47" y="508.63" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
<rect class="cls-3" x="82.93" y="402.04" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 800.3 239.55">
<defs>
<style>
.cls-1 {
fill: url(#_未命名的渐变_117);
}
.cls-2 {
fill: #000000;
}
.cls-3 {
fill: url(#_未命名的渐变_117-4);
}
.cls-4 {
fill: url(#_未命名的渐变_117-3);
}
.cls-5 {
fill: url(#_未命名的渐变_117-2);
}
</style>
<linearGradient id="_未命名的渐变_117" data-name="未命名的渐变 117" x1="731.38" y1="39.67" x2="585.56" y2="185.48" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1fbdff"/>
<stop offset=".21" stop-color="#1f95ff"/>
<stop offset=".39" stop-color="#1f7aff"/>
<stop offset=".5" stop-color="#1f70ff"/>
<stop offset=".56" stop-color="#346aff"/>
<stop offset=".68" stop-color="#5363ff"/>
<stop offset=".8" stop-color="#695dff"/>
<stop offset=".9" stop-color="#775aff"/>
<stop offset="1" stop-color="#7c59ff"/>
</linearGradient>
<linearGradient id="_未命名的渐变_117-2" data-name="未命名的渐变 117" x1="602.95" y1="49.72" x2="563.39" y2="89.28" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-3" data-name="未命名的渐变 117" x1="602.95" y1="136.9" x2="563.39" y2="176.45" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-4" data-name="未命名的渐变 117" x1="541.8" y1="93.31" x2="502.24" y2="132.87" xlink:href="#_未命名的渐变_117"/>
</defs>
<g>
<path class="cls-1" d="M642.74,5.33c19.51,11.92,38.33,25.02,57.56,37.34,25.22,16.17,50.57,32.09,75.69,48.29,5.7,3.68,11.84,6.98,17.31,10.99,5.09,3.73,8.07,9,6.65,15.53-1.91,8.8-11.08,11.27-17.31,16.22l-143.3,85.89c-10.07,5.13-24.96,1.35-26.32-11.24-.56-5.14-.42-15.97,0-21.24.47-5.95,4.57-8.95,10.31-9.38,14.25-1.07,33.17,5.59,33.1-15.53-.02-5.97-.82-12.38-.32-18.44,1.07-12.74,11.92-10.52,21.39-10.6,1.44-.01,2.86.01,4.28,0,7.96-.07,17.64,1.16,20.53-8.41,1.04-3.45.97-18.74.55-22.82-.57-5.62-5.53-9.25-10.92-9.69-8.89-.72-18.69.53-27.68,0-3.38.31-6.37,2.01-7.16,5.45-.86,9.84.89,21-.08,30.68-.47,4.65-4.54,6.63-8.75,6.94-7.63.55-17.25.09-24.92-.33-3.89-.21-8,.62-10.07-3.77-1.17-2.49-.54-4.43-.54-6.81-.02-7.97-.75-16.92-.33-24.63.26-4.75,2.38-8.81,7.55-9.37,7.3-.79,25.75,1.65,31.2-1.1,3.5-1.77,4.71-4.82,4.97-8.57.53-7.82-.82-16.09-.35-23.98-3.74-16.21-24.22-7.61-35.74-10.41-4.09-.99-6.79-4.28-7.27-8.42-.9-7.71.58-16.98,0-24.85,1.42-6.76,5.64-11.42,12.51-12.71,7.25-1.36,11.68,1.42,17.49,4.97Z"/>
<rect class="cls-5" x="561.23" y="47.71" width="43.88" height="43.59" rx="7.13" ry="7.13"/>
<rect class="cls-4" x="561.23" y="134.88" width="43.88" height="43.59" rx="7.13" ry="7.13"/>
<rect class="cls-3" x="500.08" y="91.29" width="43.88" height="43.59" rx="7.13" ry="7.13"/>
</g>
<g>
<path class="cls-2" d="M0,57.64l.46-.27c7.68-.44,15.43-1.77,22.99-3.16,29.23-5.4,57.7-14.17,85.16-25.32l.7.14,8.7,10.87c.31.39.14.65-.19.94-13.33,5.8-26.75,11.41-40.25,16.8l61.01.27.28,1c-.6,23.72.76,47.8,0,71.47-.01.43-.15.75-.18,1.11-.03.46.43.91-.2,1.26l-121.8.07-.02-61.2H.27l-.27-.27v-13.71ZM119.81,72.53H36.22v7.32h83.59v-7.32ZM119.81,91.73H36.22v7.13h83.59v-7.13ZM36.02,110.91v7.68h83.79v-7.68H36.02Z"/>
<path class="cls-2" d="M461.32,21.55v15.08l-.27.27h-25.88v16.27l23.78.27v14.62s-.28.32-.37.36c-6.58.03-13.26.28-19.85.1-1.07-.03-2.59-.58-3.56.08v16.36h23.69l.27.27v14.89h-23.96v16.45h28.9v15.44s-.29.51-.37.55l-72.51-.26c-.61.15-.25,2.26-1.13,2.49l-18.36.04-.19-76.94c-4.3.04-8.6-.05-12.9,0-.7,0-1.04.34-1.85.03-.19-.07-.31.09-.25-.29.76-.63,1.19-1.5,1.68-2.35,9.24-16.15,16.46-33.39,25.14-49.81.37-.69.71-1.45,1.26-2.03h18.57l-8.6,18.09,24.33.18-8.39-18.15c.18-.54.9-.12,1.34-.11,4.54.12,9.37.09,13.92,0,1.02-.02,2.6-.65,3.35.29l8.53,17.79h23.69ZM417.24,36.9h-26.71l.08,79.51,26.63.36.18-16.63h-23.69c-.1,0-.4.29-.64.18l.09-14.98c.04-.09.33-.37.36-.37h23.6l.27-.27v-16.17h-24.24c-.09,0-.3-.3-.28-.45l.36-14.63,23.98-.08v-16.45Z"/>
<path class="cls-2" d="M216.94,114.57h62.28c.06,0,.28.24.46.18v17.45l-.27.27h-81.4c-.33,0-.44-.72-.47-.99-.26-2.63.19-5.44.19-8.05.06-30.55.11-61.36-.07-91.89-.02-4.2-.41-8.86-.12-13.01.03-.41.04-1.36.65-1.36h18.47l.27.27v97.13Z"/>
<path class="cls-2" d="M332.91,22.28l.18-18.37.3-.43c.72.12,1.55-.2,2.17-.21,4.46-.03,9.05.17,13.55.19.48,0,1.54-.3,1.87.04l.32,18.78h12.16v14.53c0,.06-.24.28-.18.46h-12.16l-.09,30.88,12.07-3.94.75.22-.42,15.74-12.37,4.36-.17,36.38c-2.21,3.76-4.14,7.75-6.48,11.44-.19.3-.5.91-.82,1.01l-23.12-.26c-.19-.38-.02-.6.16-.93,1.2-2.24,3.04-4.7,4.39-6.95,2.67-4.42,5.27-8.89,7.86-13.35.4-7.12.17-14.28.23-21.43-1.93.18-15.14,5.42-15.8,4.93-.24-.18-.33-.31-.31-.62l.05-14.78.34-.39,15.73-5.31v-36.73l-.27-.27h-15.64v-14.99h15.73Z"/>
<path class="cls-2" d="M288.69,111.42l-10.73-49.68c-1.69-8.32-4.13-16.51-5.91-24.8-.12-.54-.44-1.88-.43-2.33.04-1.17,1.42-.44,2.12-.44,4.77,0,9.62.04,14.46,0,1.5-.01,2.03-.7,2.59,1.23,2.1,7.24,3.38,15.34,5.04,22.75,3.83,17.13,8.11,34.26,11.61,51.45.1.47.46,1.68.07,1.97l-18.81-.15Z"/>
<path class="cls-2" d="M177.61,111.46c-.64-.14-1.36.14-1.92.15-4.1.01-8.17-.03-12.25.04-.77.01-5.31.11-5.51-.18l-.07-.63c7.4-25.03,11.48-50.88,16.36-76.5.49-.8,2.75-.17,3.48-.18,2.08-.03,4.12-.01,6.2,0,2.63.02,5.23-.12,7.85-.17.84.27-.1,2.46-.21,3.03-3.24,18.04-6.5,36-9.78,54.01l-4.16,20.42Z"/>
<path class="cls-2" d="M246.12,3.45c.1.02.42.18.46.32.76,3.3,1.34,6.65,2.06,9.96,4.04,18.57,7.87,37.58,12.2,55.82l.37,3.71h-18.66l-6.08-30.93c-2.12-12.11-5.79-24.42-7.73-36.5-.07-.44-.56-2.38.19-2.38h17.19Z"/>
<path class="cls-2" d="M51.4,8.39c.23.93-.74,1.44-1.28,2.11-8.38,10.34-17.21,20.34-25.8,30.51l-22.08-.04-.23-.31c.24-.8,1.01-1.13,1.56-1.74,9.05-10.08,18.02-20.25,26.89-30.52h20.94Z"/>
<path class="cls-2" d="M129.04,16.35c6.55,7.97,13.06,16.05,19.68,23.93,0,.9-1.81.42-2.48.45-5.46.28-10.96.09-16.46.17l-.72.57-.1-.53c-.37-.05-.72.05-1.09-.11-.25-.11-2.68-3.02-3.11-3.52-7.85-9.15-15.2-18.73-23.13-27.82l-.28-1.09,20.68-.1.62.3c2.18,2.55,4.27,5.18,6.4,7.77Z"/>
<path class="cls-2" d="M62.92,3.55c.1-.58.89-.61,1.37-.65,5.5-.43,11.59.3,17.16.05,1.52.17,1.09,3.18,1.06,4.44-.18,8.19.11,16.48-.18,24.67-.03.92,0,1.88-.35,2.75-.38.47-10.46,2.05-11.95,2.32-1.34.24-5.67,1.41-6.64,1.23-.2-.04-.34-.09-.46-.28V3.55Z"/>
<g>
<path class="cls-2" d="M58.37,156.95l-3.17,12.69h-25.13l-2.92,11.84h21.36l-3.26,12.87h-21.36l-3.35,13.55h26.08l-3.17,12.87H2.01l15.87-63.82h40.49Z"/>
<path class="cls-2" d="M101.76,193.75l-6.69,27.02h-12.35v-4.37c-4.98,3.6-9.86,5.58-14.67,5.58-9.61,0-13.81-7.38-11.67-16.3,2.4-9.52,11.15-14.49,30.88-17.24,1.2-3.86.09-5.49-4.29-5.49s-9.01,1.89-14.32,4.63l-3.95-10.72c7.46-3.86,14.84-6.09,21.87-6.09,13.21,0,18.96,7.72,15.18,22.99ZM85.89,198.55c-9.86,1.29-14.32,4.63-15.35,8.84-.6,2.06.77,2.74,3.34,2.74,3.69,0,6.43-1.97,9.18-4.37l2.83-7.21Z"/>
<path class="cls-2" d="M133.15,183.89h-17.33l2.92-11.92h36.63l-1.8,8.15-26.93,28.73h20.16l-2.92,11.92h-39.46l1.8-8.15,26.93-28.73Z"/>
<path class="cls-2" d="M146.44,238.44l4.46-11.24c.86.17,2.06.43,2.57.43,5.23,0,8.83-3.09,10.64-6.52l1.46-1.8-6.69-47.35h15.01l1.29,20.93c.34,4.46.26,9.01.09,13.81l1.03-1.37c2.14-4.63,4.37-9.18,6.52-13.81l10.64-19.56h14.75l-28.99,49.58c-7.89,12.52-14.15,18.01-25.13,18.01-3.77,0-5.66-.51-7.63-1.12Z"/>
<path class="cls-2" d="M242.16,156.95c14.07,0,24.87,5.66,20.76,22.22-3.6,14.41-16.3,20.41-29.76,20.41h-8.06l-5.23,21.19h-15.35l15.87-63.82h21.79ZM248.68,176.25c1.46-5.66-1.72-7.2-9.09-7.2h-6.86l-4.63,18.44h6.09c7.46,0,12.78-4.2,14.5-11.24Z"/>
<path class="cls-2" d="M266.51,201.47l7.29-29.51h15.27l-7.2,28.99c-1.72,6.78-.77,7.98,2.49,7.98,4.03,0,6.95-1.97,10.38-5.58l8.15-31.39h15.27l-12.09,48.8h-12.35l.51-6.69-.17.51c-5.23,4.8-10.21,7.38-16.3,7.38-11.24,0-14.32-8.32-11.24-20.5Z"/>
<path class="cls-2" d="M315.83,214.68l8.23-8.66c3.6,3.43,7.21,4.72,10.46,4.72,4.63,0,7.46-2.14,8.23-5.32.6-2.14-3.34-3.17-7.29-5.4-5.83-1.97-12.18-6.35-9.95-15.18,2.14-8.49,10.46-14.07,21.19-14.07,8.32,0,13.04,3.52,16.81,6.69l-8.23,8.23c-2.83-2.4-5.83-3.69-8.49-3.69-4.03,0-6.78,1.89-7.55,4.98-.51,2.14,3.17,2.83,7.21,4.89,6.09,2.06,12.44,6,10.04,15.61-2.06,8.23-10.04,14.5-22.73,14.5-6.95,0-13.81-3.17-17.93-7.29Z"/>
<path class="cls-2" d="M394.31,152.24l-4.03,16.47-3.26,8.15c4.38-3.26,9.69-6.09,15.7-6.09,11.24,0,14.32,8.32,11.24,20.5l-7.29,29.51h-15.27l7.2-28.99c1.63-6.69.77-7.98-2.49-7.98-4.03,0-6.78,2.06-10.46,4.89l-8.41,32.08h-15.18l17.07-68.53h15.18Z"/>
<path class="cls-2" d="M426.04,210.91c1.2-4.55,5.75-7.98,10.98-7.98,6.43,0,10.04,4.8,8.58,10.89-1.2,4.72-5.66,7.98-10.98,7.98-6.35,0-10.12-4.63-8.58-10.89ZM440.36,156.61h18.78l-3.95,14.24-10.29,27.1h-10.72l3.26-27.1,2.92-14.24Z"/>
</g>
<g>
<path class="cls-2" d="M477.32,5.77h-7.2v-2.53h17.41v2.53h-7.2v21.23h-3.01V5.77Z"/>
<path class="cls-2" d="M491.77,3.24h3.63l4.57,12.71c.55,1.65,1.1,3.31,1.69,4.96h.16c.55-1.65,1.07-3.31,1.62-4.96l4.54-12.71h3.63v23.76h-2.82v-13.16c0-2.04.23-4.93.39-7h-.13l-1.88,5.41-4.51,12.35h-2.01l-4.51-12.35-1.88-5.41h-.13c.13,2.07.36,4.96.36,7v13.16h-2.72V3.24Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.0 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -1,7 +1,8 @@
#!/usr/bin/env node #!/usr/bin/env node
/* /*
* Generates every brand icon asset the desktop client needs from the single * Generates every brand icon asset the desktop client needs from SVG sources.
* source of truth: public/logo.svg. * Most assets come from public/logo.svg; the Windows tray icon uses the
* colored public/icon-color.svg variant.
* *
* Outputs: * Outputs:
* build/icon.icns macOS app icon (electron-builder) * build/icon.icns macOS app icon (electron-builder)
@@ -10,7 +11,7 @@
* src/main/brand-icons.ts base64 icons consumed by the main process * src/main/brand-icons.ts base64 icons consumed by the main process
* (tray + dock + window + Windows overlay) * (tray + dock + window + Windows overlay)
* *
* Re-run after changing public/logo.svg: * Re-run after changing public/logo.svg or public/icon-color.svg:
* node scripts/generate-brand-icons.cjs * node scripts/generate-brand-icons.cjs
* *
* Requires `rsvg-convert`, `sips` and `iconutil` (preinstalled on macOS via * Requires `rsvg-convert`, `sips` and `iconutil` (preinstalled on macOS via
@@ -20,16 +21,17 @@ const { execFileSync } = require('node:child_process')
const fs = require('node:fs') const fs = require('node:fs')
const os = require('node:os') const os = require('node:os')
const path = require('node:path') const path = require('node:path')
const zlib = require('node:zlib')
const APP_DIR = path.resolve(__dirname, '..') const APP_DIR = path.resolve(__dirname, '..')
const LOGO_PATH = path.join(APP_DIR, 'public', 'logo.svg') const LOGO_PATH = path.join(APP_DIR, 'public', 'logo.svg')
const WINDOWS_TRAY_LOGO_PATH = path.join(APP_DIR, 'public', 'icon-color.svg')
const BUILD_DIR = path.join(APP_DIR, 'build') const BUILD_DIR = path.join(APP_DIR, 'build')
const OUT_TS = path.join(APP_DIR, 'src', 'main', 'brand-icons.ts') const OUT_TS = path.join(APP_DIR, 'src', 'main', 'brand-icons.ts')
// Brand palette — keep in sync with the renderer (#1677ff is Ant Design blue). // Brand palette — keep in sync with the renderer (#1677ff is Ant Design blue).
const BRAND_BLUE = '#1677ff' const BRAND_BLUE = '#1677ff'
const DANGER_RED = '#ff4d4f' const DANGER_RED = '#ff4d4f'
const LOGO_FILL = '#dfdfdf' // the fill baked into logo.svg
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'brand-icons-')) const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'brand-icons-'))
const cleanup = () => fs.rmSync(tmpDir, { recursive: true, force: true }) const cleanup = () => fs.rmSync(tmpDir, { recursive: true, force: true })
@@ -38,35 +40,188 @@ function rsvg(args) {
return execFileSync('rsvg-convert', args) return execFileSync('rsvg-convert', args)
} }
/** Extract the inner markup (the <path> elements) and viewBox from logo.svg. */ /** Extract the inner markup and viewBox from an SVG icon source. */
function readLogo() { function readLogo(filePath, label) {
const raw = fs.readFileSync(LOGO_PATH, 'utf8') const raw = fs.readFileSync(filePath, 'utf8')
const viewBox = (raw.match(/viewBox="([^"]+)"/) || [])[1] const viewBox = (raw.match(/viewBox="([^"]+)"/) || [])[1]
const inner = (raw.match(/<svg[^>]*>([\s\S]*)<\/svg>/) || [])[1] const inner = (raw.match(/<svg[^>]*>([\s\S]*)<\/svg>/) || [])[1]
if (!viewBox || !inner) { if (!viewBox || !inner) {
throw new Error('Could not parse public/logo.svg (missing viewBox or body)') throw new Error(`Could not parse ${label} (missing viewBox or body)`)
} }
const [, , vbW, vbH] = viewBox.split(/\s+/).map(Number) const [x, y, width, height] = viewBox.split(/\s+/).map(Number)
return { inner: inner.trim(), width: vbW, height: vbH } if (![x, y, width, height].every(Number.isFinite)) {
throw new Error(`Could not parse ${label} viewBox`)
}
return { label, inner: inner.trim(), x, y, width, height }
} }
const logo = readLogo() const logo = readLogo(LOGO_PATH, 'public/logo.svg')
const windowsTrayLogo = readLogo(WINDOWS_TRAY_LOGO_PATH, 'public/icon-color.svg')
const logoBounds = measureLogoBounds(logo)
const windowsTrayLogoBounds = measureLogoBounds(windowsTrayLogo)
function logoSvg(source, inner = source.inner) {
return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${source.width}" height="${source.height}" viewBox="${source.x} ${source.y} ${source.width} ${source.height}">
${inner}
</svg>`
}
function paeth(a, b, c) {
const p = a + b - c
const pa = Math.abs(p - a)
const pb = Math.abs(p - b)
const pc = Math.abs(p - c)
if (pa <= pb && pa <= pc) return a
return pb <= pc ? b : c
}
function readPngAlphaBounds(pngPath) {
const png = fs.readFileSync(pngPath)
const signature = '89504e470d0a1a0a'
if (png.subarray(0, 8).toString('hex') !== signature) {
throw new Error(`Expected PNG: ${pngPath}`)
}
let offset = 8
let width = 0
let height = 0
let bitDepth = 0
let colorType = 0
let interlace = 0
const idat = []
while (offset < png.length) {
const length = png.readUInt32BE(offset)
const type = png.toString('ascii', offset + 4, offset + 8)
const dataStart = offset + 8
const dataEnd = dataStart + length
const data = png.subarray(dataStart, dataEnd)
if (type === 'IHDR') {
width = data.readUInt32BE(0)
height = data.readUInt32BE(4)
bitDepth = data.readUInt8(8)
colorType = data.readUInt8(9)
interlace = data.readUInt8(12)
} else if (type === 'IDAT') {
idat.push(data)
} else if (type === 'IEND') {
break
}
offset = dataEnd + 4
}
if (bitDepth !== 8 || colorType !== 6 || interlace !== 0) {
throw new Error(`Unsupported PNG format in ${pngPath}`)
}
const bytesPerPixel = 4
const rowBytes = width * bytesPerPixel
const raw = zlib.inflateSync(Buffer.concat(idat))
let rawOffset = 0
let prev = new Uint8Array(rowBytes)
let minX = width
let minY = height
let maxX = -1
let maxY = -1
for (let y = 0; y < height; y += 1) {
const filter = raw[rawOffset]
rawOffset += 1
const row = new Uint8Array(rowBytes)
for (let i = 0; i < rowBytes; i += 1) {
const value = raw[rawOffset]
rawOffset += 1
const left = i >= bytesPerPixel ? row[i - bytesPerPixel] : 0
const up = prev[i]
const upLeft = i >= bytesPerPixel ? prev[i - bytesPerPixel] : 0
if (filter === 0) row[i] = value
else if (filter === 1) row[i] = (value + left) & 0xff
else if (filter === 2) row[i] = (value + up) & 0xff
else if (filter === 3) row[i] = (value + Math.floor((left + up) / 2)) & 0xff
else if (filter === 4) row[i] = (value + paeth(left, up, upLeft)) & 0xff
else throw new Error(`Unsupported PNG filter ${filter} in ${pngPath}`)
}
for (let x = 0; x < width; x += 1) {
if (row[x * bytesPerPixel + 3] === 0) {
continue
}
minX = Math.min(minX, x)
minY = Math.min(minY, y)
maxX = Math.max(maxX, x)
maxY = Math.max(maxY, y)
}
prev = row
}
if (maxX < minX || maxY < minY) {
return null
}
return { minX, minY, maxX, maxY, width, height }
}
function measureLogoBounds(source) {
const size = 512
const slug = source.label.replace(/[^a-z0-9._-]+/gi, '-')
const svgPath = path.join(tmpDir, `${slug}-measure.svg`)
const pngPath = path.join(tmpDir, `${slug}-measure.png`)
fs.writeFileSync(svgPath, logoSvg(source))
try {
rsvg(['-w', String(size), '-h', String(size), '-o', pngPath, svgPath])
const bounds = readPngAlphaBounds(pngPath)
if (!bounds) {
throw new Error('logo rendered with no visible pixels')
}
return {
x: source.x + (bounds.minX / bounds.width) * source.width,
y: source.y + (bounds.minY / bounds.height) * source.height,
width: ((bounds.maxX - bounds.minX + 1) / bounds.width) * source.width,
height: ((bounds.maxY - bounds.minY + 1) / bounds.height) * source.height,
}
} catch (error) {
console.warn(`[brand-icons] Could not measure visible bounds for ${source.label}; using full viewBox. ${error.message}`)
return { x: source.x, y: source.y, width: source.width, height: source.height }
}
}
function fitLogo(bounds, maxW, maxH, centerX, centerY) {
const scale = Math.min(maxW / bounds.width, maxH / bounds.height)
const drawnW = bounds.width * scale
const drawnH = bounds.height * scale
return {
scale,
tx: centerX - drawnW / 2 - bounds.x * scale,
ty: centerY - drawnH / 2 - bounds.y * scale,
}
}
function forceLogoColor(source, fill) {
if (!fill) {
return source.inner
}
return `<g class="brand-icon-color">${source.inner}</g>
<style>.brand-icon-color *{fill:${fill}!important;stroke:${fill}!important;}</style>`
}
/** A square app icon: logo centered on a rounded-rect (squircle-ish) bg. */ /** A square app icon: logo centered on a rounded-rect (squircle-ish) bg. */
function squareIconSvg(bg) { function squareIconSvg(bg, logoSource = logo, boundsSource = logoBounds) {
const CANVAS = 1024 const CANVAS = 1024
// macOS icon grid: 824x824 art area inside a 1024 canvas (100px margin). // macOS icon grid: 824x824 art area inside a 1024 canvas (100px margin).
const PLATE = 824 const PLATE = 824
const MARGIN = (CANVAS - PLATE) / 2 const MARGIN = (CANVAS - PLATE) / 2
const targetW = PLATE * 0.62 const target = PLATE * 0.62
const scale = targetW / logo.width const { scale, tx, ty } = fitLogo(boundsSource, target, target, MARGIN + PLATE / 2, MARGIN + PLATE / 2)
const drawnW = logo.width * scale return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${CANVAS}" height="${CANVAS}" viewBox="0 0 ${CANVAS} ${CANVAS}">
const drawnH = logo.height * scale
const tx = MARGIN + (PLATE - drawnW) / 2
const ty = MARGIN + (PLATE - drawnH) / 2
return `<svg xmlns="http://www.w3.org/2000/svg" width="${CANVAS}" height="${CANVAS}" viewBox="0 0 ${CANVAS} ${CANVAS}">
<rect x="${MARGIN}" y="${MARGIN}" width="${PLATE}" height="${PLATE}" rx="185" ry="185" fill="${bg}"/> <rect x="${MARGIN}" y="${MARGIN}" width="${PLATE}" height="${PLATE}" rx="185" ry="185" fill="${bg}"/>
<g transform="translate(${tx.toFixed(2)},${ty.toFixed(2)}) scale(${scale.toFixed(6)})">${logo.inner}</g> <g transform="translate(${tx.toFixed(2)},${ty.toFixed(2)}) scale(${scale.toFixed(6)})">${logoSource.inner}</g>
</svg>` </svg>`
} }
@@ -75,18 +230,11 @@ function squareIconSvg(bg) {
* tray.ts loads it with scaleFactor 2, so it shows at ~16pt on retina menu * tray.ts loads it with scaleFactor 2, so it shows at ~16pt on retina menu
* bars. Padding keeps the wide/landscape mark from touching the canvas edges. * bars. Padding keeps the wide/landscape mark from touching the canvas edges.
*/ */
function trayLogoSvg(fill) { function trayLogoSvg(source = logo, bounds = logoBounds, fill) {
const CANVAS = 32 // tray asset is 32x32 px const CANVAS = 32 // tray asset is 32x32 px
// Glyph height inside the 32px canvas — the single knob for tray size. const { scale, tx, ty } = fitLogo(bounds, 30, 28, CANVAS / 2, CANVAS / 2)
// Bump up for a larger glyph, down for a smaller one. const inner = forceLogoColor(source, fill)
const targetH = 20 return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="${CANVAS}" height="${CANVAS}" viewBox="0 0 ${CANVAS} ${CANVAS}">
const scale = targetH / logo.height
const drawnW = logo.width * scale
const drawnH = logo.height * scale
const tx = (CANVAS - drawnW) / 2
const ty = (CANVAS - drawnH) / 2
const inner = fill ? logo.inner.split(LOGO_FILL).join(fill) : logo.inner
return `<svg xmlns="http://www.w3.org/2000/svg" width="${CANVAS}" height="${CANVAS}" viewBox="0 0 ${CANVAS} ${CANVAS}">
<g transform="translate(${tx.toFixed(2)},${ty.toFixed(2)}) scale(${scale.toFixed(6)})">${inner}</g> <g transform="translate(${tx.toFixed(2)},${ty.toFixed(2)}) scale(${scale.toFixed(6)})">${inner}</g>
</svg>` </svg>`
} }
@@ -137,7 +285,7 @@ function pngsToIco(pngBuffers) {
function buildAppIcons() { function buildAppIcons() {
// 1024 master for the normal app icon. // 1024 master for the normal app icon.
const masterPng = svgToPng(squareIconSvg(BRAND_BLUE), 'app-normal', ['-w', '1024', '-h', '1024']) const masterPng = svgToPng(squareIconSvg('#ffffff', windowsTrayLogo, windowsTrayLogoBounds), 'app-normal', ['-w', '1024', '-h', '1024'])
fs.mkdirSync(BUILD_DIR, { recursive: true }) fs.mkdirSync(BUILD_DIR, { recursive: true })
fs.copyFileSync(masterPng, path.join(BUILD_DIR, 'icon.png')) fs.copyFileSync(masterPng, path.join(BUILD_DIR, 'icon.png'))
@@ -167,20 +315,21 @@ function buildAppIcons() {
// .ico with every size Windows asks for (taskbar/Explorer/Alt-Tab/tiles). // .ico with every size Windows asks for (taskbar/Explorer/Alt-Tab/tiles).
const icoSizes = [16, 24, 32, 48, 64, 128, 256] const icoSizes = [16, 24, 32, 48, 64, 128, 256]
const icoPngs = icoSizes.map((s) => const icoPngs = icoSizes.map((s) =>
fs.readFileSync(svgToPng(squareIconSvg(BRAND_BLUE), `app-ico-${s}`, ['-w', String(s), '-h', String(s)])), fs.readFileSync(svgToPng(squareIconSvg('#ffffff', windowsTrayLogo, windowsTrayLogoBounds), `app-ico-${s}`, ['-w', String(s), '-h', String(s)])),
) )
fs.writeFileSync(path.join(BUILD_DIR, 'icon.ico'), pngsToIco(icoPngs)) fs.writeFileSync(path.join(BUILD_DIR, 'icon.ico'), pngsToIco(icoPngs))
} }
function buildMainProcessIcons() { function buildMainProcessIcons() {
// Tray icons are 32x32 px and loaded @2x in tray.ts (=> ~16pt on retina). // Tray icons are 32x32 px and loaded @2x in tray.ts (=> ~16pt on retina).
// Glyph size is controlled by targetH in trayLogoSvg(), not by an rsvg -h. // Visible artwork is measured and fitted, so SVG viewBox padding does not
// shrink the menu-bar/taskbar glyph.
const trayNormal = b64(svgToPng(trayLogoSvg(), 'tray-normal')) const trayNormal = b64(svgToPng(trayLogoSvg(), 'tray-normal'))
const trayWindows = b64(svgToPng(trayLogoSvg(BRAND_BLUE), 'tray-windows')) const trayWindows = b64(svgToPng(trayLogoSvg(windowsTrayLogo, windowsTrayLogoBounds), 'tray-windows'))
const trayDanger = b64(svgToPng(trayLogoSvg(DANGER_RED), 'tray-danger')) const trayDanger = b64(svgToPng(trayLogoSvg(logo, logoBounds, DANGER_RED), 'tray-danger'))
// Dock / window icons: logo on the brand plate (normal) and danger plate. // Dock / window icons: logo on the brand plate (normal) and danger plate.
const appNormal = b64(svgToPng(squareIconSvg(BRAND_BLUE), 'dock-normal', ['-w', '512', '-h', '512'])) const appNormal = b64(svgToPng(squareIconSvg('#ffffff', windowsTrayLogo, windowsTrayLogoBounds), 'dock-normal', ['-w', '512', '-h', '512']))
const appDanger = b64(svgToPng(squareIconSvg(DANGER_RED), 'dock-danger', ['-w', '512', '-h', '512'])) const appDanger = b64(svgToPng(squareIconSvg(DANGER_RED), 'dock-danger', ['-w', '512', '-h', '512']))
// Windows taskbar overlay: a small danger badge (status cue, not the logo). // Windows taskbar overlay: a small danger badge (status cue, not the logo).
@@ -191,7 +340,7 @@ function buildMainProcessIcons() {
</svg>` </svg>`
const overlay = b64(svgToPng(overlaySvg, 'win-overlay')) const overlay = b64(svgToPng(overlaySvg, 'win-overlay'))
const banner = `// AUTO-GENERATED from public/logo.svg by scripts/generate-brand-icons.cjs. const banner = `// AUTO-GENERATED from public/logo.svg and public/icon-color.svg by scripts/generate-brand-icons.cjs.
// Do not edit by hand — run \`node scripts/generate-brand-icons.cjs\` instead. // Do not edit by hand — run \`node scripts/generate-brand-icons.cjs\` instead.
/* eslint-disable */ /* eslint-disable */
/* prettier-ignore-start */` /* prettier-ignore-start */`
@@ -201,7 +350,7 @@ function buildMainProcessIcons() {
'// macOS menu-bar template silhouette (rendered @2x).', '// macOS menu-bar template silhouette (rendered @2x).',
`export const TRAY_ICON_BASE64 =\n '${trayNormal}'`, `export const TRAY_ICON_BASE64 =\n '${trayNormal}'`,
'', '',
'// Windows tray icon: brand-blue silhouette for light tray flyouts.', '// Windows tray icon: colored brand mark for light tray flyouts.',
`export const TRAY_WINDOWS_ICON_BASE64 =\n '${trayWindows}'`, `export const TRAY_WINDOWS_ICON_BASE64 =\n '${trayWindows}'`,
'', '',
'// Tray icon shown when accounts have health issues (rendered @2x, not a template).', '// Tray icon shown when accounts have health issues (rendered @2x, not a template).',
File diff suppressed because one or more lines are too long
+6 -1
View File
@@ -1,7 +1,12 @@
// Type for the `@brand-logo` alias (electron.vite.config.ts → public/logo.svg). // Types for brand SVG aliases (electron.vite.config.ts → public/*.svg).
// Kept in its own ambient (non-module) declaration file so vue-tsc resolves the // Kept in its own ambient (non-module) declaration file so vue-tsc resolves the
// alias the same way Vite does at build time. // alias the same way Vite does at build time.
declare module '@brand-logo' { declare module '@brand-logo' {
const src: string const src: string
export default src export default src
} }
declare module '@brand-logo-full' {
const src: string
export default src
}
@@ -14,6 +14,7 @@ import { computed, onMounted, ref, watch } from 'vue'
import { RouterLink, RouterView, useRoute } from 'vue-router' import { RouterLink, RouterView, useRoute } from 'vue-router'
import brandLogo from '@brand-logo' import brandLogo from '@brand-logo'
import iconWithTitle from '@brand-logo-full'
import { useClientRelease } from '../composables/useClientRelease' import { useClientRelease } from '../composables/useClientRelease'
import { useDesktopRuntime } from '../composables/useDesktopRuntime' import { useDesktopRuntime } from '../composables/useDesktopRuntime'
import { useDesktopSession } from '../composables/useDesktopSession' import { useDesktopSession } from '../composables/useDesktopSession'
@@ -276,13 +277,7 @@ watch(
<div class="window-drag-bar" aria-hidden="true"></div> <div class="window-drag-bar" aria-hidden="true"></div>
<aside class="sidebar"> <aside class="sidebar">
<div class="brand-block"> <div class="brand-block">
<div class="brand-mark"> <img :src="iconWithTitle" alt="省心推" class="brand-logo-full" />
<img :src="brandLogo" alt="省心推" class="brand-mark-img" />
</div>
<div>
<p class="eyebrow">Workspace Cockpit</p>
<h1>省心推</h1>
</div>
</div> </div>
<nav class="nav"> <nav class="nav">
@@ -530,6 +525,8 @@ watch(
display: flex; display: flex;
gap: 16px; gap: 16px;
align-items: center; align-items: center;
justify-content: center;
margin-top: 16px;
-webkit-app-region: drag; -webkit-app-region: drag;
} }
@@ -539,13 +536,20 @@ watch(
display: grid; display: grid;
place-items: center; place-items: center;
border-radius: 11px; border-radius: 11px;
background: linear-gradient(135deg, #1677ff 0%, #4096ff 100%); background: linear-gradient(135deg, #6e55ff 0%, #00c6ff 100%);
box-shadow: 0 6px 14px rgba(22, 119, 255, 0.28); box-shadow: 0 6px 14px rgba(110, 85, 255, 0.28);
} }
.brand-mark-img { .brand-mark-img {
width: 62%; width: 72%;
height: 62%; height: 72%;
object-fit: contain;
}
.brand-logo-full {
height: 40px;
max-width: 100%;
display: block;
object-fit: contain; object-fit: contain;
} }
@@ -443,15 +443,15 @@ onBeforeUnmount(() => {
border-radius: 50%; border-radius: 50%;
display: grid; display: grid;
place-items: center; place-items: center;
background: linear-gradient(135deg, #1677ff 0%, #4096ff 100%); background: linear-gradient(135deg, #6e55ff 0%, #00c6ff 100%);
box-shadow: box-shadow:
0 10px 22px rgba(22, 119, 255, 0.28), 0 10px 22px rgba(110, 85, 255, 0.28),
inset 0 1px 0 rgba(255, 255, 255, 0.35); inset 0 1px 0 rgba(255, 255, 255, 0.35);
} }
.brand-logo-img { .brand-logo-img {
width: 60%; width: 72%;
height: 60%; height: 72%;
object-fit: contain; object-fit: contain;
} }
+46
View File
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 900 900">
<defs>
<style>
.cls-1 {
fill: url(#_未命名的渐变_117);
}
.cls-2 {
fill: #fff;
}
.cls-3 {
fill: url(#_未命名的渐变_117-4);
}
.cls-4 {
fill: url(#_未命名的渐变_117-3);
}
.cls-5 {
fill: url(#_未命名的渐变_117-2);
}
</style>
<linearGradient id="_未命名的渐变_117" data-name="未命名的渐变 117" x1="648.54" y1="275.8" x2="291.97" y2="632.36" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1fbdff"/>
<stop offset=".21" stop-color="#1f95ff"/>
<stop offset=".39" stop-color="#1f7aff"/>
<stop offset=".5" stop-color="#1f70ff"/>
<stop offset=".56" stop-color="#346aff"/>
<stop offset=".68" stop-color="#5363ff"/>
<stop offset=".8" stop-color="#695dff"/>
<stop offset=".9" stop-color="#775aff"/>
<stop offset="1" stop-color="#7c59ff"/>
</linearGradient>
<linearGradient id="_未命名的渐变_117-2" data-name="未命名的渐变 117" x1="334.48" y1="300.38" x2="237.75" y2="397.11" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-3" data-name="未命名的渐变 117" x1="334.48" y1="513.55" x2="237.75" y2="610.28" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-4" data-name="未命名的渐变 117" x1="184.94" y1="406.97" x2="88.21" y2="503.7" xlink:href="#_未命名的渐变_117"/>
</defs>
<g>
<path class="cls-1" d="M431.78,191.83c47.7,29.16,93.74,61.17,140.75,91.31,61.67,39.54,123.67,78.46,185.08,118.08,13.94,8.99,28.96,17.08,42.33,26.88,12.45,9.12,19.73,22.01,16.27,37.98-4.67,21.53-27.1,27.57-42.33,39.67l-350.42,210.03c-24.63,12.54-61.03,3.3-64.37-27.48-1.37-12.57-1.04-39.06-.02-51.93,1.15-14.55,11.18-21.89,25.2-22.94,34.84-2.61,81.1,13.67,80.94-37.98-.05-14.61-2.02-30.28-.77-45.08,2.62-31.16,29.16-25.73,52.31-25.93,3.52-.03,6.99.03,10.47,0,19.47-.17,43.14,2.83,50.21-20.57,2.55-8.42,2.37-45.83,1.35-55.79-1.4-13.75-13.53-22.62-26.71-23.69-21.73-1.77-45.71,1.28-67.69,0-8.26.75-15.57,4.92-17.51,13.33-2.1,24.07,2.19,51.34-.19,75.02-1.14,11.38-11.1,16.21-21.4,16.96-18.66,1.35-42.17.21-60.94-.81-9.52-.52-19.57,1.52-24.63-9.22-2.87-6.08-1.31-10.84-1.32-16.66-.04-19.48-1.84-41.36-.82-60.24.63-11.61,5.81-21.54,18.46-22.91,17.86-1.94,62.96,4.03,76.3-2.7,8.55-4.32,11.53-11.78,12.15-20.95,1.3-19.12-2.01-39.36-.85-58.64-9.13-39.63-59.23-18.6-87.4-25.44-10.01-2.43-16.6-10.46-17.79-20.58-2.2-18.85,1.42-41.52-.02-60.78,3.48-16.54,13.78-27.93,30.59-31.09,17.72-3.33,28.57,3.48,42.77,12.16Z"/>
<rect class="cls-5" x="232.47" y="295.46" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
<rect class="cls-4" x="232.47" y="508.63" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
<rect class="cls-3" x="82.93" y="402.04" width="107.3" height="106.58" rx="17.43" ry="17.43"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="_图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 800.3 239.55">
<defs>
<style>
.cls-1 {
fill: url(#_未命名的渐变_117);
}
.cls-2 {
fill: #000000;
}
.cls-3 {
fill: url(#_未命名的渐变_117-4);
}
.cls-4 {
fill: url(#_未命名的渐变_117-3);
}
.cls-5 {
fill: url(#_未命名的渐变_117-2);
}
</style>
<linearGradient id="_未命名的渐变_117" data-name="未命名的渐变 117" x1="731.38" y1="39.67" x2="585.56" y2="185.48" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#1fbdff"/>
<stop offset=".21" stop-color="#1f95ff"/>
<stop offset=".39" stop-color="#1f7aff"/>
<stop offset=".5" stop-color="#1f70ff"/>
<stop offset=".56" stop-color="#346aff"/>
<stop offset=".68" stop-color="#5363ff"/>
<stop offset=".8" stop-color="#695dff"/>
<stop offset=".9" stop-color="#775aff"/>
<stop offset="1" stop-color="#7c59ff"/>
</linearGradient>
<linearGradient id="_未命名的渐变_117-2" data-name="未命名的渐变 117" x1="602.95" y1="49.72" x2="563.39" y2="89.28" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-3" data-name="未命名的渐变 117" x1="602.95" y1="136.9" x2="563.39" y2="176.45" xlink:href="#_未命名的渐变_117"/>
<linearGradient id="_未命名的渐变_117-4" data-name="未命名的渐变 117" x1="541.8" y1="93.31" x2="502.24" y2="132.87" xlink:href="#_未命名的渐变_117"/>
</defs>
<g>
<path class="cls-1" d="M642.74,5.33c19.51,11.92,38.33,25.02,57.56,37.34,25.22,16.17,50.57,32.09,75.69,48.29,5.7,3.68,11.84,6.98,17.31,10.99,5.09,3.73,8.07,9,6.65,15.53-1.91,8.8-11.08,11.27-17.31,16.22l-143.3,85.89c-10.07,5.13-24.96,1.35-26.32-11.24-.56-5.14-.42-15.97,0-21.24.47-5.95,4.57-8.95,10.31-9.38,14.25-1.07,33.17,5.59,33.1-15.53-.02-5.97-.82-12.38-.32-18.44,1.07-12.74,11.92-10.52,21.39-10.6,1.44-.01,2.86.01,4.28,0,7.96-.07,17.64,1.16,20.53-8.41,1.04-3.45.97-18.74.55-22.82-.57-5.62-5.53-9.25-10.92-9.69-8.89-.72-18.69.53-27.68,0-3.38.31-6.37,2.01-7.16,5.45-.86,9.84.89,21-.08,30.68-.47,4.65-4.54,6.63-8.75,6.94-7.63.55-17.25.09-24.92-.33-3.89-.21-8,.62-10.07-3.77-1.17-2.49-.54-4.43-.54-6.81-.02-7.97-.75-16.92-.33-24.63.26-4.75,2.38-8.81,7.55-9.37,7.3-.79,25.75,1.65,31.2-1.1,3.5-1.77,4.71-4.82,4.97-8.57.53-7.82-.82-16.09-.35-23.98-3.74-16.21-24.22-7.61-35.74-10.41-4.09-.99-6.79-4.28-7.27-8.42-.9-7.71.58-16.98,0-24.85,1.42-6.76,5.64-11.42,12.51-12.71,7.25-1.36,11.68,1.42,17.49,4.97Z"/>
<rect class="cls-5" x="561.23" y="47.71" width="43.88" height="43.59" rx="7.13" ry="7.13"/>
<rect class="cls-4" x="561.23" y="134.88" width="43.88" height="43.59" rx="7.13" ry="7.13"/>
<rect class="cls-3" x="500.08" y="91.29" width="43.88" height="43.59" rx="7.13" ry="7.13"/>
</g>
<g>
<path class="cls-2" d="M0,57.64l.46-.27c7.68-.44,15.43-1.77,22.99-3.16,29.23-5.4,57.7-14.17,85.16-25.32l.7.14,8.7,10.87c.31.39.14.65-.19.94-13.33,5.8-26.75,11.41-40.25,16.8l61.01.27.28,1c-.6,23.72.76,47.8,0,71.47-.01.43-.15.75-.18,1.11-.03.46.43.91-.2,1.26l-121.8.07-.02-61.2H.27l-.27-.27v-13.71ZM119.81,72.53H36.22v7.32h83.59v-7.32ZM119.81,91.73H36.22v7.13h83.59v-7.13ZM36.02,110.91v7.68h83.79v-7.68H36.02Z"/>
<path class="cls-2" d="M461.32,21.55v15.08l-.27.27h-25.88v16.27l23.78.27v14.62s-.28.32-.37.36c-6.58.03-13.26.28-19.85.1-1.07-.03-2.59-.58-3.56.08v16.36h23.69l.27.27v14.89h-23.96v16.45h28.9v15.44s-.29.51-.37.55l-72.51-.26c-.61.15-.25,2.26-1.13,2.49l-18.36.04-.19-76.94c-4.3.04-8.6-.05-12.9,0-.7,0-1.04.34-1.85.03-.19-.07-.31.09-.25-.29.76-.63,1.19-1.5,1.68-2.35,9.24-16.15,16.46-33.39,25.14-49.81.37-.69.71-1.45,1.26-2.03h18.57l-8.6,18.09,24.33.18-8.39-18.15c.18-.54.9-.12,1.34-.11,4.54.12,9.37.09,13.92,0,1.02-.02,2.6-.65,3.35.29l8.53,17.79h23.69ZM417.24,36.9h-26.71l.08,79.51,26.63.36.18-16.63h-23.69c-.1,0-.4.29-.64.18l.09-14.98c.04-.09.33-.37.36-.37h23.6l.27-.27v-16.17h-24.24c-.09,0-.3-.3-.28-.45l.36-14.63,23.98-.08v-16.45Z"/>
<path class="cls-2" d="M216.94,114.57h62.28c.06,0,.28.24.46.18v17.45l-.27.27h-81.4c-.33,0-.44-.72-.47-.99-.26-2.63.19-5.44.19-8.05.06-30.55.11-61.36-.07-91.89-.02-4.2-.41-8.86-.12-13.01.03-.41.04-1.36.65-1.36h18.47l.27.27v97.13Z"/>
<path class="cls-2" d="M332.91,22.28l.18-18.37.3-.43c.72.12,1.55-.2,2.17-.21,4.46-.03,9.05.17,13.55.19.48,0,1.54-.3,1.87.04l.32,18.78h12.16v14.53c0,.06-.24.28-.18.46h-12.16l-.09,30.88,12.07-3.94.75.22-.42,15.74-12.37,4.36-.17,36.38c-2.21,3.76-4.14,7.75-6.48,11.44-.19.3-.5.91-.82,1.01l-23.12-.26c-.19-.38-.02-.6.16-.93,1.2-2.24,3.04-4.7,4.39-6.95,2.67-4.42,5.27-8.89,7.86-13.35.4-7.12.17-14.28.23-21.43-1.93.18-15.14,5.42-15.8,4.93-.24-.18-.33-.31-.31-.62l.05-14.78.34-.39,15.73-5.31v-36.73l-.27-.27h-15.64v-14.99h15.73Z"/>
<path class="cls-2" d="M288.69,111.42l-10.73-49.68c-1.69-8.32-4.13-16.51-5.91-24.8-.12-.54-.44-1.88-.43-2.33.04-1.17,1.42-.44,2.12-.44,4.77,0,9.62.04,14.46,0,1.5-.01,2.03-.7,2.59,1.23,2.1,7.24,3.38,15.34,5.04,22.75,3.83,17.13,8.11,34.26,11.61,51.45.1.47.46,1.68.07,1.97l-18.81-.15Z"/>
<path class="cls-2" d="M177.61,111.46c-.64-.14-1.36.14-1.92.15-4.1.01-8.17-.03-12.25.04-.77.01-5.31.11-5.51-.18l-.07-.63c7.4-25.03,11.48-50.88,16.36-76.5.49-.8,2.75-.17,3.48-.18,2.08-.03,4.12-.01,6.2,0,2.63.02,5.23-.12,7.85-.17.84.27-.1,2.46-.21,3.03-3.24,18.04-6.5,36-9.78,54.01l-4.16,20.42Z"/>
<path class="cls-2" d="M246.12,3.45c.1.02.42.18.46.32.76,3.3,1.34,6.65,2.06,9.96,4.04,18.57,7.87,37.58,12.2,55.82l.37,3.71h-18.66l-6.08-30.93c-2.12-12.11-5.79-24.42-7.73-36.5-.07-.44-.56-2.38.19-2.38h17.19Z"/>
<path class="cls-2" d="M51.4,8.39c.23.93-.74,1.44-1.28,2.11-8.38,10.34-17.21,20.34-25.8,30.51l-22.08-.04-.23-.31c.24-.8,1.01-1.13,1.56-1.74,9.05-10.08,18.02-20.25,26.89-30.52h20.94Z"/>
<path class="cls-2" d="M129.04,16.35c6.55,7.97,13.06,16.05,19.68,23.93,0,.9-1.81.42-2.48.45-5.46.28-10.96.09-16.46.17l-.72.57-.1-.53c-.37-.05-.72.05-1.09-.11-.25-.11-2.68-3.02-3.11-3.52-7.85-9.15-15.2-18.73-23.13-27.82l-.28-1.09,20.68-.1.62.3c2.18,2.55,4.27,5.18,6.4,7.77Z"/>
<path class="cls-2" d="M62.92,3.55c.1-.58.89-.61,1.37-.65,5.5-.43,11.59.3,17.16.05,1.52.17,1.09,3.18,1.06,4.44-.18,8.19.11,16.48-.18,24.67-.03.92,0,1.88-.35,2.75-.38.47-10.46,2.05-11.95,2.32-1.34.24-5.67,1.41-6.64,1.23-.2-.04-.34-.09-.46-.28V3.55Z"/>
<g>
<path class="cls-2" d="M58.37,156.95l-3.17,12.69h-25.13l-2.92,11.84h21.36l-3.26,12.87h-21.36l-3.35,13.55h26.08l-3.17,12.87H2.01l15.87-63.82h40.49Z"/>
<path class="cls-2" d="M101.76,193.75l-6.69,27.02h-12.35v-4.37c-4.98,3.6-9.86,5.58-14.67,5.58-9.61,0-13.81-7.38-11.67-16.3,2.4-9.52,11.15-14.49,30.88-17.24,1.2-3.86.09-5.49-4.29-5.49s-9.01,1.89-14.32,4.63l-3.95-10.72c7.46-3.86,14.84-6.09,21.87-6.09,13.21,0,18.96,7.72,15.18,22.99ZM85.89,198.55c-9.86,1.29-14.32,4.63-15.35,8.84-.6,2.06.77,2.74,3.34,2.74,3.69,0,6.43-1.97,9.18-4.37l2.83-7.21Z"/>
<path class="cls-2" d="M133.15,183.89h-17.33l2.92-11.92h36.63l-1.8,8.15-26.93,28.73h20.16l-2.92,11.92h-39.46l1.8-8.15,26.93-28.73Z"/>
<path class="cls-2" d="M146.44,238.44l4.46-11.24c.86.17,2.06.43,2.57.43,5.23,0,8.83-3.09,10.64-6.52l1.46-1.8-6.69-47.35h15.01l1.29,20.93c.34,4.46.26,9.01.09,13.81l1.03-1.37c2.14-4.63,4.37-9.18,6.52-13.81l10.64-19.56h14.75l-28.99,49.58c-7.89,12.52-14.15,18.01-25.13,18.01-3.77,0-5.66-.51-7.63-1.12Z"/>
<path class="cls-2" d="M242.16,156.95c14.07,0,24.87,5.66,20.76,22.22-3.6,14.41-16.3,20.41-29.76,20.41h-8.06l-5.23,21.19h-15.35l15.87-63.82h21.79ZM248.68,176.25c1.46-5.66-1.72-7.2-9.09-7.2h-6.86l-4.63,18.44h6.09c7.46,0,12.78-4.2,14.5-11.24Z"/>
<path class="cls-2" d="M266.51,201.47l7.29-29.51h15.27l-7.2,28.99c-1.72,6.78-.77,7.98,2.49,7.98,4.03,0,6.95-1.97,10.38-5.58l8.15-31.39h15.27l-12.09,48.8h-12.35l.51-6.69-.17.51c-5.23,4.8-10.21,7.38-16.3,7.38-11.24,0-14.32-8.32-11.24-20.5Z"/>
<path class="cls-2" d="M315.83,214.68l8.23-8.66c3.6,3.43,7.21,4.72,10.46,4.72,4.63,0,7.46-2.14,8.23-5.32.6-2.14-3.34-3.17-7.29-5.4-5.83-1.97-12.18-6.35-9.95-15.18,2.14-8.49,10.46-14.07,21.19-14.07,8.32,0,13.04,3.52,16.81,6.69l-8.23,8.23c-2.83-2.4-5.83-3.69-8.49-3.69-4.03,0-6.78,1.89-7.55,4.98-.51,2.14,3.17,2.83,7.21,4.89,6.09,2.06,12.44,6,10.04,15.61-2.06,8.23-10.04,14.5-22.73,14.5-6.95,0-13.81-3.17-17.93-7.29Z"/>
<path class="cls-2" d="M394.31,152.24l-4.03,16.47-3.26,8.15c4.38-3.26,9.69-6.09,15.7-6.09,11.24,0,14.32,8.32,11.24,20.5l-7.29,29.51h-15.27l7.2-28.99c1.63-6.69.77-7.98-2.49-7.98-4.03,0-6.78,2.06-10.46,4.89l-8.41,32.08h-15.18l17.07-68.53h15.18Z"/>
<path class="cls-2" d="M426.04,210.91c1.2-4.55,5.75-7.98,10.98-7.98,6.43,0,10.04,4.8,8.58,10.89-1.2,4.72-5.66,7.98-10.98,7.98-6.35,0-10.12-4.63-8.58-10.89ZM440.36,156.61h18.78l-3.95,14.24-10.29,27.1h-10.72l3.26-27.1,2.92-14.24Z"/>
</g>
<g>
<path class="cls-2" d="M477.32,5.77h-7.2v-2.53h17.41v2.53h-7.2v21.23h-3.01V5.77Z"/>
<path class="cls-2" d="M491.77,3.24h3.63l4.57,12.71c.55,1.65,1.1,3.31,1.69,4.96h.16c.55-1.65,1.07-3.31,1.62-4.96l4.54-12.71h3.63v23.76h-2.82v-13.16c0-2.04.23-4.93.39-7h-.13l-1.88,5.41-4.51,12.35h-2.01l-4.51-12.35-1.88-5.41h-.13c.13,2.07.36,4.96.36,7v13.16h-2.72V3.24Z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.0 KiB

+72 -11
View File
@@ -1,9 +1,23 @@
<template> <template>
<a-layout style="min-height: 100vh"> <a-layout style="min-height: 100vh">
<a-layout-sider v-model:collapsed="collapsed" collapsible breakpoint="lg" :trigger="null"> <a-layout-sider v-model:collapsed="collapsed" collapsible breakpoint="lg" :trigger="null">
<div class="ops-brand"> <div class="ops-brand" aria-label="省心推运营控制台">
<span v-if="!collapsed">省心推 · 运营</span> <img
<span v-else>SXT</span> v-if="!collapsed"
class="ops-brand__logo ops-brand__logo--full"
src="/logos/icon-with-title.svg"
alt=""
aria-hidden="true"
/>
<span v-if="!collapsed" class="ops-brand__badge">运营端</span>
<img
v-else
class="ops-brand__logo ops-brand__logo--icon"
src="/logos/icon-color.svg"
alt=""
aria-hidden="true"
/>
<span v-if="collapsed" class="ops-brand__badge ops-brand__badge--compact"></span>
</div> </div>
<a-menu <a-menu
theme="light" theme="light"
@@ -235,18 +249,65 @@ onMounted(() => {
} }
.ops-brand { .ops-brand {
height: 40px; height: 38px;
background: #eef2ff; margin: 14px 12px 18px;
border: 1px solid #c7d2fe; padding: 0;
margin: 16px;
border-radius: 6px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 6px;
overflow: hidden;
transition:
margin 0.2s ease,
width 0.2s ease;
}
.ops-brand__logo {
display: block;
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.ops-brand__logo--full {
width: 96px;
height: 32px;
}
.ops-brand__logo--icon {
width: 32px;
height: 32px;
}
.ops-brand__badge {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
height: 20px;
padding: 0 6px;
border: 1px solid rgba(79, 70, 229, 0.22);
border-radius: 999px;
background: #eef2ff;
color: #4f46e5; color: #4f46e5;
font-weight: 800; font-size: 11px;
font-size: 16px; font-weight: 700;
letter-spacing: 0.05em; line-height: 1;
white-space: nowrap;
}
.ops-brand__badge--compact {
width: 18px;
height: 18px;
padding: 0;
border-radius: 5px;
font-size: 11px;
}
:deep(.ant-layout-sider-collapsed) .ops-brand {
width: 58px;
margin: 14px auto 18px;
gap: 2px;
} }
.ops-header { .ops-header {
+42 -19
View File
@@ -7,8 +7,8 @@
}" }"
> >
<div class="brand"> <div class="brand">
<div class="brand-icon"><StarOutlined :style="{ fontSize: '16px' }" /></div> <img class="brand-logo brand-logo--white" src="/logos/icon-with-title.svg" alt="省心推运营控制台" />
<span>省心推运营控制台</span> <span class="brand-badge brand-badge--white">运营端</span>
</div> </div>
<div class="characters-area"> <div class="characters-area">
<AnimatedCharacters <AnimatedCharacters
@@ -29,8 +29,8 @@
<div class="right"> <div class="right">
<div class="form-wrapper"> <div class="form-wrapper">
<div class="mobile-brand"> <div class="mobile-brand">
<div class="brand-icon"><StarOutlined :style="{ fontSize: '16px' }" /></div> <img class="brand-logo brand-logo--mobile" src="/logos/icon-with-title.svg" alt="省心推运营控制台" />
<span>省心推运营控制台</span> <span class="brand-badge">运营端</span>
</div> </div>
<div class="header"> <div class="header">
<h1>欢迎回来</h1> <h1>欢迎回来</h1>
@@ -102,7 +102,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { EyeInvisibleOutlined, EyeOutlined, StarOutlined } from '@ant-design/icons-vue' import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons-vue'
import { onMounted, reactive, ref } from 'vue' import { onMounted, reactive, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
@@ -205,19 +205,41 @@ async function handleSubmit(): Promise<void> {
z-index: 20; z-index: 20;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 10px;
font-size: 18px;
font-weight: 600;
} }
.brand-icon {
width: 32px; .brand-logo {
height: 32px; display: block;
border-radius: 8px; width: 164px;
background: rgba(255, 255, 255, 0.1); height: auto;
backdrop-filter: blur(8px); object-fit: contain;
display: flex; }
.brand-logo--white {
filter: brightness(0) invert(1);
}
.brand-badge {
display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 24px;
padding: 0 9px;
border: 1px solid rgba(79, 70, 229, 0.24);
border-radius: 999px;
background: #eef2ff;
color: #4f46e5;
font-size: 12px;
font-weight: 700;
line-height: 1;
white-space: nowrap;
}
.brand-badge--white {
border-color: rgba(255, 255, 255, 0.38);
background: rgba(255, 255, 255, 0.14);
color: #fff;
backdrop-filter: blur(8px);
} }
.characters-area { .characters-area {
position: relative; position: relative;
@@ -438,11 +460,12 @@ async function handleSubmit(): Promise<void> {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
gap: 8px; gap: 10px;
font-size: 18px;
font-weight: 600;
margin-bottom: 48px; margin-bottom: 48px;
color: #18181b; }
.brand-logo--mobile {
width: 144px;
} }
} }
</style> </style>