Implemented dual-nozzle AMS wiring visualization

- Added AMSSectionDual component with CSS border-based wiring
- Wiring connects AMS slots to hub to extruder with proper 90° corners
- Supports future dynamic filament color display
- Added TemperatureColumn with dual nozzle L/R display
- Added JogPad, BedControls, ExtruderControls components
- Added various control page icons

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Martin Ziegler
2025-12-02 16:02:36 +01:00
co-authored by Claude
parent f448f2482e
commit 2f103d607d
73 changed files with 2205 additions and 622 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><g clip-rule="evenodd" fill="#000" fill-rule="evenodd"><path d="m2.25 6c0-.41421.33579-.75.75-.75h3.5c.41421 0 .75.33579.75.75s-.33579.75-.75.75h-3.5c-.41421 0-.75-.33579-.75-.75zm8.5 0c0-.41421.3358-.75.75-.75h9.5c.4142 0 .75.33579.75.75s-.3358.75-.75.75h-9.5c-.4142 0-.75-.33579-.75-.75z"/><path d="m9 4.25c-.9665 0-1.75.7835-1.75 1.75s.7835 1.75 1.75 1.75 1.75-.7835 1.75-1.75-.7835-1.75-1.75-1.75zm-3.25 1.75c0-1.79493 1.45507-3.25 3.25-3.25 1.7949 0 3.25 1.45507 3.25 3.25s-1.4551 3.25-3.25 3.25c-1.79493 0-3.25-1.45507-3.25-3.25z"/><path d="m21.75 12c0-.4142-.3358-.75-.75-.75h-2c-.4142 0-.75.3358-.75.75s.3358.75.75.75h2c.4142 0 .75-.3358.75-.75zm-7 0c0-.4142-.3358-.75-.75-.75h-5c-.41421 0-.75.3358-.75.75s.33579.75.75.75h5c.4142 0 .75-.3358.75-.75zm-9 0c0-.4142-.33579-.75-.75-.75h-2c-.41421 0-.75.3358-.75.75s.33579.75.75.75h2c.41421 0 .75-.3358.75-.75z"/><path d="m16.5 10.25c.9665 0 1.75.7835 1.75 1.75s-.7835 1.75-1.75 1.75-1.75-.7835-1.75-1.75.7835-1.75 1.75-1.75zm3.25 1.75c0-1.7949-1.4551-3.25-3.25-3.25s-3.25 1.4551-3.25 3.25 1.4551 3.25 3.25 3.25 3.25-1.4551 3.25-3.25z"/><path d="m2.25 18c0-.4142.33579-.75.75-.75h5c.41421 0 .75.3358.75.75s-.33579.75-.75.75h-5c-.41421 0-.75-.3358-.75-.75zm10 0c0-.4142.3358-.75.75-.75h8c.4142 0 .75.3358.75.75s-.3358.75-.75.75h-8c-.4142 0-.75-.3358-.75-.75z"/><path d="m10.5 16.25c-.9665 0-1.75.7835-1.75 1.75s.7835 1.75 1.75 1.75 1.75-.7835 1.75-1.75-.7835-1.75-1.75-1.75zm-3.25 1.75c0-1.7949 1.45507-3.25 3.25-3.25 1.7949 0 3.25 1.4551 3.25 3.25s-1.4551 3.25-3.25 3.25c-1.79493 0-3.25-1.4551-3.25-3.25z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 50">
<!-- Left wire: horizontal from left edge, then down to extruder left inlet -->
<line x1="0" y1="0" x2="10" y2="0" stroke="#909090" stroke-width="2" />
<line x1="10" y1="0" x2="10" y2="50" stroke="#909090" stroke-width="2" />
<!-- Right wire: horizontal from right edge, then down to extruder right inlet -->
<line x1="40" y1="0" x2="30" y2="0" stroke="#909090" stroke-width="2" />
<line x1="30" y1="0" x2="30" y2="50" stroke="#909090" stroke-width="2" />
</svg>

After

Width:  |  Height:  |  Size: 537 B

+17
View File
@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 50">
<!-- Vertical lines from slots down to horizontal bar -->
<line x1="28" y1="0" x2="28" y2="14" stroke="#909090" stroke-width="2" />
<line x1="82" y1="0" x2="82" y2="14" stroke="#909090" stroke-width="2" />
<line x1="138" y1="0" x2="138" y2="14" stroke="#909090" stroke-width="2" />
<line x1="192" y1="0" x2="192" y2="14" stroke="#909090" stroke-width="2" />
<!-- Horizontal bar across all slots -->
<line x1="28" y1="14" x2="192" y2="14" stroke="#909090" stroke-width="2" />
<!-- Center hub box -->
<rect x="96" y="8" width="28" height="12" rx="2" fill="#c0c0c0" stroke="#909090" stroke-width="1" />
<!-- Wire from hub: down, then right to edge (at same level as hub horizontal bar) -->
<line x1="110" y1="20" x2="110" y2="35" stroke="#909090" stroke-width="2" />
<line x1="110" y1="35" x2="220" y2="35" stroke="#909090" stroke-width="2" />
</svg>

After

Width:  |  Height:  |  Size: 937 B

@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 50">
<!-- Vertical lines from slots down to horizontal bar -->
<line x1="28" y1="0" x2="28" y2="14" stroke="#909090" stroke-width="2" />
<line x1="82" y1="0" x2="82" y2="14" stroke="#909090" stroke-width="2" />
<line x1="138" y1="0" x2="138" y2="14" stroke="#909090" stroke-width="2" />
<line x1="192" y1="0" x2="192" y2="14" stroke="#909090" stroke-width="2" />
<!-- Horizontal bar across all slots -->
<line x1="28" y1="14" x2="192" y2="14" stroke="#909090" stroke-width="2" />
<!-- Center hub box -->
<rect x="96" y="8" width="28" height="12" rx="2" fill="#c0c0c0" stroke="#909090" stroke-width="1" />
<!-- Wire from hub: down, then left to edge (at same level as hub horizontal bar) -->
<line x1="110" y1="20" x2="110" y2="35" stroke="#909090" stroke-width="2" />
<line x1="0" y1="35" x2="110" y2="35" stroke="#909090" stroke-width="2" />
</svg>

After

Width:  |  Height:  |  Size: 934 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Capa_1" enable-background="new 0 0 512 512" height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><g><g><path d="m422.995 217.87c4.143 0 7.5-3.357 7.5-7.5v-192.87c0-9.649-7.851-17.5-17.5-17.5h-313.99c-9.649 0-17.5 7.851-17.5 17.5v477c0 9.649 7.851 17.5 17.5 17.5h313.99c9.649 0 17.5-7.851 17.5-17.5v-248.203c0-4.143-3.357-7.5-7.5-7.5s-7.5 3.357-7.5 7.5v52.811h-16.639v-117.615h16.639v28.877c0 4.143 3.358 7.5 7.5 7.5zm-294.851-144.77h33.028c4.143 0 7.5-3.357 7.5-7.5s-3.357-7.5-7.5-7.5h-33.028v-43.1h255.713v43.1h-186.759c-4.143 0-7.5 3.357-7.5 7.5s3.357 7.5 7.5 7.5h186.759v22.158h-255.713zm-29.139-58.1h14.139v151.493h-16.639v-148.993c0-1.379 1.121-2.5 2.5-2.5zm-2.5 447v-15.278h16.639v15.278zm0-280.507h16.639v117.614h-16.639zm316.49 315.507h-313.99c-1.379 0-2.5-1.121-2.5-2.5v-17.5h318.99v17.5c0 1.379-1.121 2.5-2.5 2.5zm2.5-35h-16.639v-15.278h16.639zm0-147.893v117.614h-16.639v-117.614zm-31.639-15h-3.586c-4.143 0-7.5 3.357-7.5 7.5s3.357 7.5 7.5 7.5h3.586v117.614h-3.586c-4.143 0-7.5 3.357-7.5 7.5s3.357 7.5 7.5 7.5h3.586v15.279h-255.712v-15.278h3.586c4.143 0 7.5-3.357 7.5-7.5s-3.357-7.5-7.5-7.5h-3.586v-53.092c0-4.143-3.357-7.5-7.5-7.5s-7.5 3.357-7.5 7.5v53.092h-16.639v-117.615h16.639v28.596c0 4.143 3.357 7.5 7.5 7.5s7.5-3.357 7.5-7.5v-28.596h3.586c4.143 0 7.5-3.357 7.5-7.5s-3.357-7.5-7.5-7.5h-3.586v-117.614h3.586c4.143 0 7.5-3.357 7.5-7.5s-3.357-7.5-7.5-7.5h-3.586v-56.235h255.713v56.235h-3.586c-4.143 0-7.5 3.357-7.5 7.5s3.357 7.5 7.5 7.5h3.586v117.614zm15-132.614v-151.493h14.139c1.379 0 2.5 1.121 2.5 2.5v148.993z"/><path d="m256 129.22c-17.53 0-31.793 14.263-31.793 31.794 0 17.53 14.263 31.793 31.793 31.793s31.793-14.263 31.793-31.793c0-17.532-14.263-31.794-31.793-31.794zm0 48.587c-9.26 0-16.793-7.533-16.793-16.793s7.533-16.794 16.793-16.794 16.793 7.534 16.793 16.794-7.533 16.793-16.793 16.793z"/><path d="m201.313 419.229c-1.407-1.406-3.314-2.196-5.304-2.196s-3.897.79-5.304 2.197l-10.465 10.466c-2.929 2.929-2.929 7.678.001 10.606 1.464 1.464 3.384 2.196 5.303 2.196s3.839-.732 5.304-2.197l5.161-5.162 5.162 5.163c2.93 2.928 7.678 2.928 10.607 0 2.929-2.93 2.929-7.678 0-10.607z"/><path d="m261.304 419.23c-1.406-1.407-3.314-2.197-5.304-2.197s-3.897.79-5.304 2.197l-10.465 10.466c-2.929 2.929-2.929 7.678.001 10.606 2.928 2.928 7.677 2.929 10.606-.001l5.161-5.161 5.161 5.161c1.465 1.465 3.384 2.197 5.304 2.197 1.919 0 3.839-.732 5.303-2.196 2.93-2.929 2.93-7.678.001-10.606z"/><path d="m321.295 419.23c-1.406-1.407-3.314-2.197-5.304-2.197s-3.896.79-5.304 2.196l-10.466 10.466c-2.929 2.93-2.929 7.678 0 10.607 2.93 2.928 7.678 2.928 10.607 0l5.162-5.163 5.161 5.162c1.465 1.465 3.384 2.197 5.304 2.197 1.919 0 3.839-.732 5.303-2.196 2.93-2.929 2.93-7.678.001-10.606z"/><path d="m213.252 44.05h85.496c4.143 0 7.5-3.357 7.5-7.5s-3.357-7.5-7.5-7.5h-85.496c-4.143 0-7.5 3.357-7.5 7.5s3.357 7.5 7.5 7.5z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

+51
View File
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 511.999 511.999" style="enable-background:new 0 0 511.999 511.999;" xml:space="preserve">
<g>
<g>
<path d="M508.745,246.041c-4.574-6.257-113.557-153.206-252.748-153.206S7.818,239.784,3.249,246.035
c-4.332,5.936-4.332,13.987,0,19.923c4.569,6.257,113.557,153.206,252.748,153.206s248.174-146.95,252.748-153.201
C513.083,260.028,513.083,251.971,508.745,246.041z M255.997,385.406c-102.529,0-191.33-97.533-217.617-129.418
c26.253-31.913,114.868-129.395,217.617-129.395c102.524,0,191.319,97.516,217.617,129.418
C447.361,287.923,358.746,385.406,255.997,385.406z"/>
</g>
</g>
<g>
<g>
<path d="M255.997,154.725c-55.842,0-101.275,45.433-101.275,101.275s45.433,101.275,101.275,101.275
s101.275-45.433,101.275-101.275S311.839,154.725,255.997,154.725z M255.997,323.516c-37.23,0-67.516-30.287-67.516-67.516
s30.287-67.516,67.516-67.516s67.516,30.287,67.516,67.516S293.227,323.516,255.997,323.516z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"><g fill="rgb(0,0,0)"><path d="m6.3 3.9c.54-.4 1.2-.9 1.2-1.9 0-.28-.22-.5-.5-.5s-.5.22-.5.5c0 .48-.29.71-.8 1.1-.53.4-1.2.9-1.2 1.9s.67 1.5 1.2 1.9c.51.38.8.62.8 1.1s-.29.72-.8 1.1c-.54.4-1.2.9-1.2 1.9 0 .28.22.5.5.5s.5-.22.5-.5c0-.48.29-.72.8-1.1.54-.4 1.2-.9 1.2-1.9s-.67-1.5-1.2-1.9c-.51-.38-.8-.62-.8-1.1s.29-.72.8-1.1z"/><path d="m12.3 3.9c.54-.4 1.2-.9 1.2-1.9 0-.28-.22-.5-.5-.5s-.5.22-.5.5c0 .48-.29.71-.8 1.1-.53.4-1.2.9-1.2 1.9s.67 1.5 1.2 1.9c.51.38.8.62.8 1.1s-.29.72-.8 1.1c-.54.4-1.2.9-1.2 1.9 0 .28.22.5.5.5s.5-.22.5-.5c0-.48.29-.72.8-1.1.54-.4 1.2-.9 1.2-1.9s-.67-1.5-1.2-1.9c-.51-.38-.8-.62-.8-1.1s.29-.72.8-1.1z"/><path d="m18.3 3.9c.54-.4 1.2-.9 1.2-1.9 0-.28-.22-.5-.5-.5s-.5.22-.5.5c0 .48-.29.71-.8 1.1-.53.4-1.2.9-1.2 1.9s.67 1.5 1.2 1.9c.51.38.8.62.8 1.1s-.29.72-.8 1.1c-.54.4-1.2.9-1.2 1.9 0 .28.22.5.5.5s.5-.22.5-.5c0-.48.29-.72.8-1.1.54-.4 1.2-.9 1.2-1.9s-.67-1.5-1.2-1.9c-.51-.38-.8-.62-.8-1.1s.29-.72.8-1.1z"/><path d="m22 13.5c-1.07 0-1.61.65-2.05 1.18-.44.52-.71.82-1.29.82s-.85-.3-1.29-.82c-.44-.53-.98-1.18-2.05-1.18s-1.61.65-2.05 1.18c-.44.52-.71.82-1.28.82s-.85-.3-1.28-.82c-.44-.53-.98-1.18-2.05-1.18s-1.61.65-2.05 1.18c-.44.52-.71.82-1.28.82s-.84-.3-1.28-.82c-.44-.53-.98-1.18-2.05-1.18-.28 0-.5.22-.5.5s.22.5.5.5c.57 0 .84.3 1.28.82.44.53.98 1.18 2.05 1.18s1.61-.65 2.05-1.18c.44-.52.71-.82 1.28-.82s.85.3 1.28.82c.44.53.98 1.18 2.05 1.18s1.61-.65 2.05-1.18c.44-.52.71-.82 1.28-.82s.85.3 1.29.82c.44.53.98 1.18 2.05 1.18s1.61-.65 2.05-1.18c.44-.52.71-.82 1.29-.82.28 0 .5-.22.5-.5s-.22-.5-.5-.5z"/><path d="m21 18.5h-18c-.83 0-1.5.67-1.5 1.5v1c0 .83.67 1.5 1.5 1.5h18c.83 0 1.5-.67 1.5-1.5v-1c0-.83-.67-1.5-1.5-1.5zm.5 2.5c0 .28-.22.5-.5.5h-18c-.28 0-.5-.22-.5-.5v-1c0-.28.22-.5.5-.5h18c.28 0 .5.22.5.5z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 476.912 476.912" style="enable-background:new 0 0 476.912 476.912;" xml:space="preserve">
<g>
<g>
<path d="M461.776,209.408L249.568,4.52c-6.182-6.026-16.042-6.026-22.224,0L15.144,209.4c-3.124,3.015-4.888,7.17-4.888,11.512
c0,8.837,7.164,16,16,16h28.2v224c0,8.837,7.163,16,16,16h112c8.837,0,16-7.163,16-16v-128h80v128c0,8.837,7.163,16,16,16h112
c8.837,0,16-7.163,16-16v-224h28.2c4.338,0,8.489-1.761,11.504-4.88C468.301,225.678,468.129,215.549,461.776,209.408z
M422.456,220.912c-8.837,0-16,7.163-16,16v224h-112v-128c0-8.837-7.163-16-16-16h-80c-8.837,0-16,7.163-16,16v128h-112v-224
c0-8.837-7.163-16-16-16h-28.2l212.2-204.88l212.28,204.88H422.456z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg"><g id="Front_Heater" data-name="Front Heater"><path d="m33.14 29h2.86l-4-7-4 7h3l1.5 3.7a8.38 8.38 0 0 1 -.92 8l-.67.82a10.43 10.43 0 0 0 -.29 11.74 1 1 0 0 0 .82.42 1 1 0 0 0 .58-.19 1 1 0 0 0 .23-1.39 8.4 8.4 0 0 1 .21-9.32l.67-.82a10.32 10.32 0 0 0 1.22-10z"/><path d="m23.22 29h2.78l-4-7-4 7h3.06l1.5 3.7a8.35 8.35 0 0 1 -.92 8l-.67.82a10.43 10.43 0 0 0 -.29 11.74 1 1 0 0 0 .82.42 1 1 0 0 0 .58-.19 1 1 0 0 0 .24-1.39 8.4 8.4 0 0 1 .2-9.32l.67-.82a10.32 10.32 0 0 0 1.22-10z"/><path d="m57.88 20.09a3 3 0 0 0 -1.49-1.84l-7.73-4.1a35.48 35.48 0 0 0 -33.32 0l-7.72 4.1a3 3 0 0 0 -1.22 4.2l9.72 17a3 3 0 0 0 2.6 1.55 3 3 0 0 0 1.39-.34 1 1 0 0 0 .42-1.35 1 1 0 0 0 -1.34-.42 1 1 0 0 1 -1.33-.39l-9.72-17a1 1 0 0 1 -.1-.81 1 1 0 0 1 .52-.69l7.72-4.1a33.46 33.46 0 0 1 31.44 0l7.73 4.1a1 1 0 0 1 .51.63 1 1 0 0 1 -.1.81l-9.72 17a1 1 0 0 1 -1.33.39l-.2-.11a10.82 10.82 0 0 0 -.36-6.72l-1.19-3h2.94l-4-7-4 7h2.9l1.5 3.7a8.38 8.38 0 0 1 -.93 8l-.66.82a10.43 10.43 0 0 0 -.29 11.74 1 1 0 0 0 .82.42 1 1 0 0 0 .58-.19 1 1 0 0 0 .23-1.39 8.4 8.4 0 0 1 .21-9.32l.64-.78a8.27 8.27 0 0 0 .84-1.3 3 3 0 0 0 4-1.17l9.72-17a3 3 0 0 0 .32-2.44z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 98 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Ecommerce" enable-background="new 0 0 48 48" height="512" viewBox="0 0 48 48" width="512" xmlns="http://www.w3.org/2000/svg"><g><path d="m25 7.03c0-.552-.447-1-1-1-5.514 0-10 4.486-10 10 0 .552.447 1 1 1s1-.448 1-1c0-4.411 3.589-8 8-8 .553 0 1-.448 1-1z"/><path d="m22.246 45.79h1.754 1.754c1.652 0 2.999-1.345 3-3v-1.099c1.032-.475 1.755-1.512 1.755-2.721v-3.72c.176-.382.281-.802.281-1.25 0-1.016.226-2 .671-2.927.441-.919 1.086-1.752 1.864-2.409 3.746-3.165 5.709-7.989 5.25-12.909-.7-7.375-6.813-13.189-14.265-13.525l-.31-.01-.354.011c-7.408.335-13.521 6.149-14.222 13.526-.458 4.917 1.505 9.742 5.251 12.906.778.658 1.423 1.491 1.864 2.41.445.927.671 1.911.671 2.927 0 .447.105.868.281 1.25v3.721c0 1.209.722 2.247 1.755 2.721v1.1c.001 1.653 1.348 2.998 3 2.998zm4.508-3c0 .552-.449 1-1 1h-1.754-1.754c-.551 0-1-.449-1-1v-.82h2.754 2.754zm1.755-3.819c0 .551-.448 1-1 1h-3.509-3.509c-.552 0-1-.449-1-1v-2.068c.232.058.47.097.719.097h3.79 3.79c.249 0 .487-.039.719-.097zm-9.299-4.971c0-1.318-.292-2.595-.868-3.793-.563-1.171-1.385-2.233-2.376-3.071-3.247-2.742-4.948-6.926-4.551-11.191.607-6.389 5.903-11.426 12.275-11.715l.31-.01.265.009c6.417.29 11.713 5.327 12.319 11.714.398 4.267-1.303 8.451-4.55 11.193-.991.838-1.813 1.9-2.376 3.071-.576 1.198-.868 2.475-.868 3.793 0 .551-.448 1-1 1h-3.79-3.79c-.552 0-1-.449-1-1z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" height="512" viewBox="0 0 100 100" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m44.94 55.32h4.08c.71 0 1.29.68 1.29 1.52 0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5c0-2.49-1.93-4.52-4.29-4.52h-4.08c-2.37 0-4.29 2.03-4.29 4.52v2.07c0 2.38 1.76 4.32 3.98 4.49.1.02.2.03.31.03h4.08c.71 0 1.29.68 1.29 1.52v2.08c0 .84-.58 1.52-1.29 1.52h-4.08c-.71 0-1.29-.68-1.29-1.52 0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5c0 2.49 1.93 4.52 4.29 4.52h4.08c2.37 0 4.29-2.03 4.29-4.52v-2.08c0-2.38-1.76-4.31-3.98-4.49-.1-.02-.2-.03-.31-.03h-4.08c-.71 0-1.29-.68-1.29-1.52v-2.07c0-.84.58-1.52 1.29-1.52z"/><path d="m64.22 52.32h-4.64c-.83 0-1.5.67-1.5 1.5v16.22c0 .83.67 1.5 1.5 1.5h4.64c3.59 0 6.52-2.92 6.52-6.52v-6.19c-.01-3.59-2.93-6.51-6.52-6.51zm3.51 12.7c0 1.94-1.58 3.52-3.52 3.52h-3.14v-13.22h3.14c1.94 0 3.52 1.58 3.52 3.52z"/><path d="m11.22 72.57c-.28.28-.44.66-.44 1.06v16.99c0 3.44 2.8 6.25 6.25 6.25h65.95c3.44 0 6.25-2.8 6.25-6.25v-81.23c0-3.44-2.8-6.25-6.25-6.25h-55.9c-3.37 0-6.11 2.74-6.11 6.12v24.13l-9.75 9.75c-.28.28-.44.66-.44 1.06v9.87c0 .83.67 1.5 1.5 1.5h8.69v7.26zm11.25-20.01h-8.69v-7.75l9.75-9.75c.28-.28.44-.66.44-1.06v-24.74c0-1.72 1.4-3.12 3.11-3.12h55.9c1.79 0 3.25 1.46 3.25 3.25v81.23c0 1.79-1.46 3.25-3.25 3.25h-65.96c-1.79 0-3.25-1.46-3.25-3.25v-16.37l9.75-9.75c.28-.28.44-.66.44-1.06v-9.38c.01-.83-.67-1.5-1.49-1.5z"/><path d="m31.84 32.33h4.73c1.39 0 2.51-1.13 2.51-2.51v-16.9c0-1.39-1.13-2.51-2.51-2.51h-4.73c-1.39 0-2.51 1.13-2.51 2.51v16.9c0 1.38 1.13 2.51 2.51 2.51zm.49-18.93h3.76v15.93h-3.76z"/><path d="m45.82 32.33h4.73c1.39 0 2.51-1.13 2.51-2.51v-16.9c0-1.39-1.13-2.51-2.51-2.51h-4.73c-1.39 0-2.51 1.13-2.51 2.51v16.9c-.01 1.38 1.12 2.51 2.51 2.51zm.48-18.93h3.76v15.93h-3.76z"/><path d="m59.79 32.33h4.73c1.39 0 2.51-1.13 2.51-2.51v-16.9c0-1.39-1.13-2.51-2.51-2.51h-4.73c-1.39 0-2.51 1.13-2.51 2.51v16.9c-.01 1.38 1.12 2.51 2.51 2.51zm.48-18.93h3.76v15.93h-3.76z"/><path d="m73.76 32.33h4.73c1.39 0 2.51-1.13 2.51-2.51v-16.9c0-1.39-1.13-2.51-2.51-2.51h-4.73c-1.39 0-2.51 1.13-2.51 2.51v16.9c0 1.38 1.12 2.51 2.51 2.51zm.49-18.93h3.76v15.93h-3.76z"/><path d="m30.83 83.8h48.67c.83 0 1.5-.67 1.5-1.5v-38.79c0-.83-.67-1.5-1.5-1.5h-48.67c-.83 0-1.5.67-1.5 1.5v38.79c0 .82.67 1.5 1.5 1.5zm1.5-38.79h45.67v35.79h-45.67z"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m22 11a1 1 0 0 0 -1 1 9 9 0 1 1 -9-9 8.9 8.9 0 0 1 4.42 1.166l-1.127 1.127a1 1 0 0 0 .707 1.707h4a1 1 0 0 0 1-1v-4a1 1 0 0 0 -1.707-.707l-1.411 1.407a10.9 10.9 0 0 0 -5.882-1.7 11 11 0 1 0 11 11 1 1 0 0 0 -1-1z"/></svg>

After

Width:  |  Height:  |  Size: 288 B

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" enable-background="new 0 0 512 512" height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m272.066 512h-32.133c-25.989 0-47.134-21.144-47.134-47.133v-10.871c-11.049-3.53-21.784-7.986-32.097-13.323l-7.704 7.704c-18.659 18.682-48.548 18.134-66.665-.007l-22.711-22.71c-18.149-18.129-18.671-48.008.006-66.665l7.698-7.698c-5.337-10.313-9.792-21.046-13.323-32.097h-10.87c-25.988 0-47.133-21.144-47.133-47.133v-32.134c0-25.989 21.145-47.133 47.134-47.133h10.87c3.531-11.05 7.986-21.784 13.323-32.097l-7.704-7.703c-18.666-18.646-18.151-48.528.006-66.665l22.713-22.712c18.159-18.184 48.041-18.638 66.664.006l7.697 7.697c10.313-5.336 21.048-9.792 32.097-13.323v-10.87c0-25.989 21.144-47.133 47.134-47.133h32.133c25.989 0 47.133 21.144 47.133 47.133v10.871c11.049 3.53 21.784 7.986 32.097 13.323l7.704-7.704c18.659-18.682 48.548-18.134 66.665.007l22.711 22.71c18.149 18.129 18.671 48.008-.006 66.665l-7.698 7.698c5.337 10.313 9.792 21.046 13.323 32.097h10.87c25.989 0 47.134 21.144 47.134 47.133v32.134c0 25.989-21.145 47.133-47.134 47.133h-10.87c-3.531 11.05-7.986 21.784-13.323 32.097l7.704 7.704c18.666 18.646 18.151 48.528-.006 66.665l-22.713 22.712c-18.159 18.184-48.041 18.638-66.664-.006l-7.697-7.697c-10.313 5.336-21.048 9.792-32.097 13.323v10.871c0 25.987-21.144 47.131-47.134 47.131zm-106.349-102.83c14.327 8.473 29.747 14.874 45.831 19.025 6.624 1.709 11.252 7.683 11.252 14.524v22.148c0 9.447 7.687 17.133 17.134 17.133h32.133c9.447 0 17.134-7.686 17.134-17.133v-22.148c0-6.841 4.628-12.815 11.252-14.524 16.084-4.151 31.504-10.552 45.831-19.025 5.895-3.486 13.4-2.538 18.243 2.305l15.688 15.689c6.764 6.772 17.626 6.615 24.224.007l22.727-22.726c6.582-6.574 6.802-17.438.006-24.225l-15.695-15.695c-4.842-4.842-5.79-12.348-2.305-18.242 8.473-14.326 14.873-29.746 19.024-45.831 1.71-6.624 7.684-11.251 14.524-11.251h22.147c9.447 0 17.134-7.686 17.134-17.133v-32.134c0-9.447-7.687-17.133-17.134-17.133h-22.147c-6.841 0-12.814-4.628-14.524-11.251-4.151-16.085-10.552-31.505-19.024-45.831-3.485-5.894-2.537-13.4 2.305-18.242l15.689-15.689c6.782-6.774 6.605-17.634.006-24.225l-22.725-22.725c-6.587-6.596-17.451-6.789-24.225-.006l-15.694 15.695c-4.842 4.843-12.35 5.791-18.243 2.305-14.327-8.473-29.747-14.874-45.831-19.025-6.624-1.709-11.252-7.683-11.252-14.524v-22.15c0-9.447-7.687-17.133-17.134-17.133h-32.133c-9.447 0-17.134 7.686-17.134 17.133v22.148c0 6.841-4.628 12.815-11.252 14.524-16.084 4.151-31.504 10.552-45.831 19.025-5.896 3.485-13.401 2.537-18.243-2.305l-15.688-15.689c-6.764-6.772-17.627-6.615-24.224-.007l-22.727 22.726c-6.582 6.574-6.802 17.437-.006 24.225l15.695 15.695c4.842 4.842 5.79 12.348 2.305 18.242-8.473 14.326-14.873 29.746-19.024 45.831-1.71 6.624-7.684 11.251-14.524 11.251h-22.148c-9.447.001-17.134 7.687-17.134 17.134v32.134c0 9.447 7.687 17.133 17.134 17.133h22.147c6.841 0 12.814 4.628 14.524 11.251 4.151 16.085 10.552 31.505 19.024 45.831 3.485 5.894 2.537 13.4-2.305 18.242l-15.689 15.689c-6.782 6.774-6.605 17.634-.006 24.225l22.725 22.725c6.587 6.596 17.451 6.789 24.225.006l15.694-15.695c3.568-3.567 10.991-6.594 18.244-2.304z"/><path d="m256 367.4c-61.427 0-111.4-49.974-111.4-111.4s49.973-111.4 111.4-111.4 111.4 49.974 111.4 111.4-49.973 111.4-111.4 111.4zm0-192.8c-44.885 0-81.4 36.516-81.4 81.4s36.516 81.4 81.4 81.4 81.4-36.516 81.4-81.4-36.515-81.4-81.4-81.4z"/></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" height="512" viewBox="0 0 32 32" width="512" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"><path d="m30 17-3 3-3-3h2c0-6.0654-4.9355-11-11-11s-11 4.9346-11 11h-2c0-7.168 5.832-13 13-13s13 5.832 13 13zm0 5h-6v2h6zm-10 0h-2v2h2zm-16 0h-2v2h2zm4 0h-2v2h2zm4 0h-2v2h2zm4 0h-2v2h2z"/></svg>

After

Width:  |  Height:  |  Size: 312 B

+53
View File
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 412.8 412.8" style="enable-background:new 0 0 412.8 412.8;" xml:space="preserve">
<g>
<g>
<path d="M378.4,225.6L304,251.2L274,234v-27.6v-27.2l30-17.2l74.4,25.6c5.2,2,11.2-1.2,12.8-6.4c2-5.2-1.2-11.2-6.4-12.8
l-57.6-19.6l54-31.2c4.8-2.8,6.4-9.2,3.6-14c-2.8-4.8-9.2-6.4-14-3.6l-54,31.2l11.6-59.6c1.2-5.6-2.4-10.8-8-12
c-5.6-1.2-10.8,2.4-12,8l-15.2,77.2l-30,17.2l-22.8-13.2l-0.4-0.4l-23.2-13.6v-34.4L276,48.8c4.4-3.6,4.8-10,0.8-14.4
c-3.6-4.4-10-4.8-14.4-0.8l-45.6,40V10.4c0-5.6-4.4-10.4-10.4-10.4C200.8,0,196,4.4,196,10.4v62.4l-45.6-39.6
C146,29.6,139.6,30,136,34c-3.6,4.4-3.2,10.8,0.8,14.4L196,100v34.4L172.8,148l-23.2,13.6l-30-17.2l-15.2-77.2
c-1.2-5.6-6.4-9.2-12-8c-5.6,1.2-9.2,6.4-8,12L96,130.8L42,99.6c-4.8-2.8-11.2-1.2-14,3.6s-1.2,11.2,3.6,14l54,31.2L28,168
c-5.2,2-8.4,7.6-6.4,12.8s7.6,8.4,12.8,6.4l74.4-25.6l30,17.2v27.6v27.2h0.4l-30,17.2l-74.4-25.6c-5.2-2-11.2,1.2-12.8,6.4
c-2,5.2,1.2,11.2,6.4,12.8L86,264l-54,31.2c-4.8,2.8-6.4,9.2-3.6,14c2.8,4.8,9.2,6.4,14,3.6l54-31.2l-11.6,59.6
c-1.2,5.6,2.4,10.8,8,12c5.6,1.2,10.8-2.4,12-8L120,268l30-17.2l23.6,13.6l23.2,13.6v34.4L137.6,364c-4.4,3.6-4.8,10-0.8,14.4
c3.6,4.4,10,4.8,14.4,0.8l45.6-40v63.2c0,5.6,4.4,10.4,10.4,10.4c5.6,0,10.4-4.4,10.4-10.4V340l45.6,40c4.4,3.6,10.8,3.2,14.4-0.8
c3.6-4.4,3.2-10.8-0.8-14.4l-60-52v-34.4l23.2-13.6l23.2-13.6l30,17.2l15.2,77.2c1.2,5.6,6.4,9.2,12,8c5.6-1.2,9.2-6.4,8-12
L316.8,282l54,31.2c4.8,2.8,11.2,1.2,14-3.6c2.8-4.8,1.2-11.2-3.6-14l-54-31.2l57.6-19.6c5.2-2,8.4-7.6,6.4-12.8
C389.2,226.8,383.6,223.6,378.4,225.6z M252.4,206.4v27.2l-23.2,13.6l-22.8,13.2l-23.6-13.6l-23.2-13.6v-26.8v-27.2l23.2-13.6
L206,152l23.2,13.6l0.4,0.4l22.8,13.2V206.4z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Teamwork" enable-background="new 0 0 64 64" height="512" viewBox="0 0 64 64" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m29.351 39h-15.351c-.553 0-1-.448-1-1s.447-1 1-1h15.351c.553 0 1 .448 1 1s-.448 1-1 1z"/><path d="m29.351 27h-15.351c-.553 0-1-.448-1-1s.447-1 1-1h15.351c.553 0 1 .448 1 1s-.448 1-1 1z"/><path d="m28 33h-20c-.553 0-1-.448-1-1s.447-1 1-1h20c.553 0 1 .448 1 1s-.447 1-1 1z"/><path d="m38 35.902c-1.987 0-4-1.34-4-3.902s2.013-3.902 4-3.902 4 1.34 4 3.902-2.013 3.902-4 3.902zm0-5.804c-.923 0-2 .498-2 1.902s1.077 1.902 2 1.902 2-.498 2-1.902-1.077-1.902-2-1.902z"/><path d="m40.121 30.879c-.256 0-.512-.098-.707-.293-.391-.391-.391-1.023 0-1.414l5.657-5.657c.391-.391 1.023-.391 1.414 0s.391 1.023 0 1.414l-5.657 5.657c-.195.195-.451.293-.707.293z"/><path d="m34.465 36.536c-.256 0-.512-.098-.707-.293-.391-.39-.391-1.023 0-1.414l1.414-1.415c.391-.391 1.023-.391 1.414 0 .391.39.391 1.023 0 1.414l-1.414 1.415c-.195.195-.451.293-.707.293z"/><path d="m38 51c-.553 0-1-.448-1-1v-3c0-.552.447-1 1-1s1 .448 1 1v3c0 .552-.447 1-1 1z"/><path d="m50.728 45.728c-.256 0-.512-.098-.707-.293l-2.121-2.122c-.391-.391-.391-1.024 0-1.414.391-.391 1.023-.391 1.414 0l2.121 2.122c.391.391.391 1.024 0 1.414-.196.195-.452.293-.707.293z"/><path d="m48.606 22.394c-.256 0-.512-.098-.707-.293-.391-.39-.391-1.023 0-1.414l2.121-2.122c.391-.391 1.023-.391 1.414 0 .391.39.391 1.023 0 1.414l-2.121 2.122c-.195.195-.451.293-.707.293z"/><path d="m38 18c-.553 0-1-.448-1-1v-3c0-.552.447-1 1-1s1 .448 1 1v3c0 .552-.447 1-1 1z"/><path d="m56 33h-3c-.553 0-1-.448-1-1s.447-1 1-1h3c.553 0 1 .448 1 1s-.447 1-1 1z"/><path d="m30.789 21h-10.789c-.553 0-1-.448-1-1s.447-1 1-1h10.789c.553 0 1 .448 1 1s-.447 1-1 1z"/><path d="m30.789 45h-10.789c-.553 0-1-.448-1-1s.447-1 1-1h10.789c.553 0 1 .448 1 1s-.447 1-1 1z"/><path d="m37.938 50.981c-2.931 0-5.892-.675-8.642-2.092-.491-.253-.684-.856-.431-1.347s.857-.684 1.347-.431c7.844 4.042 17.615 1.334 22.245-6.165 4.643-7.521 2.7-17.48-4.423-22.673-5.159-3.76-12.155-4.304-17.822-1.385-.49.253-1.094.061-1.347-.431-.253-.491-.061-1.094.431-1.347 6.333-3.264 14.149-2.657 19.916 1.546 7.962 5.804 10.135 16.935 4.946 25.34-3.551 5.754-9.81 8.985-16.22 8.985z"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" height="512" viewBox="0 0 64 64" width="512" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"><path d="m36 39.47v-32.47a7 7 0 1 0 -14 0v32.47a13.26 13.26 0 1 0 14 0zm-7 22.59a11.32 11.32 0 0 1 -5.53-21.19 1 1 0 0 0 .53-.87v-33a5 5 0 1 1 10 0v33a1 1 0 0 0 .49.84 11.32 11.32 0 0 1 -5.49 21.22z"/><path d="m30 44.89v-30.25a1 1 0 1 0 -1.94 0v30.25a5.94 5.94 0 1 0 1.94 0zm-1 9.85a4 4 0 1 1 4-4 4 4 0 0 1 -4 4z"/><path d="m40.32 9.64h7a1 1 0 0 0 0-1.94h-7a1 1 0 1 0 0 1.94z"/><path d="m40.32 16.06h4.06a1 1 0 0 0 0-1.94h-4.06a1 1 0 0 0 0 1.94z"/><path d="m47.29 20.55h-7a1 1 0 1 0 0 1.93h7a1 1 0 1 0 0-1.93z"/><path d="m40.32 28.91h4.06a1 1 0 0 0 0-1.94h-4.06a1 1 0 0 0 0 1.94z"/><path d="m47.29 33.39h-7a1 1 0 0 0 0 1.94h7a1 1 0 1 0 0-1.94z"/></svg>

After

Width:  |  Height:  |  Size: 770 B

+1
View File
@@ -0,0 +1 @@
<svg id="layer_1" enable-background="new 0 0 200 200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"><g fill="rgb(0,0,0)"><path d="m61.3366 198.7365c-3.8893 0-7.7945-1.0847-11.3086-3.2781-32.6418-20.3714-44.9485-46.703-49.5247-65.2053-6.1066-30.8373 44.9333-36.4535 67.8505-35.056 1.761-6.9634 6.1301-13.08 12.1249-17.0214-9.0714-12.1387-21.2458-19.7867-36.2543-22.7586-19.3391-3.2847-23.4263-31.1087-5.8545-39.8477 33.3392-19.0024 97.1952-22.5083 96.3704 10.811-.6835 19.2868-6.9715 37.8308-18.7038 55.1859 5.1612 4.9953 8.292 11.7803 8.6884 19.0147 15.0429-1.7888 27.7494-8.5077 37.8247-20.0165 6.0052-6.8593 15.3868-9.1156 23.9022-5.7478 8.5361 3.3773 13.8491 11.4631 13.535 20.6005-1.3216 38.4536-17.9721 62.2774-31.708 75.4917-23.6412 20.7064-54.0319-20.679-64.2755-41.2153-6.816 1.9769-14.557 1.2532-20.8202-1.9875-5.969 13.9198-6.5027 28.2804-1.574 42.7574 5.0949 13.3396-6.2694 28.6219-20.2725 28.273zm-1.6188-94.5681c-14.1176.1632-54.2272 5.0317-50.2069 23.856 4.1646 16.8367 15.4261 40.8368 45.43 59.562 5.3197 3.3207 10.6838 1.7539 13.9293-.8201 3.2305-2.5623 5.9658-7.4048 3.9546-13.3126-6.3202-18.5652-4.873-36.9425 4.3011-54.6216.6379-1.2292 1.7915-2.1091 3.1458-2.3995 1.3551-.2882 2.7674.0404 3.8526.8993 3.4512 2.733 7.6019 4.1775 12.0037 4.1775 4.9261.8516 11.3607-5.6527 14.5071.4457 6.0281 15.2396 35.1102 56.5264 51.2108 42.2675 12.4987-12.025 27.6526-33.7782 28.8673-69.1245.0159-11.6249-13.2308-16.8886-21.1812-8.4221-12.9177 14.7553-29.5546 22.6907-49.4492 23.5865-1.3715.0602-2.7195-.4957-3.6482-1.5215-1.8205-1.8024-.9363-4.3611-.9455-6.5928-.0001-6.3459-3.1223-12.2987-8.3528-15.9233-1.0257-.7109-1.7221-1.8051-1.931-3.0357-.2093-1.2306.0861-2.4938.8196-3.5037 10.2153-12.9246 31.3669-58.5212 11.0023-65.4878-16.6655-4.8123-43.08-7.0587-74.2968 9.5628-10.0753 5.7972-8.0115 19.9044 3.2961 22.5543 19.2372 3.809 34.4279 14.2491 45.1507 31.0306 1.5812 2.3482.4574 5.827-2.1953 6.8094-6.7913 2.7009-11.5582 9.1434-12.144 16.4131-.1006 1.2455-.6991 2.3982-1.6611 3.1966-4.5407 2.4665-10.5485-.3007-15.459.4039z"/><path d="m96.1279 112.2302c-7.607 1.0321-15.4151-13.051-5.4426-14.7224 2.5623.0007 4.6397 2.0781 4.6397 4.6403 0 .4354.3675.8028.8029.8028 6.0654.0249 6.0675 9.2545 0 9.2793z"/><path d="m9.2329 99.228c-12.7712-.764 4.8333-40.6245 9.5289-46.5697 3.292-5.0803 11.0691-.1194 7.8098 5.0118-7.1818 11.1897-11.5808 24.0937-12.7217 37.3166-.2085 2.4172-2.2352 4.2413-4.617 4.2413z"/><path d="m39.2577 89.6348c-11.0543-1.6919 1.3997-18.9153 4.3572-24.1282 3.4934-4.9529 11.064.3241 7.6063 5.3167-3.325 4.7567-5.8564 9.9749-7.5229 15.5084-.6044 2.0077-2.4471 3.3031-4.4406 3.3031z"/><path d="m96.2071 193.9939c-3.6525.2417-8.8695-.1084-8.6734-4.9527.12-2.5591 2.2921-4.5182 4.8525-4.4162 13.2881.6302 26.6579-2.0181 38.6783-7.6414 5.4914-2.5456 9.4266 5.808 3.9316 8.4049-12.0948 5.6586-25.4224 8.6054-38.789 8.6054z"/><path d="m96.194 166.1857c-3.9048.076-10.1254.1951-9.7645-5.2634.2215-2.5524 2.4715-4.439 5.0229-4.2215 5.7823.502 11.5673.0847 17.1924-1.2392 2.4947-.584 4.9917.9597 5.5789 3.4539.8588 8.4162-12.5193 6.4771-18.0297 7.2702z"/><path d="m173.5515 66.6619c-1.6806 0-3.3021-.9157-4.1263-2.512-6.0995-11.8142-15.0751-22.0758-25.9565-29.6754-4.9499-3.4817.3164-11.067 5.3132-7.6072 6.2137 3.1209 41.191 37.1803 24.7696 39.7946z"/><path d="m149.9162 81.597c-1.7462 0-3.4186-.99-4.2065-2.6759-2.4571-5.2576-5.7103-10.0585-9.6698-14.27-4.1842-4.3187 2.6992-10.8071 6.7603-6.3556 3.7145 4.588 19.1197 21.1144 7.116 23.3015z"/></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

+1
View File
@@ -0,0 +1 @@
<svg height="472pt" viewBox="0 -87 472 472" width="472pt" xmlns="http://www.w3.org/2000/svg"><path d="m467.101562 26.527344c-3.039062-1.800782-6.796874-1.871094-9.898437-.179688l-108.296875 59.132813v-35.480469c-.03125-27.601562-22.398438-49.96875-50-50h-248.90625c-27.601562.03125-49.96875 22.398438-50 50v197.421875c.03125 27.601563 22.398438 49.96875 50 50h248.90625c27.601562-.03125 49.96875-22.398437 50-50v-34.835937l108.300781 59.132812c3.097657 1.691406 6.859375 1.625 9.894531-.175781 3.039063-1.804688 4.898438-5.074219 4.898438-8.601563v-227.816406c0-3.53125-1.863281-6.796875-4.898438-8.597656zm-138.203124 220.898437c-.015626 16.5625-13.4375 29.980469-30 30h-248.898438c-16.5625-.019531-29.980469-13.4375-30-30v-197.425781c.019531-16.558594 13.4375-29.980469 30-30h248.90625c16.558594.019531 29.980469 13.441406 30 30zm123.101562-1.335937-103.09375-56.289063v-81.535156l103.09375-56.285156zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 916 B

+2
View File
@@ -0,0 +1,2 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="512" height="512"><g id="Water"><path d="M24,46A16.0183,16.0183,0,0,1,8,30C8,16.0942,22.708,2.8125,23.3345,2.2539a.9983.9983,0,0,1,1.331,0C25.292,2.8125,40,16.0942,40,30A16.0183,16.0183,0,0,1,24,46ZM24,4.3721C21.1333,7.1372,10,18.6118,10,30a14,14,0,0,0,28,0C38,18.6118,26.8667,7.1372,24,4.3721Z"/><path d="M18.4976,40.5273a.9946.9946,0,0,1-.5-.1342A12.0449,12.0449,0,0,1,12,30a1,1,0,0,1,2,0,10.0373,10.0373,0,0,0,5,8.6616,1,1,0,0,1-.5019,1.8657Z"/></g></svg>

After

Width:  |  Height:  |  Size: 548 B

+73
View File
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M256,40c-5.52,0-10,4.48-10,10s4.48,10,10,10s10-4.48,10-10S261.52,40,256,40z"/>
</g>
</g>
<g>
<g>
<path d="M466,210C466,94.206,371.794,0,256,0S46,94.206,46,210c0,96.488,66.579,180.855,159.516,203.859
c-1.591,14.119-6.958,31.441-13.568,38.051l-0.131,0.131c-18.899,0.353-32.638,3.149-42.999,8.73
C133.677,468.949,126,482.82,126,502c0,5.522,4.478,10,10,10h240c5.522,0,10-4.478,10-10c0-19.187-7.68-33.058-22.824-41.229
c-10.344-5.58-24.082-8.378-42.992-8.731l-0.132-0.132c-6.61-6.609-11.977-23.931-13.568-38.05
C399.423,390.853,466,306.486,466,210z M316,472c33.23,0,45.303,7.689,48.794,20H147.226c2.172-7.762,6.862-11.345,11.087-13.626
C166.274,474.085,178.603,472,196,472H316z M215.517,452c5.068-10.601,8.238-23.466,9.638-34.27
C235.326,419.232,245.658,420,256,420c10.342,0,20.674-0.768,30.845-2.27c1.401,10.804,4.57,23.67,9.638,34.27H215.517z
M294.015,396.179c-0.019,0.004-0.037,0.007-0.056,0.011c-24.788,5.056-51.127,5.057-75.922-0.001
c-0.017-0.004-0.035-0.007-0.052-0.01C129.918,378.227,66,299.929,66,210c0-104.767,85.233-190,190-190s190,85.233,190,190
C446,299.929,382.082,378.227,294.015,396.179z"/>
</g>
</g>
<g>
<g>
<path d="M389.606,104.994c-23.072-29.303-55.544-50.505-91.434-59.701c-5.355-1.374-10.799,1.855-12.17,7.205
c-1.37,5.35,1.855,10.798,7.205,12.169c31.66,8.112,60.314,26.828,80.686,52.7c3.426,4.352,9.716,5.077,14.043,1.67
C392.275,115.621,393.023,109.333,389.606,104.994z"/>
</g>
</g>
<g>
<g>
<path d="M256,100c-60.654,0-110,49.346-110,110s49.346,110,110,110s110-49.346,110-110S316.654,100,256,100z M256,300
c-49.626,0-90-40.374-90-90c0-49.626,40.374-90,90-90c49.626,0,90,40.374,90,90C346,259.626,305.626,300,256,300z"/>
</g>
</g>
<g>
<g>
<path d="M256,140c-38.598,0-70,31.402-70,70c0,38.598,31.402,70,70,70c38.598,0,70-31.402,70-70C326,171.402,294.598,140,256,140z
M256,260c-27.57,0-50-22.43-50-50s22.43-50,50-50s50,22.43,50,50S283.57,260,256,260z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

@@ -0,0 +1,337 @@
import { useState } from 'react';
import { useMutation } from '@tanstack/react-query';
import { api } from '../../api/client';
import type { PrinterStatus, AMSUnit } from '../../api/client';
import { Loader2 } from 'lucide-react';
interface AMSSectionDualProps {
printerId: number;
status: PrinterStatus | null | undefined;
nozzleCount: number;
}
function hexToRgb(hex: string | null): string {
if (!hex) return 'rgb(128, 128, 128)';
const cleanHex = hex.replace('#', '').substring(0, 6);
const r = parseInt(cleanHex.substring(0, 2), 16) || 128;
const g = parseInt(cleanHex.substring(2, 4), 16) || 128;
const b = parseInt(cleanHex.substring(4, 6), 16) || 128;
return `rgb(${r}, ${g}, ${b})`;
}
function isLightColor(hex: string | null): boolean {
if (!hex) return false;
const cleanHex = hex.replace('#', '').substring(0, 6);
const r = parseInt(cleanHex.substring(0, 2), 16) || 0;
const g = parseInt(cleanHex.substring(2, 4), 16) || 0;
const b = parseInt(cleanHex.substring(4, 6), 16) || 0;
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
return luminance > 0.5;
}
interface AMSPanelContentProps {
units: AMSUnit[];
side: 'left' | 'right';
isPrinting: boolean;
selectedAmsIndex: number;
onSelectAms: (index: number) => void;
selectedTray: number | null;
onSelectTray: (trayId: number | null) => void;
}
function AMSPanelContent({
units,
side,
isPrinting,
selectedAmsIndex,
onSelectAms,
selectedTray,
onSelectTray,
}: AMSPanelContentProps) {
const selectedUnit = units[selectedAmsIndex];
const slotPrefix = side === 'left' ? 'A' : 'B';
return (
<div className="flex-1 min-w-0 overflow-visible">
<div className="text-center text-[11px] font-semibold text-bambu-gray uppercase mb-2">
{side === 'left' ? 'Left Nozzle' : 'Right Nozzle'}
</div>
{/* AMS Tab Selectors - only show connected units */}
<div className="flex gap-1.5 mb-2.5 p-1.5 bg-bambu-dark/50 rounded-lg w-fit">
{units.map((unit, index) => (
<button
key={unit.id}
onClick={() => onSelectAms(index)}
className={`flex items-center p-1.5 rounded border-2 transition-colors bg-bambu-dark ${
selectedAmsIndex === index
? 'border-bambu-green'
: 'border-transparent hover:border-bambu-gray'
}`}
>
<div className="flex gap-0.5">
{unit.tray.map((tray) => (
<div
key={tray.id}
className="w-2.5 h-2.5 rounded-full"
style={{
backgroundColor: tray.tray_color ? hexToRgb(tray.tray_color) : '#808080',
}}
/>
))}
</div>
</button>
))}
</div>
{/* AMS Content */}
{selectedUnit && (
<div className="bg-bambu-dark-secondary rounded-[10px] p-2.5 pb-0 overflow-visible">
{/* AMS Header - Humidity & Temp */}
<div className="flex items-center gap-2.5 text-xs text-bambu-gray mb-2">
{selectedUnit.humidity !== null && (
<span className="flex items-center gap-1">
<img src="/icons/water.svg" alt="" className="w-3.5 icon-theme" />
{selectedUnit.humidity} %
</span>
)}
{selectedUnit.temp !== null && (
<span className="flex items-center gap-1">
<img src="/icons/temperature.svg" alt="" className="w-3.5 icon-theme" />
{selectedUnit.temp}°C
</span>
)}
<span className="text-yellow-500 text-sm">☀</span>
</div>
{/* Slot Labels */}
<div className="flex justify-center gap-1.5 mb-1.5">
{selectedUnit.tray.map((tray, index) => (
<div
key={tray.id}
className="w-12 flex items-center justify-center gap-0.5 text-[10px] text-bambu-gray px-1.5 py-[3px] bg-bambu-dark rounded-full border border-bambu-dark-tertiary"
>
{slotPrefix}{index + 1}
<img src="/icons/reload.svg" alt="" className="w-2.5 h-2.5 icon-theme" />
</div>
))}
</div>
{/* AMS Slots with integrated wiring */}
<div className="flex justify-center gap-1.5 mb-0">
{selectedUnit.tray.map((tray) => {
const globalTrayId = selectedUnit.id * 4 + tray.id;
const isSelected = selectedTray === globalTrayId;
const isEmpty = !tray.tray_type || tray.tray_type === '' || tray.tray_type === 'NONE';
const isLight = isLightColor(tray.tray_color);
return (
<div key={tray.id} className="flex flex-col items-center">
<button
onClick={() => !isEmpty && onSelectTray(isSelected ? null : globalTrayId)}
disabled={isEmpty || isPrinting}
className={`w-12 h-[70px] rounded-md border-2 overflow-hidden transition-all bg-bambu-dark ${
isSelected
? 'border-[#d4a84b]'
: 'border-bambu-dark-tertiary hover:border-bambu-gray'
} ${isEmpty ? 'opacity-50' : ''} disabled:cursor-not-allowed`}
>
<div
className="w-full h-full flex flex-col items-center justify-end pb-[5px]"
style={{
backgroundColor: isEmpty ? undefined : hexToRgb(tray.tray_color),
}}
>
<span
className={`text-[11px] font-semibold mb-1 ${
isLight ? 'text-gray-800' : 'text-white'
} ${isLight ? '' : 'drop-shadow-sm'}`}
>
{isEmpty ? '--' : tray.tray_type}
</span>
{!isEmpty && (
<img
src="/icons/eye.svg"
alt=""
className={`w-3.5 h-3.5 ${isLight ? '' : 'invert'}`}
style={{ opacity: 0.8 }}
/>
)}
</div>
</button>
{/* Vertical wire from slot center down */}
<div className="w-[2px] h-[14px] bg-[#909090]" />
</div>
);
})}
</div>
{/* Wiring visualization - horizontal bar and hub */}
<div className="flex justify-center">
<div className="relative h-[50px]" style={{ width: '210px' }}>
{/* Horizontal bar connecting all slots (spans from first to last slot center) */}
<div className="absolute left-[24px] right-[24px] top-0 border-t-2 border-[#909090]" />
{/* Center hub box on the horizontal bar */}
<div className="absolute left-1/2 -translate-x-1/2 top-[-6px] w-[28px] h-[14px] bg-[#c0c0c0] border border-[#909090] rounded-sm" />
{/* Vertical wire from hub going down */}
<div className="absolute left-1/2 -translate-x-[1px] top-[8px] h-[14px] border-l-2 border-[#909090]" />
{/* Horizontal wire from hub toward the center of the panel (extends beyond panel edge) */}
{side === 'left' && (
<div className="absolute left-1/2 top-[21px] w-[calc(50%+30px)] border-t-2 border-[#909090]" />
)}
{side === 'right' && (
<div className="absolute right-1/2 top-[21px] w-[calc(50%+30px)] border-t-2 border-[#909090]" />
)}
</div>
</div>
</div>
)}
{/* No AMS message */}
{units.length === 0 && (
<div className="bg-bambu-dark-secondary rounded-[10px] p-6 text-center text-bambu-gray text-sm">
No AMS connected to {side} nozzle
</div>
)}
</div>
);
}
export function AMSSectionDual({ printerId, status, nozzleCount }: AMSSectionDualProps) {
const isConnected = status?.connected ?? false;
const isPrinting = status?.state === 'RUNNING';
const isDualNozzle = nozzleCount > 1;
const amsUnits: AMSUnit[] = status?.ams ?? [];
// For dual nozzle, split AMS units between left and right
// In real implementation, this would be based on actual nozzle assignment
const leftUnits = isDualNozzle ? amsUnits.filter((_, i) => i % 2 === 0) : amsUnits;
const rightUnits = isDualNozzle ? amsUnits.filter((_, i) => i % 2 === 1) : [];
const [leftAmsIndex, setLeftAmsIndex] = useState(0);
const [rightAmsIndex, setRightAmsIndex] = useState(0);
const [selectedTray, setSelectedTray] = useState<number | null>(null);
const loadMutation = useMutation({
mutationFn: (trayId: number) => api.amsLoadFilament(printerId, trayId),
});
const unloadMutation = useMutation({
mutationFn: () => api.amsUnloadFilament(printerId),
});
const handleLoad = () => {
if (selectedTray !== null) {
loadMutation.mutate(selectedTray);
}
};
const handleUnload = () => {
unloadMutation.mutate();
};
const isLoading = loadMutation.isPending || unloadMutation.isPending;
return (
<div className="bg-bambu-dark-tertiary rounded-[10px] p-3 relative overflow-visible">
{/* Center wiring and Extruder - absolutely centered between the two AMS panels */}
{isDualNozzle && (
<>
{/* Center wiring: two vertical lines going down to extruder inlets */}
{/* Positioned to connect with horizontal wires from AMS panels */}
<div className="absolute left-1/2 -translate-x-1/2 bottom-[62px] pointer-events-none" style={{ width: '24px', height: '30px' }}>
{/* Left vertical line - connects to left AMS horizontal wire, goes to left extruder inlet */}
<div className="absolute left-0 top-0 h-full border-l-2 border-[#909090]" />
{/* Right vertical line - connects to right AMS horizontal wire, goes to right extruder inlet */}
<div className="absolute right-0 top-0 h-full border-l-2 border-[#909090]" />
</div>
{/* Extruder */}
<img
src="/icons/extruder-left-right.png"
alt="Extruder"
className="absolute h-[50px] left-1/2 -translate-x-1/2 bottom-[12px]"
/>
</>
)}
{/* Dual Panel Layout */}
<div className="flex gap-5 overflow-visible">
{/* Left Nozzle Panel */}
<AMSPanelContent
units={leftUnits}
side="left"
isPrinting={isPrinting}
selectedAmsIndex={leftAmsIndex}
onSelectAms={setLeftAmsIndex}
selectedTray={selectedTray}
onSelectTray={setSelectedTray}
/>
{/* Right Nozzle Panel - only for dual nozzle */}
{isDualNozzle && (
<AMSPanelContent
units={rightUnits}
side="right"
isPrinting={isPrinting}
selectedAmsIndex={rightAmsIndex}
onSelectAms={setRightAmsIndex}
selectedTray={selectedTray}
onSelectTray={setSelectedTray}
/>
)}
</div>
{/* Action Buttons Row with Extruder */}
<div className="flex items-start pt-2">
{/* Left buttons */}
<div className="flex items-center gap-2">
<button className="w-10 h-10 rounded-lg bg-bambu-dark-secondary hover:bg-bambu-dark border border-bambu-dark-tertiary flex items-center justify-center">
<img src="/icons/ams-settings.svg" alt="Settings" className="w-5 icon-theme" />
</button>
<button className="px-[18px] py-2.5 rounded-lg bg-bambu-dark-secondary hover:bg-bambu-dark border border-bambu-dark-tertiary text-sm text-bambu-gray flex items-center gap-1.5">
Auto-refill
</button>
</div>
{/* Spacer */}
<div className="flex-1" />
{/* Right buttons */}
<div className="flex items-center gap-2">
<button
onClick={handleUnload}
disabled={!isConnected || isPrinting || isLoading}
className="px-7 py-2.5 rounded-lg bg-bambu-dark hover:bg-bambu-dark-secondary text-sm text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
>
{unloadMutation.isPending ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
'Unload'
)}
</button>
<button
onClick={handleLoad}
disabled={!isConnected || isPrinting || selectedTray === null || isLoading}
className="px-7 py-2.5 rounded-lg bg-bambu-dark hover:bg-bambu-dark-secondary text-sm text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
>
{loadMutation.isPending ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
'Load'
)}
</button>
</div>
</div>
{/* Error messages */}
{(loadMutation.error || unloadMutation.error) && (
<p className="mt-2 text-sm text-red-500 text-center">
{(loadMutation.error || unloadMutation.error)?.message}
</p>
)}
</div>
);
}
@@ -0,0 +1,99 @@
import { useMutation } from '@tanstack/react-query';
import { api, isConfirmationRequired } from '../../api/client';
import type { PrinterStatus } from '../../api/client';
import { useState } from 'react';
import { ConfirmModal } from '../ConfirmModal';
interface BedControlsProps {
printerId: number;
status: PrinterStatus | null | undefined;
}
export function BedControls({ printerId, status }: BedControlsProps) {
const isConnected = status?.connected ?? false;
const [confirmModal, setConfirmModal] = useState<{
token: string;
warning: string;
distance: number;
} | null>(null);
const moveMutation = useMutation({
mutationFn: ({ distance, token }: { distance: number; token?: string }) =>
api.moveAxis(printerId, 'Z', distance, 1000, token),
onSuccess: (result, variables) => {
if (isConfirmationRequired(result)) {
setConfirmModal({
token: result.token,
warning: result.warning,
distance: variables.distance,
});
}
},
});
const handleMove = (distance: number) => {
moveMutation.mutate({ distance });
};
const handleConfirm = () => {
if (confirmModal) {
moveMutation.mutate({ distance: confirmModal.distance, token: confirmModal.token });
setConfirmModal(null);
}
};
const isDisabled = !isConnected || moveMutation.isPending;
return (
<>
<div className="flex items-center gap-2">
<button
onClick={() => handleMove(10)}
disabled={isDisabled}
className="px-3.5 py-2 rounded-md bg-bambu-dark-secondary hover:bg-bambu-dark-tertiary border border-bambu-dark-tertiary text-sm text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
title="Z+10"
>
↑10
</button>
<button
onClick={() => handleMove(1)}
disabled={isDisabled}
className="px-3.5 py-2 rounded-md bg-bambu-dark-secondary hover:bg-bambu-dark-tertiary border border-bambu-dark-tertiary text-sm text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
title="Z+1"
>
↑1
</button>
<span className="px-2 py-2 text-sm text-bambu-gray">Bed</span>
<button
onClick={() => handleMove(-1)}
disabled={isDisabled}
className="px-3.5 py-2 rounded-md bg-bambu-dark-secondary hover:bg-bambu-dark-tertiary border border-bambu-dark-tertiary text-sm text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
title="Z-1"
>
↓1
</button>
<button
onClick={() => handleMove(-10)}
disabled={isDisabled}
className="px-3.5 py-2 rounded-md bg-bambu-dark-secondary hover:bg-bambu-dark-tertiary border border-bambu-dark-tertiary text-sm text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
title="Z-10"
>
↓10
</button>
</div>
{/* Confirmation Modal */}
{confirmModal && (
<ConfirmModal
title="Confirm Bed Movement"
message={confirmModal.warning}
confirmText="Continue"
variant="warning"
onConfirm={handleConfirm}
onCancel={() => setConfirmModal(null)}
/>
)}
</>
);
}
+67 -75
View File
@@ -55,84 +55,76 @@ export function CameraFeed({ printerId, isConnected }: CameraFeedProps) {
};
return (
<div className="bg-bambu-dark-secondary rounded-lg overflow-hidden">
<div className="flex items-center justify-between px-4 py-2 border-b border-bambu-dark-tertiary">
<div className="flex items-center gap-2">
<Camera className="w-4 h-4 text-bambu-gray" />
<span className="text-sm font-medium">Camera</span>
</div>
<div className="flex items-center gap-2">
{streamEnabled && (
<>
<button
onClick={handleRefresh}
className="p-1.5 rounded hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white transition-colors"
title="Refresh stream"
>
<RefreshCw className="w-4 h-4" />
</button>
<button
onClick={handleFullscreen}
className="p-1.5 rounded hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white transition-colors"
title="Fullscreen"
>
<Maximize2 className="w-4 h-4" />
</button>
</>
)}
<button
onClick={handleToggleStream}
disabled={!isConnected}
className={`px-3 py-1 rounded text-sm transition-colors ${
streamEnabled
? 'bg-red-500/20 text-red-400 hover:bg-red-500/30'
: 'bg-bambu-green/20 text-bambu-green hover:bg-bambu-green/30'
} disabled:opacity-50 disabled:cursor-not-allowed`}
>
{streamEnabled ? 'Stop' : 'Start'}
</button>
</div>
</div>
<div className="relative aspect-video bg-bambu-dark">
{!streamEnabled ? (
<div className="absolute inset-0 flex flex-col items-center justify-center text-bambu-gray">
<CameraOff className="w-12 h-12 mb-2" />
<span className="text-sm">
<div className="relative w-full h-full bg-black">
{!streamEnabled ? (
<div className="absolute inset-0 flex flex-col items-center justify-center text-bambu-gray">
<div className="bg-bambu-dark-secondary rounded-lg p-6 flex flex-col items-center">
<Camera className="w-8 h-8 mb-2" />
<span className="text-sm mb-3">
{isConnected ? 'Click Start to view camera' : 'Printer not connected'}
</span>
<button
onClick={handleToggleStream}
disabled={!isConnected}
className="px-4 py-1.5 rounded text-sm bg-bambu-green text-white hover:bg-bambu-green-dark disabled:opacity-50 disabled:cursor-not-allowed"
>
Start
</button>
</div>
) : (
<>
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-bambu-dark">
<Loader2 className="w-8 h-8 animate-spin text-bambu-green" />
</div>
)}
{error ? (
<div className="absolute inset-0 flex flex-col items-center justify-center text-red-400">
<CameraOff className="w-12 h-12 mb-2" />
<span className="text-sm">{error}</span>
<button
onClick={handleRefresh}
className="mt-2 text-xs text-bambu-green hover:underline"
>
Retry
</button>
</div>
) : (
<img
ref={imgRef}
src={streamUrl}
alt="Camera stream"
className="w-full h-full object-contain"
onLoad={handleImageLoad}
onError={handleImageError}
/>
)}
</>
)}
</div>
</div>
) : (
<>
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center">
<Loader2 className="w-8 h-8 animate-spin text-bambu-green" />
</div>
)}
{error ? (
<div className="absolute inset-0 flex flex-col items-center justify-center text-red-400">
<CameraOff className="w-12 h-12 mb-2" />
<span className="text-sm">{error}</span>
<button
onClick={handleRefresh}
className="mt-2 text-xs text-bambu-green hover:underline"
>
Retry
</button>
</div>
) : (
<img
ref={imgRef}
src={streamUrl}
alt="Camera stream"
className="w-full h-full object-contain"
onLoad={handleImageLoad}
onError={handleImageError}
/>
)}
{/* Overlay controls */}
<div className="absolute top-2 right-2 flex gap-2">
<button
onClick={handleRefresh}
className="p-2 rounded bg-black/50 hover:bg-black/70 text-white transition-colors"
title="Refresh stream"
>
<RefreshCw className="w-4 h-4" />
</button>
<button
onClick={handleFullscreen}
className="p-2 rounded bg-black/50 hover:bg-black/70 text-white transition-colors"
title="Fullscreen"
>
<Maximize2 className="w-4 h-4" />
</button>
<button
onClick={handleToggleStream}
className="px-3 py-1.5 rounded bg-red-500/80 hover:bg-red-500 text-white text-sm transition-colors"
>
Stop
</button>
</div>
</>
)}
</div>
);
}
@@ -0,0 +1,98 @@
import { useState } from 'react';
import { useMutation } from '@tanstack/react-query';
import type { PrinterStatus } from '../../api/client';
import { ChevronUp, ChevronDown } from 'lucide-react';
interface ExtruderControlsProps {
printerId: number;
status: PrinterStatus | null | undefined;
nozzleCount: number;
}
export function ExtruderControls({ status, nozzleCount }: ExtruderControlsProps) {
const isConnected = status?.connected ?? false;
const isPrinting = status?.state === 'RUNNING' || status?.state === 'PAUSE';
const isDualNozzle = nozzleCount > 1;
const [selectedNozzle, setSelectedNozzle] = useState<'left' | 'right'>('left');
// TODO: Add extrude/retract API calls when available
const extrudeMutation = useMutation({
mutationFn: async ({ distance }: { distance: number }) => {
// Placeholder - implement when API is ready
console.log(`Extrude ${distance}mm on ${selectedNozzle} nozzle`);
},
});
const handleExtrude = (distance: number) => {
extrudeMutation.mutate({ distance });
};
const isDisabled = !isConnected || isPrinting || extrudeMutation.isPending;
return (
<div className="flex flex-col items-center gap-1.5 flex-1 justify-center">
{/* Left/Right Toggle - only for dual nozzle */}
{isDualNozzle && (
<div className="flex rounded-md overflow-hidden border border-bambu-dark-tertiary mb-1 flex-shrink-0">
<button
onClick={() => setSelectedNozzle('left')}
className={`px-3 py-1.5 text-sm border-r border-bambu-dark-tertiary transition-colors ${
selectedNozzle === 'left'
? 'bg-bambu-green text-white'
: 'bg-bambu-dark-secondary text-bambu-gray hover:bg-bambu-dark-tertiary'
}`}
>
Left
</button>
<button
onClick={() => setSelectedNozzle('right')}
className={`px-3 py-1.5 text-sm transition-colors ${
selectedNozzle === 'right'
? 'bg-bambu-green text-white'
: 'bg-bambu-dark-secondary text-bambu-gray hover:bg-bambu-dark-tertiary'
}`}
>
Right
</button>
</div>
)}
{/* Extrude Up Button */}
<button
onClick={() => handleExtrude(5)}
disabled={isDisabled}
className="w-9 h-[30px] rounded-md bg-bambu-dark-secondary hover:bg-bambu-dark-tertiary border border-bambu-dark-tertiary flex items-center justify-center text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
title="Extrude 5mm"
>
<ChevronUp className="w-4 h-4" />
</button>
{/* Extruder Image */}
<div className="h-[120px] flex items-center justify-center">
<img
src={isDualNozzle ? "/icons/dual-extruder.png" : "/icons/single-extruder1.png"}
alt={isDualNozzle ? "Dual Extruder" : "Single Extruder"}
className="h-full object-contain"
onError={(e) => {
// Fallback if image doesn't load
(e.target as HTMLImageElement).style.display = 'none';
}}
/>
</div>
{/* Retract Down Button */}
<button
onClick={() => handleExtrude(-5)}
disabled={isDisabled}
className="w-9 h-[30px] rounded-md bg-bambu-dark-secondary hover:bg-bambu-dark-tertiary border border-bambu-dark-tertiary flex items-center justify-center text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
title="Retract 5mm"
>
<ChevronDown className="w-4 h-4" />
</button>
{/* Label */}
<span className="text-xs text-bambu-gray mt-0.5">Extruder</span>
</div>
);
}
+160
View File
@@ -0,0 +1,160 @@
import { useMutation } from '@tanstack/react-query';
import { api, isConfirmationRequired } from '../../api/client';
import type { PrinterStatus } from '../../api/client';
import { useState } from 'react';
import { ConfirmModal } from '../ConfirmModal';
interface JogPadProps {
printerId: number;
status: PrinterStatus | null | undefined;
}
export function JogPad({ printerId, status }: JogPadProps) {
const isConnected = status?.connected ?? false;
const [confirmModal, setConfirmModal] = useState<{
action: string;
token: string;
warning: string;
onConfirm: () => void;
} | null>(null);
const homeMutation = useMutation({
mutationFn: ({ axes, token }: { axes: string; token?: string }) =>
api.homeAxes(printerId, axes, token),
onSuccess: (result) => {
if (isConfirmationRequired(result)) {
setConfirmModal({
action: 'home',
token: result.token,
warning: result.warning,
onConfirm: () => homeMutation.mutate({ axes: 'XY', token: result.token }),
});
}
},
});
const moveMutation = useMutation({
mutationFn: ({ axis, distance, token }: { axis: string; distance: number; token?: string }) =>
api.moveAxis(printerId, axis, distance, 3000, token),
onSuccess: (result, variables) => {
if (isConfirmationRequired(result)) {
setConfirmModal({
action: 'move',
token: result.token,
warning: result.warning,
onConfirm: () =>
moveMutation.mutate({
axis: variables.axis,
distance: variables.distance,
token: result.token,
}),
});
}
},
});
const handleHome = () => {
homeMutation.mutate({ axes: 'XY' });
};
const handleMove = (axis: string, distance: number) => {
moveMutation.mutate({ axis, distance });
};
const handleConfirm = () => {
if (confirmModal) {
confirmModal.onConfirm();
setConfirmModal(null);
}
};
const isLoading = homeMutation.isPending || moveMutation.isPending;
const isDisabled = !isConnected || isLoading;
return (
<>
<div className="relative w-[220px] h-[220px] mb-3.5">
{/* Use the actual jogpad.svg from mockup */}
<img
src="/icons/jogpad.svg"
alt="Jog Pad"
className="w-full h-full jogpad-theme"
/>
{/* Invisible clickable areas overlaid on the SVG */}
{/* Outer ring - 10mm moves */}
<button
onClick={() => handleMove('Y', 10)}
disabled={isDisabled}
className="absolute top-[8px] left-1/2 -translate-x-1/2 w-[40px] h-[30px] opacity-0 hover:opacity-10 hover:bg-white disabled:cursor-not-allowed"
title="Y+10"
/>
<button
onClick={() => handleMove('Y', -10)}
disabled={isDisabled}
className="absolute bottom-[8px] left-1/2 -translate-x-1/2 w-[40px] h-[30px] opacity-0 hover:opacity-10 hover:bg-white disabled:cursor-not-allowed"
title="Y-10"
/>
<button
onClick={() => handleMove('X', -10)}
disabled={isDisabled}
className="absolute left-[8px] top-1/2 -translate-y-1/2 w-[30px] h-[40px] opacity-0 hover:opacity-10 hover:bg-white disabled:cursor-not-allowed"
title="X-10"
/>
<button
onClick={() => handleMove('X', 10)}
disabled={isDisabled}
className="absolute right-[8px] top-1/2 -translate-y-1/2 w-[30px] h-[40px] opacity-0 hover:opacity-10 hover:bg-white disabled:cursor-not-allowed"
title="X+10"
/>
{/* Inner ring - 1mm moves */}
<button
onClick={() => handleMove('Y', 1)}
disabled={isDisabled}
className="absolute top-[42px] left-1/2 -translate-x-1/2 w-[35px] h-[25px] opacity-0 hover:opacity-10 hover:bg-white disabled:cursor-not-allowed"
title="Y+1"
/>
<button
onClick={() => handleMove('Y', -1)}
disabled={isDisabled}
className="absolute bottom-[42px] left-1/2 -translate-x-1/2 w-[35px] h-[25px] opacity-0 hover:opacity-10 hover:bg-white disabled:cursor-not-allowed"
title="Y-1"
/>
<button
onClick={() => handleMove('X', -1)}
disabled={isDisabled}
className="absolute left-[42px] top-1/2 -translate-y-1/2 w-[25px] h-[35px] opacity-0 hover:opacity-10 hover:bg-white disabled:cursor-not-allowed"
title="X-1"
/>
<button
onClick={() => handleMove('X', 1)}
disabled={isDisabled}
className="absolute right-[42px] top-1/2 -translate-y-1/2 w-[25px] h-[35px] opacity-0 hover:opacity-10 hover:bg-white disabled:cursor-not-allowed"
title="X+1"
/>
{/* Home button in center - clickable overlay */}
<button
onClick={handleHome}
disabled={isDisabled}
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[50px] h-[50px] rounded-full opacity-0 hover:opacity-10 hover:bg-white disabled:cursor-not-allowed"
title="Home XY"
/>
</div>
{/* Confirmation Modal */}
{confirmModal && (
<ConfirmModal
title="Confirm Action"
message={confirmModal.warning}
confirmText="Continue"
variant="warning"
onConfirm={handleConfirm}
onCancel={() => setConfirmModal(null)}
/>
)}
</>
);
}
@@ -66,7 +66,7 @@ export function PrintControls({ printerId, status }: PrintControlsProps) {
return (
<>
<div className="bg-bambu-dark-secondary rounded-lg p-4">
<div>
<h3 className="text-sm font-medium text-bambu-gray mb-3">Print Controls</h3>
<div className="flex gap-2">
+172 -72
View File
@@ -1,90 +1,190 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import type { PrinterStatus } from '../../api/client';
import { Clock, Layers, FileText } from 'lucide-react';
import { api, isConfirmationRequired } from '../../api/client';
import { Pause, Square, Loader2 } from 'lucide-react';
import { ConfirmModal } from '../ConfirmModal';
interface PrintStatusProps {
printerId: number;
status: PrinterStatus | null | undefined;
}
function formatTime(seconds: number | null | undefined): string {
if (!seconds) return '--:--';
const hours = Math.floor(seconds / 3600);
const mins = Math.floor((seconds % 3600) / 60);
if (hours > 0) {
return `${hours}h ${mins}m`;
}
return `${mins}m`;
function formatFinishTime(seconds: number | null | undefined): string {
if (!seconds) return 'N/A';
const now = new Date();
const finish = new Date(now.getTime() + seconds * 1000);
return finish.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}
export function PrintStatus({ status }: PrintStatusProps) {
const isPrinting = status?.state === 'RUNNING' || status?.state === 'PAUSE';
export function PrintStatus({ printerId, status }: PrintStatusProps) {
const queryClient = useQueryClient();
const [confirmModal, setConfirmModal] = useState<{
action: string;
token: string;
warning: string;
} | null>(null);
const isConnected = status?.connected ?? false;
const isPrinting = status?.state === 'RUNNING';
const isPaused = status?.state === 'PAUSE';
const progress = status?.progress ?? 0;
const pauseMutation = useMutation({
mutationFn: () => api.pausePrint(printerId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['printerStatuses'] });
},
});
const resumeMutation = useMutation({
mutationFn: () => api.resumePrint(printerId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['printerStatuses'] });
},
});
const stopMutation = useMutation({
mutationFn: (token?: string) => api.stopPrint(printerId, token),
onSuccess: (result) => {
if (isConfirmationRequired(result)) {
setConfirmModal({
action: 'stop',
token: result.token,
warning: result.warning,
});
} else {
queryClient.invalidateQueries({ queryKey: ['printerStatuses'] });
}
},
});
const handlePauseResume = () => {
if (isPrinting) {
pauseMutation.mutate();
} else if (isPaused) {
resumeMutation.mutate();
}
};
const handleStop = () => {
stopMutation.mutate(undefined);
};
const handleConfirmStop = () => {
if (confirmModal) {
stopMutation.mutate(confirmModal.token);
setConfirmModal(null);
}
};
const isLoading = pauseMutation.isPending || resumeMutation.isPending || stopMutation.isPending;
const canControl = isConnected && (isPrinting || isPaused);
return (
<div className="bg-bambu-dark-secondary rounded-lg p-4">
<div className="flex items-center justify-between mb-3">
<h3 className="text-sm font-medium text-bambu-gray">Print Status</h3>
<span
className={`px-2 py-0.5 rounded text-xs font-medium ${
status?.state === 'RUNNING'
? 'bg-bambu-green/20 text-bambu-green'
: status?.state === 'PAUSE'
? 'bg-yellow-500/20 text-yellow-500'
: status?.state === 'FINISH'
? 'bg-blue-500/20 text-blue-500'
: status?.state === 'FAILED'
? 'bg-red-500/20 text-red-500'
: 'bg-bambu-dark-tertiary text-bambu-gray'
}`}
>
{status?.state || 'IDLE'}
</span>
<>
<div className="text-xs text-bambu-gray mb-3">Printing Progress</div>
<div className="flex gap-4 items-center">
{/* Thumbnail */}
<div className="w-20 h-20 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg flex items-center justify-center flex-shrink-0 overflow-hidden">
{status?.subtask_name ? (
<img
src={`/api/v1/archives/thumbnail/${encodeURIComponent(status.subtask_name)}`}
alt=""
className="w-full h-full object-contain"
onError={(e) => {
(e.target as HTMLImageElement).style.display = 'none';
(e.target as HTMLImageElement).parentElement!.innerHTML = '<span class="text-xs text-bambu-gray">Bambu<br/>Lab</span>';
}}
/>
) : (
<span className="text-xs text-bambu-gray text-center">Bambu<br/>Lab</span>
)}
</div>
{/* Info */}
<div className="flex-1 min-w-0">
<div className="font-medium text-sm text-white truncate mb-0.5">
{status?.subtask_name || 'N/A'}
</div>
<div className={`text-sm mb-2 ${
status?.state === 'RUNNING' || status?.state === 'PAUSE'
? 'text-bambu-green'
: 'text-bambu-gray'
}`}>
{status?.state || 'N/A'}
</div>
{/* Progress Bar */}
<div className="h-1 bg-bambu-dark-tertiary rounded-full overflow-hidden mb-2">
<div
className={`h-full transition-all duration-300 ${
status?.state === 'PAUSE' ? 'bg-yellow-500' : 'bg-bambu-green'
}`}
style={{ width: `${progress}%` }}
/>
</div>
<div className="text-xs text-bambu-gray mb-1">
Layer: {status?.layer_num ?? 'N/A'} / {status?.total_layers ?? 'N/A'} &nbsp;&nbsp; {Math.round(progress)}%
</div>
<div className="text-xs text-bambu-gray">
Estimated finish time: {formatFinishTime(status?.remaining_time)}
</div>
</div>
{/* Control Buttons */}
<div className="flex gap-1.5 flex-shrink-0">
<button
onClick={handlePauseResume}
disabled={!canControl || isLoading}
className="w-8 h-8 rounded-md border border-bambu-dark-tertiary bg-bambu-dark-secondary hover:bg-bambu-dark-tertiary flex items-center justify-center text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
title={isPrinting ? 'Pause' : 'Resume'}
>
{pauseMutation.isPending || resumeMutation.isPending ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
<Pause className="w-4 h-4" />
)}
</button>
<button
onClick={handleStop}
disabled={!canControl || isLoading}
className="w-8 h-8 rounded-md border border-bambu-dark-tertiary bg-bambu-dark-secondary hover:bg-bambu-dark-tertiary flex items-center justify-center text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
title="Stop"
>
{stopMutation.isPending ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
<Square className="w-4 h-4" />
)}
</button>
<button
disabled={!canControl || isLoading}
className="w-8 h-8 rounded-md border border-bambu-dark-tertiary bg-bambu-dark-secondary hover:bg-bambu-dark-tertiary flex items-center justify-center text-bambu-gray disabled:opacity-50 disabled:cursor-not-allowed"
title="Skip Objects"
>
<img src="/icons/skip-objects.svg" alt="Skip Objects" className="w-4 h-4 icon-theme" />
</button>
</div>
</div>
{isPrinting && status?.subtask_name && (
<div className="flex items-center gap-2 mb-3 text-sm">
<FileText className="w-4 h-4 text-bambu-gray" />
<span className="truncate" title={status.subtask_name}>
{status.subtask_name}
</span>
</div>
{/* Error Message */}
{(pauseMutation.error || resumeMutation.error || stopMutation.error) && (
<p className="mt-2 text-xs text-red-500">
{(pauseMutation.error || resumeMutation.error || stopMutation.error)?.message}
</p>
)}
{/* Progress Bar */}
<div className="mb-3">
<div className="flex justify-between text-xs text-bambu-gray mb-1">
<span>Progress</span>
<span>{Math.round(progress)}%</span>
</div>
<div className="h-2 bg-bambu-dark-tertiary rounded-full overflow-hidden">
<div
className={`h-full transition-all duration-300 ${
status?.state === 'PAUSE' ? 'bg-yellow-500' : 'bg-bambu-green'
}`}
style={{ width: `${progress}%` }}
/>
</div>
</div>
{/* Stats */}
<div className="grid grid-cols-2 gap-3 text-sm">
<div className="flex items-center gap-2">
<Clock className="w-4 h-4 text-bambu-gray" />
<div>
<div className="text-xs text-bambu-gray">Remaining</div>
<div className="font-medium">{formatTime(status?.remaining_time)}</div>
</div>
</div>
<div className="flex items-center gap-2">
<Layers className="w-4 h-4 text-bambu-gray" />
<div>
<div className="text-xs text-bambu-gray">Layer</div>
<div className="font-medium">
{status?.layer_num ?? 0} / {status?.total_layers ?? 0}
</div>
</div>
</div>
</div>
</div>
{/* Confirmation Modal */}
{confirmModal && (
<ConfirmModal
title="Confirm Stop"
message={confirmModal.warning}
confirmText="Stop Print"
variant="danger"
onConfirm={handleConfirmStop}
onCancel={() => setConfirmModal(null)}
/>
)}
</>
);
}
@@ -0,0 +1,93 @@
import type { PrinterStatus } from '../../api/client';
interface Temperatures {
bed?: number;
bed_target?: number;
nozzle?: number;
nozzle_target?: number;
nozzle_2?: number;
nozzle_2_target?: number;
chamber?: number;
}
interface TemperatureColumnProps {
printerId?: number;
status: PrinterStatus | null | undefined;
nozzleCount: number;
}
export function TemperatureColumn({ status, nozzleCount }: TemperatureColumnProps) {
const temps = (status?.temperatures ?? {}) as Temperatures;
const isDualNozzle = nozzleCount > 1;
return (
<div className="flex flex-col justify-evenly min-w-[150px] pr-5 border-r border-bambu-dark-tertiary">
{/* Nozzle 1 (Left) */}
<div className="flex items-center gap-1.5">
<div className="w-5 h-5 flex items-center justify-center flex-shrink-0">
<img src="/icons/hotend.svg" alt="" className="w-5 icon-theme" />
</div>
{isDualNozzle && (
<span className="text-[11px] font-semibold text-bambu-green bg-bambu-green/20 px-1.5 py-0.5 rounded min-w-[18px] text-center flex-shrink-0">
L
</span>
)}
<span className="text-lg font-medium text-white">{Math.round(temps.nozzle ?? 0)}</span>
<span className="text-sm text-bambu-gray">/{Math.round(temps.nozzle_target ?? 0)} °C</span>
</div>
{/* Nozzle 2 (Right) - only for dual nozzle */}
{isDualNozzle && (
<div className="flex items-center gap-1.5">
<div className="w-5 h-5 flex items-center justify-center flex-shrink-0">
<img src="/icons/hotend.svg" alt="" className="w-5 icon-theme" />
</div>
<span className="text-[11px] font-semibold text-bambu-green bg-bambu-green/20 px-1.5 py-0.5 rounded min-w-[18px] text-center flex-shrink-0">
R
</span>
<span className="text-lg font-medium text-white">{Math.round(temps.nozzle_2 ?? 0)}</span>
<span className="text-sm text-bambu-gray">/{Math.round(temps.nozzle_2_target ?? 0)} °C</span>
</div>
)}
{/* Bed */}
<div className="flex items-center gap-1.5">
<div className="w-5 h-5 flex items-center justify-center flex-shrink-0">
<img src="/icons/heatbed.svg" alt="" className="w-5 icon-theme" />
</div>
{/* Spacer to align with L/R badge (min-w-[18px]) */}
{isDualNozzle && <span className="min-w-[18px] flex-shrink-0" />}
<span className="text-lg font-medium text-white">{Math.round(temps.bed ?? 0)}</span>
<span className="text-sm text-bambu-gray">/{Math.round(temps.bed_target ?? 0)} °C</span>
</div>
{/* Chamber */}
<div className="flex items-center gap-1.5">
<div className="w-5 h-5 flex items-center justify-center flex-shrink-0">
<img src="/icons/chamber.svg" alt="" className="w-5 icon-theme" />
</div>
{/* Spacer to align with L/R badge */}
{isDualNozzle && <span className="min-w-[18px] flex-shrink-0" />}
<span className="text-lg font-medium text-white">{Math.round(temps.chamber ?? 0)}</span>
<span className="text-sm text-bambu-gray">/{0} °C</span>
</div>
{/* Air Condition - button */}
<button className="flex items-center gap-2 hover:opacity-80 transition-opacity">
<div className="w-5 h-5 flex items-center justify-center flex-shrink-0">
<img src="/icons/ventilation.svg" alt="" className="w-5 icon-theme" />
</div>
<span className="text-sm text-bambu-gray">Air Condition</span>
</button>
{/* Lamp - button */}
<button className="flex items-center gap-2 hover:opacity-80 transition-opacity">
<div className="w-5 h-5 flex items-center justify-center flex-shrink-0">
<img src="/icons/ventilation.svg" alt="" className="w-4 icon-theme" />
</div>
<span className="text-sm text-bambu-gray">Lamp</span>
<div className="w-3.5 h-3.5 rounded-full bg-bambu-green" />
</button>
</div>
);
}
+22 -1
View File
@@ -1,7 +1,9 @@
@import "tailwindcss";
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
/* Enable class-based dark mode for Tailwind v4 */
@custom-variant dark (&:where(.dark, .dark *));
@theme {
/* Bambu Lab brand colors - always the same */
--color-bambu-green: #00ae42;
@@ -89,3 +91,22 @@ body {
.animate-slide-in {
animation: slide-in 0.2s ease-out;
}
/* Theme-aware icon inversion - only invert in dark mode */
.icon-theme {
opacity: 0.5;
}
.dark .icon-theme {
filter: invert(1);
opacity: 0.4;
}
/* Jogpad theme styling - darken background in dark mode */
.jogpad-theme {
/* Light mode - normal */
}
.dark .jogpad-theme {
filter: brightness(0.7) contrast(1.1);
}
+101 -67
View File
@@ -5,14 +5,12 @@ import { api } from '../api/client';
import type { PrinterStatus } from '../api/client';
import { CameraFeed } from '../components/control/CameraFeed';
import { PrintStatus } from '../components/control/PrintStatus';
import { PrintControls } from '../components/control/PrintControls';
import { TemperaturePanel } from '../components/control/TemperaturePanel';
import { SpeedControl } from '../components/control/SpeedControl';
import { FanControls } from '../components/control/FanControls';
import { LightToggle } from '../components/control/LightToggle';
import { MovementControls } from '../components/control/MovementControls';
import { AMSPanel } from '../components/control/AMSPanel';
import { Loader2, WifiOff } from 'lucide-react';
import { TemperatureColumn } from '../components/control/TemperatureColumn';
import { JogPad } from '../components/control/JogPad';
import { BedControls } from '../components/control/BedControls';
import { ExtruderControls } from '../components/control/ExtruderControls';
import { AMSSectionDual } from '../components/control/AMSSectionDual';
import { Loader2, WifiOff, Video, Webcam, HardDrive, Settings } from 'lucide-react';
export function ControlPage() {
const [searchParams, setSearchParams] = useSearchParams();
@@ -89,7 +87,7 @@ export function ControlPage() {
}
return (
<div className="h-screen flex flex-col">
<div className="h-screen flex flex-col bg-bambu-dark">
{/* Printer Tabs */}
<div className="bg-bambu-dark-secondary border-b border-bambu-dark-tertiary">
<div className="flex overflow-x-auto">
@@ -125,79 +123,115 @@ export function ControlPage() {
</div>
</div>
{/* Main Content */}
{/* Main Content - Bambu Studio Layout */}
{selectedPrinter && (
<div className="flex-1 overflow-auto p-4">
<div className="max-w-7xl mx-auto">
<div className="flex-1 flex overflow-hidden">
{/* Left Panel - Camera & Print Progress */}
<div className="flex-1 flex flex-col bg-bambu-dark">
{/* Camera Header Icons - same height as Control header */}
<div className="flex items-center justify-end gap-2 px-3 py-2.5 bg-bambu-dark-secondary border-b border-bambu-dark-tertiary min-h-[44px]">
<button className="p-1.5 rounded hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white">
<HardDrive className="w-4 h-4" />
</button>
<button className="p-1.5 rounded hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white">
<Video className="w-4 h-4" />
</button>
<button className="p-1.5 rounded hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white">
<Webcam className="w-4 h-4" />
</button>
<button className="p-1.5 rounded hover:bg-bambu-dark-tertiary text-bambu-gray hover:text-white">
<Settings className="w-4 h-4" />
</button>
</div>
{/* Camera Feed - Embedded directly */}
<div className="flex-1 bg-black">
<CameraFeed
printerId={selectedPrinter.id}
isConnected={selectedStatus?.connected ?? false}
/>
</div>
{/* Status Bar */}
<div className="h-1 bg-bambu-green" />
{/* Print Progress with integrated controls */}
<div className="bg-bambu-dark-secondary p-4 px-5">
<PrintStatus
printerId={selectedPrinter.id}
status={selectedStatus}
/>
</div>
</div>
{/* Right Panel - Control */}
<div className="w-[620px] flex flex-col bg-bambu-dark-secondary border-l border-bambu-dark-tertiary overflow-y-auto">
{/* Control Header - same height as Camera header */}
<div className="flex items-center justify-between px-3 py-2.5 border-b border-bambu-dark-tertiary min-h-[44px]">
<span className="text-sm text-bambu-gray">Control</span>
<div className="flex gap-2">
<button className="px-4 py-1.5 text-xs rounded bg-bambu-green text-white hover:bg-bambu-green-dark">
Printer Parts
</button>
<button className="px-4 py-1.5 text-xs rounded bg-bambu-green text-white hover:bg-bambu-green-dark">
Print Options
</button>
<button className="px-4 py-1.5 text-xs rounded bg-bambu-green text-white hover:bg-bambu-green-dark">
Calibration
</button>
</div>
</div>
{/* Connection Warning */}
{!selectedStatus?.connected && (
<div className="mb-4 p-4 bg-red-500/20 border border-red-500/50 rounded-lg flex items-center gap-3">
<WifiOff className="w-5 h-5 text-red-500" />
<span className="text-red-400">
<div className="m-3 p-3 bg-red-500/20 border border-red-500/50 rounded-lg flex items-center gap-3">
<WifiOff className="w-4 h-4 text-red-500" />
<span className="text-sm text-red-400">
Printer is not connected. Controls are disabled.
</span>
</div>
)}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{/* Left Column: Camera + Print Status */}
<div className="space-y-4">
{/* Camera Feed */}
<CameraFeed
printerId={selectedPrinter.id}
isConnected={selectedStatus?.connected ?? false}
/>
{/* Print Status & Controls */}
<PrintStatus
printerId={selectedPrinter.id}
status={selectedStatus}
/>
<PrintControls
printerId={selectedPrinter.id}
status={selectedStatus}
/>
{/* AMS Panel */}
<AMSPanel
printerId={selectedPrinter.id}
status={selectedStatus}
/>
</div>
{/* Right Column: Controls */}
<div className="space-y-4">
{/* Temperature Panel */}
<TemperaturePanel
{/* Control Body */}
<div className="flex-1 p-4 bg-bambu-dark">
{/* Top Section: Temp + Movement + Extruder */}
<div className="flex gap-6 mb-4" style={{ minHeight: '300px' }}>
{/* Temperature Column */}
<TemperatureColumn
printerId={selectedPrinter.id}
status={selectedStatus}
nozzleCount={selectedPrinter.nozzle_count}
/>
{/* Speed Control */}
<SpeedControl
printerId={selectedPrinter.id}
status={selectedStatus}
/>
{/* Movement Column */}
<div className="flex-1 flex gap-6 items-center justify-center">
{/* Jog Section */}
<div className="flex flex-col items-center">
<JogPad
printerId={selectedPrinter.id}
status={selectedStatus}
/>
<BedControls
printerId={selectedPrinter.id}
status={selectedStatus}
/>
</div>
{/* Fan Controls */}
<FanControls
printerId={selectedPrinter.id}
status={selectedStatus}
/>
{/* Light Toggle */}
<LightToggle
printerId={selectedPrinter.id}
status={selectedStatus}
/>
{/* Movement Controls */}
<MovementControls
printerId={selectedPrinter.id}
status={selectedStatus}
/>
{/* Extruder Section */}
<ExtruderControls
printerId={selectedPrinter.id}
status={selectedStatus}
nozzleCount={selectedPrinter.nozzle_count}
/>
</div>
</div>
{/* AMS Section */}
<AMSSectionDual
printerId={selectedPrinter.id}
status={selectedStatus}
nozzleCount={selectedPrinter.nozzle_count}
/>
</div>
</div>
</div>
+1
View File
@@ -1,5 +1,6 @@
/** @type {import('tailwindcss').Config} */
export default {
darkMode: 'class',
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg fill="none" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><g clip-rule="evenodd" fill="#000" fill-rule="evenodd"><path d="m2.25 6c0-.41421.33579-.75.75-.75h3.5c.41421 0 .75.33579.75.75s-.33579.75-.75.75h-3.5c-.41421 0-.75-.33579-.75-.75zm8.5 0c0-.41421.3358-.75.75-.75h9.5c.4142 0 .75.33579.75.75s-.3358.75-.75.75h-9.5c-.4142 0-.75-.33579-.75-.75z"/><path d="m9 4.25c-.9665 0-1.75.7835-1.75 1.75s.7835 1.75 1.75 1.75 1.75-.7835 1.75-1.75-.7835-1.75-1.75-1.75zm-3.25 1.75c0-1.79493 1.45507-3.25 3.25-3.25 1.7949 0 3.25 1.45507 3.25 3.25s-1.4551 3.25-3.25 3.25c-1.79493 0-3.25-1.45507-3.25-3.25z"/><path d="m21.75 12c0-.4142-.3358-.75-.75-.75h-2c-.4142 0-.75.3358-.75.75s.3358.75.75.75h2c.4142 0 .75-.3358.75-.75zm-7 0c0-.4142-.3358-.75-.75-.75h-5c-.41421 0-.75.3358-.75.75s.33579.75.75.75h5c.4142 0 .75-.3358.75-.75zm-9 0c0-.4142-.33579-.75-.75-.75h-2c-.41421 0-.75.3358-.75.75s.33579.75.75.75h2c.41421 0 .75-.3358.75-.75z"/><path d="m16.5 10.25c.9665 0 1.75.7835 1.75 1.75s-.7835 1.75-1.75 1.75-1.75-.7835-1.75-1.75.7835-1.75 1.75-1.75zm3.25 1.75c0-1.7949-1.4551-3.25-3.25-3.25s-3.25 1.4551-3.25 3.25 1.4551 3.25 3.25 3.25 3.25-1.4551 3.25-3.25z"/><path d="m2.25 18c0-.4142.33579-.75.75-.75h5c.41421 0 .75.3358.75.75s-.33579.75-.75.75h-5c-.41421 0-.75-.3358-.75-.75zm10 0c0-.4142.3358-.75.75-.75h8c.4142 0 .75.3358.75.75s-.3358.75-.75.75h-8c-.4142 0-.75-.3358-.75-.75z"/><path d="m10.5 16.25c-.9665 0-1.75.7835-1.75 1.75s.7835 1.75 1.75 1.75 1.75-.7835 1.75-1.75-.7835-1.75-1.75-1.75zm-3.25 1.75c0-1.7949 1.45507-3.25 3.25-3.25 1.7949 0 3.25 1.4551 3.25 3.25s-1.4551 3.25-3.25 3.25c-1.79493 0-3.25-1.4551-3.25-3.25z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 50">
<!-- Left wire: horizontal from left edge, then down to extruder left inlet -->
<line x1="0" y1="0" x2="10" y2="0" stroke="#909090" stroke-width="2" />
<line x1="10" y1="0" x2="10" y2="50" stroke="#909090" stroke-width="2" />
<!-- Right wire: horizontal from right edge, then down to extruder right inlet -->
<line x1="40" y1="0" x2="30" y2="0" stroke="#909090" stroke-width="2" />
<line x1="30" y1="0" x2="30" y2="50" stroke="#909090" stroke-width="2" />
</svg>

After

Width:  |  Height:  |  Size: 537 B

+17
View File
@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 50">
<!-- Vertical lines from slots down to horizontal bar -->
<line x1="28" y1="0" x2="28" y2="14" stroke="#909090" stroke-width="2" />
<line x1="82" y1="0" x2="82" y2="14" stroke="#909090" stroke-width="2" />
<line x1="138" y1="0" x2="138" y2="14" stroke="#909090" stroke-width="2" />
<line x1="192" y1="0" x2="192" y2="14" stroke="#909090" stroke-width="2" />
<!-- Horizontal bar across all slots -->
<line x1="28" y1="14" x2="192" y2="14" stroke="#909090" stroke-width="2" />
<!-- Center hub box -->
<rect x="96" y="8" width="28" height="12" rx="2" fill="#c0c0c0" stroke="#909090" stroke-width="1" />
<!-- Wire from hub: down, then right to edge (at same level as hub horizontal bar) -->
<line x1="110" y1="20" x2="110" y2="35" stroke="#909090" stroke-width="2" />
<line x1="110" y1="35" x2="220" y2="35" stroke="#909090" stroke-width="2" />
</svg>

After

Width:  |  Height:  |  Size: 937 B

+17
View File
@@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 220 50">
<!-- Vertical lines from slots down to horizontal bar -->
<line x1="28" y1="0" x2="28" y2="14" stroke="#909090" stroke-width="2" />
<line x1="82" y1="0" x2="82" y2="14" stroke="#909090" stroke-width="2" />
<line x1="138" y1="0" x2="138" y2="14" stroke="#909090" stroke-width="2" />
<line x1="192" y1="0" x2="192" y2="14" stroke="#909090" stroke-width="2" />
<!-- Horizontal bar across all slots -->
<line x1="28" y1="14" x2="192" y2="14" stroke="#909090" stroke-width="2" />
<!-- Center hub box -->
<rect x="96" y="8" width="28" height="12" rx="2" fill="#c0c0c0" stroke="#909090" stroke-width="1" />
<!-- Wire from hub: down, then left to edge (at same level as hub horizontal bar) -->
<line x1="110" y1="20" x2="110" y2="35" stroke="#909090" stroke-width="2" />
<line x1="0" y1="35" x2="110" y2="35" stroke="#909090" stroke-width="2" />
</svg>

After

Width:  |  Height:  |  Size: 934 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Capa_1" enable-background="new 0 0 512 512" height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><g><g><path d="m422.995 217.87c4.143 0 7.5-3.357 7.5-7.5v-192.87c0-9.649-7.851-17.5-17.5-17.5h-313.99c-9.649 0-17.5 7.851-17.5 17.5v477c0 9.649 7.851 17.5 17.5 17.5h313.99c9.649 0 17.5-7.851 17.5-17.5v-248.203c0-4.143-3.357-7.5-7.5-7.5s-7.5 3.357-7.5 7.5v52.811h-16.639v-117.615h16.639v28.877c0 4.143 3.358 7.5 7.5 7.5zm-294.851-144.77h33.028c4.143 0 7.5-3.357 7.5-7.5s-3.357-7.5-7.5-7.5h-33.028v-43.1h255.713v43.1h-186.759c-4.143 0-7.5 3.357-7.5 7.5s3.357 7.5 7.5 7.5h186.759v22.158h-255.713zm-29.139-58.1h14.139v151.493h-16.639v-148.993c0-1.379 1.121-2.5 2.5-2.5zm-2.5 447v-15.278h16.639v15.278zm0-280.507h16.639v117.614h-16.639zm316.49 315.507h-313.99c-1.379 0-2.5-1.121-2.5-2.5v-17.5h318.99v17.5c0 1.379-1.121 2.5-2.5 2.5zm2.5-35h-16.639v-15.278h16.639zm0-147.893v117.614h-16.639v-117.614zm-31.639-15h-3.586c-4.143 0-7.5 3.357-7.5 7.5s3.357 7.5 7.5 7.5h3.586v117.614h-3.586c-4.143 0-7.5 3.357-7.5 7.5s3.357 7.5 7.5 7.5h3.586v15.279h-255.712v-15.278h3.586c4.143 0 7.5-3.357 7.5-7.5s-3.357-7.5-7.5-7.5h-3.586v-53.092c0-4.143-3.357-7.5-7.5-7.5s-7.5 3.357-7.5 7.5v53.092h-16.639v-117.615h16.639v28.596c0 4.143 3.357 7.5 7.5 7.5s7.5-3.357 7.5-7.5v-28.596h3.586c4.143 0 7.5-3.357 7.5-7.5s-3.357-7.5-7.5-7.5h-3.586v-117.614h3.586c4.143 0 7.5-3.357 7.5-7.5s-3.357-7.5-7.5-7.5h-3.586v-56.235h255.713v56.235h-3.586c-4.143 0-7.5 3.357-7.5 7.5s3.357 7.5 7.5 7.5h3.586v117.614zm15-132.614v-151.493h14.139c1.379 0 2.5 1.121 2.5 2.5v148.993z"/><path d="m256 129.22c-17.53 0-31.793 14.263-31.793 31.794 0 17.53 14.263 31.793 31.793 31.793s31.793-14.263 31.793-31.793c0-17.532-14.263-31.794-31.793-31.794zm0 48.587c-9.26 0-16.793-7.533-16.793-16.793s7.533-16.794 16.793-16.794 16.793 7.534 16.793 16.794-7.533 16.793-16.793 16.793z"/><path d="m201.313 419.229c-1.407-1.406-3.314-2.196-5.304-2.196s-3.897.79-5.304 2.197l-10.465 10.466c-2.929 2.929-2.929 7.678.001 10.606 1.464 1.464 3.384 2.196 5.303 2.196s3.839-.732 5.304-2.197l5.161-5.162 5.162 5.163c2.93 2.928 7.678 2.928 10.607 0 2.929-2.93 2.929-7.678 0-10.607z"/><path d="m261.304 419.23c-1.406-1.407-3.314-2.197-5.304-2.197s-3.897.79-5.304 2.197l-10.465 10.466c-2.929 2.929-2.929 7.678.001 10.606 2.928 2.928 7.677 2.929 10.606-.001l5.161-5.161 5.161 5.161c1.465 1.465 3.384 2.197 5.304 2.197 1.919 0 3.839-.732 5.303-2.196 2.93-2.929 2.93-7.678.001-10.606z"/><path d="m321.295 419.23c-1.406-1.407-3.314-2.197-5.304-2.197s-3.896.79-5.304 2.196l-10.466 10.466c-2.929 2.93-2.929 7.678 0 10.607 2.93 2.928 7.678 2.928 10.607 0l5.162-5.163 5.161 5.162c1.465 1.465 3.384 2.197 5.304 2.197 1.919 0 3.839-.732 5.303-2.196 2.93-2.929 2.93-7.678.001-10.606z"/><path d="m213.252 44.05h85.496c4.143 0 7.5-3.357 7.5-7.5s-3.357-7.5-7.5-7.5h-85.496c-4.143 0-7.5 3.357-7.5 7.5s3.357 7.5 7.5 7.5z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

+51
View File
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 511.999 511.999" style="enable-background:new 0 0 511.999 511.999;" xml:space="preserve">
<g>
<g>
<path d="M508.745,246.041c-4.574-6.257-113.557-153.206-252.748-153.206S7.818,239.784,3.249,246.035
c-4.332,5.936-4.332,13.987,0,19.923c4.569,6.257,113.557,153.206,252.748,153.206s248.174-146.95,252.748-153.201
C513.083,260.028,513.083,251.971,508.745,246.041z M255.997,385.406c-102.529,0-191.33-97.533-217.617-129.418
c26.253-31.913,114.868-129.395,217.617-129.395c102.524,0,191.319,97.516,217.617,129.418
C447.361,287.923,358.746,385.406,255.997,385.406z"/>
</g>
</g>
<g>
<g>
<path d="M255.997,154.725c-55.842,0-101.275,45.433-101.275,101.275s45.433,101.275,101.275,101.275
s101.275-45.433,101.275-101.275S311.839,154.725,255.997,154.725z M255.997,323.516c-37.23,0-67.516-30.287-67.516-67.516
s30.287-67.516,67.516-67.516s67.516,30.287,67.516,67.516S293.227,323.516,255.997,323.516z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"><g fill="rgb(0,0,0)"><path d="m6.3 3.9c.54-.4 1.2-.9 1.2-1.9 0-.28-.22-.5-.5-.5s-.5.22-.5.5c0 .48-.29.71-.8 1.1-.53.4-1.2.9-1.2 1.9s.67 1.5 1.2 1.9c.51.38.8.62.8 1.1s-.29.72-.8 1.1c-.54.4-1.2.9-1.2 1.9 0 .28.22.5.5.5s.5-.22.5-.5c0-.48.29-.72.8-1.1.54-.4 1.2-.9 1.2-1.9s-.67-1.5-1.2-1.9c-.51-.38-.8-.62-.8-1.1s.29-.72.8-1.1z"/><path d="m12.3 3.9c.54-.4 1.2-.9 1.2-1.9 0-.28-.22-.5-.5-.5s-.5.22-.5.5c0 .48-.29.71-.8 1.1-.53.4-1.2.9-1.2 1.9s.67 1.5 1.2 1.9c.51.38.8.62.8 1.1s-.29.72-.8 1.1c-.54.4-1.2.9-1.2 1.9 0 .28.22.5.5.5s.5-.22.5-.5c0-.48.29-.72.8-1.1.54-.4 1.2-.9 1.2-1.9s-.67-1.5-1.2-1.9c-.51-.38-.8-.62-.8-1.1s.29-.72.8-1.1z"/><path d="m18.3 3.9c.54-.4 1.2-.9 1.2-1.9 0-.28-.22-.5-.5-.5s-.5.22-.5.5c0 .48-.29.71-.8 1.1-.53.4-1.2.9-1.2 1.9s.67 1.5 1.2 1.9c.51.38.8.62.8 1.1s-.29.72-.8 1.1c-.54.4-1.2.9-1.2 1.9 0 .28.22.5.5.5s.5-.22.5-.5c0-.48.29-.72.8-1.1.54-.4 1.2-.9 1.2-1.9s-.67-1.5-1.2-1.9c-.51-.38-.8-.62-.8-1.1s.29-.72.8-1.1z"/><path d="m22 13.5c-1.07 0-1.61.65-2.05 1.18-.44.52-.71.82-1.29.82s-.85-.3-1.29-.82c-.44-.53-.98-1.18-2.05-1.18s-1.61.65-2.05 1.18c-.44.52-.71.82-1.28.82s-.85-.3-1.28-.82c-.44-.53-.98-1.18-2.05-1.18s-1.61.65-2.05 1.18c-.44.52-.71.82-1.28.82s-.84-.3-1.28-.82c-.44-.53-.98-1.18-2.05-1.18-.28 0-.5.22-.5.5s.22.5.5.5c.57 0 .84.3 1.28.82.44.53.98 1.18 2.05 1.18s1.61-.65 2.05-1.18c.44-.52.71-.82 1.28-.82s.85.3 1.28.82c.44.53.98 1.18 2.05 1.18s1.61-.65 2.05-1.18c.44-.52.71-.82 1.28-.82s.85.3 1.29.82c.44.53.98 1.18 2.05 1.18s1.61-.65 2.05-1.18c.44-.52.71-.82 1.29-.82.28 0 .5-.22.5-.5s-.22-.5-.5-.5z"/><path d="m21 18.5h-18c-.83 0-1.5.67-1.5 1.5v1c0 .83.67 1.5 1.5 1.5h18c.83 0 1.5-.67 1.5-1.5v-1c0-.83-.67-1.5-1.5-1.5zm.5 2.5c0 .28-.22.5-.5.5h-18c-.28 0-.5-.22-.5-.5v-1c0-.28.22-.5.5-.5h18c.28 0 .5.22.5.5z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

+44
View File
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 476.912 476.912" style="enable-background:new 0 0 476.912 476.912;" xml:space="preserve">
<g>
<g>
<path d="M461.776,209.408L249.568,4.52c-6.182-6.026-16.042-6.026-22.224,0L15.144,209.4c-3.124,3.015-4.888,7.17-4.888,11.512
c0,8.837,7.164,16,16,16h28.2v224c0,8.837,7.163,16,16,16h112c8.837,0,16-7.163,16-16v-128h80v128c0,8.837,7.163,16,16,16h112
c8.837,0,16-7.163,16-16v-224h28.2c4.338,0,8.489-1.761,11.504-4.88C468.301,225.678,468.129,215.549,461.776,209.408z
M422.456,220.912c-8.837,0-16,7.163-16,16v224h-112v-128c0-8.837-7.163-16-16-16h-80c-8.837,0-16,7.163-16,16v128h-112v-224
c0-8.837-7.163-16-16-16h-28.2l212.2-204.88l212.28,204.88H422.456z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg"><g id="Front_Heater" data-name="Front Heater"><path d="m33.14 29h2.86l-4-7-4 7h3l1.5 3.7a8.38 8.38 0 0 1 -.92 8l-.67.82a10.43 10.43 0 0 0 -.29 11.74 1 1 0 0 0 .82.42 1 1 0 0 0 .58-.19 1 1 0 0 0 .23-1.39 8.4 8.4 0 0 1 .21-9.32l.67-.82a10.32 10.32 0 0 0 1.22-10z"/><path d="m23.22 29h2.78l-4-7-4 7h3.06l1.5 3.7a8.35 8.35 0 0 1 -.92 8l-.67.82a10.43 10.43 0 0 0 -.29 11.74 1 1 0 0 0 .82.42 1 1 0 0 0 .58-.19 1 1 0 0 0 .24-1.39 8.4 8.4 0 0 1 .2-9.32l.67-.82a10.32 10.32 0 0 0 1.22-10z"/><path d="m57.88 20.09a3 3 0 0 0 -1.49-1.84l-7.73-4.1a35.48 35.48 0 0 0 -33.32 0l-7.72 4.1a3 3 0 0 0 -1.22 4.2l9.72 17a3 3 0 0 0 2.6 1.55 3 3 0 0 0 1.39-.34 1 1 0 0 0 .42-1.35 1 1 0 0 0 -1.34-.42 1 1 0 0 1 -1.33-.39l-9.72-17a1 1 0 0 1 -.1-.81 1 1 0 0 1 .52-.69l7.72-4.1a33.46 33.46 0 0 1 31.44 0l7.73 4.1a1 1 0 0 1 .51.63 1 1 0 0 1 -.1.81l-9.72 17a1 1 0 0 1 -1.33.39l-.2-.11a10.82 10.82 0 0 0 -.36-6.72l-1.19-3h2.94l-4-7-4 7h2.9l1.5 3.7a8.38 8.38 0 0 1 -.93 8l-.66.82a10.43 10.43 0 0 0 -.29 11.74 1 1 0 0 0 .82.42 1 1 0 0 0 .58-.19 1 1 0 0 0 .23-1.39 8.4 8.4 0 0 1 .21-9.32l.64-.78a8.27 8.27 0 0 0 .84-1.3 3 3 0 0 0 4-1.17l9.72-17a3 3 0 0 0 .32-2.44z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 98 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Ecommerce" enable-background="new 0 0 48 48" height="512" viewBox="0 0 48 48" width="512" xmlns="http://www.w3.org/2000/svg"><g><path d="m25 7.03c0-.552-.447-1-1-1-5.514 0-10 4.486-10 10 0 .552.447 1 1 1s1-.448 1-1c0-4.411 3.589-8 8-8 .553 0 1-.448 1-1z"/><path d="m22.246 45.79h1.754 1.754c1.652 0 2.999-1.345 3-3v-1.099c1.032-.475 1.755-1.512 1.755-2.721v-3.72c.176-.382.281-.802.281-1.25 0-1.016.226-2 .671-2.927.441-.919 1.086-1.752 1.864-2.409 3.746-3.165 5.709-7.989 5.25-12.909-.7-7.375-6.813-13.189-14.265-13.525l-.31-.01-.354.011c-7.408.335-13.521 6.149-14.222 13.526-.458 4.917 1.505 9.742 5.251 12.906.778.658 1.423 1.491 1.864 2.41.445.927.671 1.911.671 2.927 0 .447.105.868.281 1.25v3.721c0 1.209.722 2.247 1.755 2.721v1.1c.001 1.653 1.348 2.998 3 2.998zm4.508-3c0 .552-.449 1-1 1h-1.754-1.754c-.551 0-1-.449-1-1v-.82h2.754 2.754zm1.755-3.819c0 .551-.448 1-1 1h-3.509-3.509c-.552 0-1-.449-1-1v-2.068c.232.058.47.097.719.097h3.79 3.79c.249 0 .487-.039.719-.097zm-9.299-4.971c0-1.318-.292-2.595-.868-3.793-.563-1.171-1.385-2.233-2.376-3.071-3.247-2.742-4.948-6.926-4.551-11.191.607-6.389 5.903-11.426 12.275-11.715l.31-.01.265.009c6.417.29 11.713 5.327 12.319 11.714.398 4.267-1.303 8.451-4.55 11.193-.991.838-1.813 1.9-2.376 3.071-.576 1.198-.868 2.475-.868 3.793 0 .551-.448 1-1 1h-3.79-3.79c-.552 0-1-.449-1-1z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" height="512" viewBox="0 0 100 100" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m44.94 55.32h4.08c.71 0 1.29.68 1.29 1.52 0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5c0-2.49-1.93-4.52-4.29-4.52h-4.08c-2.37 0-4.29 2.03-4.29 4.52v2.07c0 2.38 1.76 4.32 3.98 4.49.1.02.2.03.31.03h4.08c.71 0 1.29.68 1.29 1.52v2.08c0 .84-.58 1.52-1.29 1.52h-4.08c-.71 0-1.29-.68-1.29-1.52 0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5c0 2.49 1.93 4.52 4.29 4.52h4.08c2.37 0 4.29-2.03 4.29-4.52v-2.08c0-2.38-1.76-4.31-3.98-4.49-.1-.02-.2-.03-.31-.03h-4.08c-.71 0-1.29-.68-1.29-1.52v-2.07c0-.84.58-1.52 1.29-1.52z"/><path d="m64.22 52.32h-4.64c-.83 0-1.5.67-1.5 1.5v16.22c0 .83.67 1.5 1.5 1.5h4.64c3.59 0 6.52-2.92 6.52-6.52v-6.19c-.01-3.59-2.93-6.51-6.52-6.51zm3.51 12.7c0 1.94-1.58 3.52-3.52 3.52h-3.14v-13.22h3.14c1.94 0 3.52 1.58 3.52 3.52z"/><path d="m11.22 72.57c-.28.28-.44.66-.44 1.06v16.99c0 3.44 2.8 6.25 6.25 6.25h65.95c3.44 0 6.25-2.8 6.25-6.25v-81.23c0-3.44-2.8-6.25-6.25-6.25h-55.9c-3.37 0-6.11 2.74-6.11 6.12v24.13l-9.75 9.75c-.28.28-.44.66-.44 1.06v9.87c0 .83.67 1.5 1.5 1.5h8.69v7.26zm11.25-20.01h-8.69v-7.75l9.75-9.75c.28-.28.44-.66.44-1.06v-24.74c0-1.72 1.4-3.12 3.11-3.12h55.9c1.79 0 3.25 1.46 3.25 3.25v81.23c0 1.79-1.46 3.25-3.25 3.25h-65.96c-1.79 0-3.25-1.46-3.25-3.25v-16.37l9.75-9.75c.28-.28.44-.66.44-1.06v-9.38c.01-.83-.67-1.5-1.49-1.5z"/><path d="m31.84 32.33h4.73c1.39 0 2.51-1.13 2.51-2.51v-16.9c0-1.39-1.13-2.51-2.51-2.51h-4.73c-1.39 0-2.51 1.13-2.51 2.51v16.9c0 1.38 1.13 2.51 2.51 2.51zm.49-18.93h3.76v15.93h-3.76z"/><path d="m45.82 32.33h4.73c1.39 0 2.51-1.13 2.51-2.51v-16.9c0-1.39-1.13-2.51-2.51-2.51h-4.73c-1.39 0-2.51 1.13-2.51 2.51v16.9c-.01 1.38 1.12 2.51 2.51 2.51zm.48-18.93h3.76v15.93h-3.76z"/><path d="m59.79 32.33h4.73c1.39 0 2.51-1.13 2.51-2.51v-16.9c0-1.39-1.13-2.51-2.51-2.51h-4.73c-1.39 0-2.51 1.13-2.51 2.51v16.9c-.01 1.38 1.12 2.51 2.51 2.51zm.48-18.93h3.76v15.93h-3.76z"/><path d="m73.76 32.33h4.73c1.39 0 2.51-1.13 2.51-2.51v-16.9c0-1.39-1.13-2.51-2.51-2.51h-4.73c-1.39 0-2.51 1.13-2.51 2.51v16.9c0 1.38 1.12 2.51 2.51 2.51zm.49-18.93h3.76v15.93h-3.76z"/><path d="m30.83 83.8h48.67c.83 0 1.5-.67 1.5-1.5v-38.79c0-.83-.67-1.5-1.5-1.5h-48.67c-.83 0-1.5.67-1.5 1.5v38.79c0 .82.67 1.5 1.5 1.5zm1.5-38.79h45.67v35.79h-45.67z"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m22 11a1 1 0 0 0 -1 1 9 9 0 1 1 -9-9 8.9 8.9 0 0 1 4.42 1.166l-1.127 1.127a1 1 0 0 0 .707 1.707h4a1 1 0 0 0 1-1v-4a1 1 0 0 0 -1.707-.707l-1.411 1.407a10.9 10.9 0 0 0 -5.882-1.7 11 11 0 1 0 11 11 1 1 0 0 0 -1-1z"/></svg>

After

Width:  |  Height:  |  Size: 288 B

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" enable-background="new 0 0 512 512" height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m272.066 512h-32.133c-25.989 0-47.134-21.144-47.134-47.133v-10.871c-11.049-3.53-21.784-7.986-32.097-13.323l-7.704 7.704c-18.659 18.682-48.548 18.134-66.665-.007l-22.711-22.71c-18.149-18.129-18.671-48.008.006-66.665l7.698-7.698c-5.337-10.313-9.792-21.046-13.323-32.097h-10.87c-25.988 0-47.133-21.144-47.133-47.133v-32.134c0-25.989 21.145-47.133 47.134-47.133h10.87c3.531-11.05 7.986-21.784 13.323-32.097l-7.704-7.703c-18.666-18.646-18.151-48.528.006-66.665l22.713-22.712c18.159-18.184 48.041-18.638 66.664.006l7.697 7.697c10.313-5.336 21.048-9.792 32.097-13.323v-10.87c0-25.989 21.144-47.133 47.134-47.133h32.133c25.989 0 47.133 21.144 47.133 47.133v10.871c11.049 3.53 21.784 7.986 32.097 13.323l7.704-7.704c18.659-18.682 48.548-18.134 66.665.007l22.711 22.71c18.149 18.129 18.671 48.008-.006 66.665l-7.698 7.698c5.337 10.313 9.792 21.046 13.323 32.097h10.87c25.989 0 47.134 21.144 47.134 47.133v32.134c0 25.989-21.145 47.133-47.134 47.133h-10.87c-3.531 11.05-7.986 21.784-13.323 32.097l7.704 7.704c18.666 18.646 18.151 48.528-.006 66.665l-22.713 22.712c-18.159 18.184-48.041 18.638-66.664-.006l-7.697-7.697c-10.313 5.336-21.048 9.792-32.097 13.323v10.871c0 25.987-21.144 47.131-47.134 47.131zm-106.349-102.83c14.327 8.473 29.747 14.874 45.831 19.025 6.624 1.709 11.252 7.683 11.252 14.524v22.148c0 9.447 7.687 17.133 17.134 17.133h32.133c9.447 0 17.134-7.686 17.134-17.133v-22.148c0-6.841 4.628-12.815 11.252-14.524 16.084-4.151 31.504-10.552 45.831-19.025 5.895-3.486 13.4-2.538 18.243 2.305l15.688 15.689c6.764 6.772 17.626 6.615 24.224.007l22.727-22.726c6.582-6.574 6.802-17.438.006-24.225l-15.695-15.695c-4.842-4.842-5.79-12.348-2.305-18.242 8.473-14.326 14.873-29.746 19.024-45.831 1.71-6.624 7.684-11.251 14.524-11.251h22.147c9.447 0 17.134-7.686 17.134-17.133v-32.134c0-9.447-7.687-17.133-17.134-17.133h-22.147c-6.841 0-12.814-4.628-14.524-11.251-4.151-16.085-10.552-31.505-19.024-45.831-3.485-5.894-2.537-13.4 2.305-18.242l15.689-15.689c6.782-6.774 6.605-17.634.006-24.225l-22.725-22.725c-6.587-6.596-17.451-6.789-24.225-.006l-15.694 15.695c-4.842 4.843-12.35 5.791-18.243 2.305-14.327-8.473-29.747-14.874-45.831-19.025-6.624-1.709-11.252-7.683-11.252-14.524v-22.15c0-9.447-7.687-17.133-17.134-17.133h-32.133c-9.447 0-17.134 7.686-17.134 17.133v22.148c0 6.841-4.628 12.815-11.252 14.524-16.084 4.151-31.504 10.552-45.831 19.025-5.896 3.485-13.401 2.537-18.243-2.305l-15.688-15.689c-6.764-6.772-17.627-6.615-24.224-.007l-22.727 22.726c-6.582 6.574-6.802 17.437-.006 24.225l15.695 15.695c4.842 4.842 5.79 12.348 2.305 18.242-8.473 14.326-14.873 29.746-19.024 45.831-1.71 6.624-7.684 11.251-14.524 11.251h-22.148c-9.447.001-17.134 7.687-17.134 17.134v32.134c0 9.447 7.687 17.133 17.134 17.133h22.147c6.841 0 12.814 4.628 14.524 11.251 4.151 16.085 10.552 31.505 19.024 45.831 3.485 5.894 2.537 13.4-2.305 18.242l-15.689 15.689c-6.782 6.774-6.605 17.634-.006 24.225l22.725 22.725c6.587 6.596 17.451 6.789 24.225.006l15.694-15.695c3.568-3.567 10.991-6.594 18.244-2.304z"/><path d="m256 367.4c-61.427 0-111.4-49.974-111.4-111.4s49.973-111.4 111.4-111.4 111.4 49.974 111.4 111.4-49.973 111.4-111.4 111.4zm0-192.8c-44.885 0-81.4 36.516-81.4 81.4s36.516 81.4 81.4 81.4 81.4-36.516 81.4-81.4-36.515-81.4-81.4-81.4z"/></svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" height="512" viewBox="0 0 32 32" width="512" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"><path d="m30 17-3 3-3-3h2c0-6.0654-4.9355-11-11-11s-11 4.9346-11 11h-2c0-7.168 5.832-13 13-13s13 5.832 13 13zm0 5h-6v2h6zm-10 0h-2v2h2zm-16 0h-2v2h2zm4 0h-2v2h2zm4 0h-2v2h2zm4 0h-2v2h2z"/></svg>

After

Width:  |  Height:  |  Size: 312 B

+53
View File
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 412.8 412.8" style="enable-background:new 0 0 412.8 412.8;" xml:space="preserve">
<g>
<g>
<path d="M378.4,225.6L304,251.2L274,234v-27.6v-27.2l30-17.2l74.4,25.6c5.2,2,11.2-1.2,12.8-6.4c2-5.2-1.2-11.2-6.4-12.8
l-57.6-19.6l54-31.2c4.8-2.8,6.4-9.2,3.6-14c-2.8-4.8-9.2-6.4-14-3.6l-54,31.2l11.6-59.6c1.2-5.6-2.4-10.8-8-12
c-5.6-1.2-10.8,2.4-12,8l-15.2,77.2l-30,17.2l-22.8-13.2l-0.4-0.4l-23.2-13.6v-34.4L276,48.8c4.4-3.6,4.8-10,0.8-14.4
c-3.6-4.4-10-4.8-14.4-0.8l-45.6,40V10.4c0-5.6-4.4-10.4-10.4-10.4C200.8,0,196,4.4,196,10.4v62.4l-45.6-39.6
C146,29.6,139.6,30,136,34c-3.6,4.4-3.2,10.8,0.8,14.4L196,100v34.4L172.8,148l-23.2,13.6l-30-17.2l-15.2-77.2
c-1.2-5.6-6.4-9.2-12-8c-5.6,1.2-9.2,6.4-8,12L96,130.8L42,99.6c-4.8-2.8-11.2-1.2-14,3.6s-1.2,11.2,3.6,14l54,31.2L28,168
c-5.2,2-8.4,7.6-6.4,12.8s7.6,8.4,12.8,6.4l74.4-25.6l30,17.2v27.6v27.2h0.4l-30,17.2l-74.4-25.6c-5.2-2-11.2,1.2-12.8,6.4
c-2,5.2,1.2,11.2,6.4,12.8L86,264l-54,31.2c-4.8,2.8-6.4,9.2-3.6,14c2.8,4.8,9.2,6.4,14,3.6l54-31.2l-11.6,59.6
c-1.2,5.6,2.4,10.8,8,12c5.6,1.2,10.8-2.4,12-8L120,268l30-17.2l23.6,13.6l23.2,13.6v34.4L137.6,364c-4.4,3.6-4.8,10-0.8,14.4
c3.6,4.4,10,4.8,14.4,0.8l45.6-40v63.2c0,5.6,4.4,10.4,10.4,10.4c5.6,0,10.4-4.4,10.4-10.4V340l45.6,40c4.4,3.6,10.8,3.2,14.4-0.8
c3.6-4.4,3.2-10.8-0.8-14.4l-60-52v-34.4l23.2-13.6l23.2-13.6l30,17.2l15.2,77.2c1.2,5.6,6.4,9.2,12,8c5.6-1.2,9.2-6.4,8-12
L316.8,282l54,31.2c4.8,2.8,11.2,1.2,14-3.6c2.8-4.8,1.2-11.2-3.6-14l-54-31.2l57.6-19.6c5.2-2,8.4-7.6,6.4-12.8
C389.2,226.8,383.6,223.6,378.4,225.6z M252.4,206.4v27.2l-23.2,13.6l-22.8,13.2l-23.6-13.6l-23.2-13.6v-26.8v-27.2l23.2-13.6
L206,152l23.2,13.6l0.4,0.4l22.8,13.2V206.4z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Teamwork" enable-background="new 0 0 64 64" height="512" viewBox="0 0 64 64" width="512" xmlns="http://www.w3.org/2000/svg"><path d="m29.351 39h-15.351c-.553 0-1-.448-1-1s.447-1 1-1h15.351c.553 0 1 .448 1 1s-.448 1-1 1z"/><path d="m29.351 27h-15.351c-.553 0-1-.448-1-1s.447-1 1-1h15.351c.553 0 1 .448 1 1s-.448 1-1 1z"/><path d="m28 33h-20c-.553 0-1-.448-1-1s.447-1 1-1h20c.553 0 1 .448 1 1s-.447 1-1 1z"/><path d="m38 35.902c-1.987 0-4-1.34-4-3.902s2.013-3.902 4-3.902 4 1.34 4 3.902-2.013 3.902-4 3.902zm0-5.804c-.923 0-2 .498-2 1.902s1.077 1.902 2 1.902 2-.498 2-1.902-1.077-1.902-2-1.902z"/><path d="m40.121 30.879c-.256 0-.512-.098-.707-.293-.391-.391-.391-1.023 0-1.414l5.657-5.657c.391-.391 1.023-.391 1.414 0s.391 1.023 0 1.414l-5.657 5.657c-.195.195-.451.293-.707.293z"/><path d="m34.465 36.536c-.256 0-.512-.098-.707-.293-.391-.39-.391-1.023 0-1.414l1.414-1.415c.391-.391 1.023-.391 1.414 0 .391.39.391 1.023 0 1.414l-1.414 1.415c-.195.195-.451.293-.707.293z"/><path d="m38 51c-.553 0-1-.448-1-1v-3c0-.552.447-1 1-1s1 .448 1 1v3c0 .552-.447 1-1 1z"/><path d="m50.728 45.728c-.256 0-.512-.098-.707-.293l-2.121-2.122c-.391-.391-.391-1.024 0-1.414.391-.391 1.023-.391 1.414 0l2.121 2.122c.391.391.391 1.024 0 1.414-.196.195-.452.293-.707.293z"/><path d="m48.606 22.394c-.256 0-.512-.098-.707-.293-.391-.39-.391-1.023 0-1.414l2.121-2.122c.391-.391 1.023-.391 1.414 0 .391.39.391 1.023 0 1.414l-2.121 2.122c-.195.195-.451.293-.707.293z"/><path d="m38 18c-.553 0-1-.448-1-1v-3c0-.552.447-1 1-1s1 .448 1 1v3c0 .552-.447 1-1 1z"/><path d="m56 33h-3c-.553 0-1-.448-1-1s.447-1 1-1h3c.553 0 1 .448 1 1s-.447 1-1 1z"/><path d="m30.789 21h-10.789c-.553 0-1-.448-1-1s.447-1 1-1h10.789c.553 0 1 .448 1 1s-.447 1-1 1z"/><path d="m30.789 45h-10.789c-.553 0-1-.448-1-1s.447-1 1-1h10.789c.553 0 1 .448 1 1s-.447 1-1 1z"/><path d="m37.938 50.981c-2.931 0-5.892-.675-8.642-2.092-.491-.253-.684-.856-.431-1.347s.857-.684 1.347-.431c7.844 4.042 17.615 1.334 22.245-6.165 4.643-7.521 2.7-17.48-4.423-22.673-5.159-3.76-12.155-4.304-17.822-1.385-.49.253-1.094.061-1.347-.431-.253-.491-.061-1.094.431-1.347 6.333-3.264 14.149-2.657 19.916 1.546 7.962 5.804 10.135 16.935 4.946 25.34-3.551 5.754-9.81 8.985-16.22 8.985z"/></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" height="512" viewBox="0 0 64 64" width="512" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"><path d="m36 39.47v-32.47a7 7 0 1 0 -14 0v32.47a13.26 13.26 0 1 0 14 0zm-7 22.59a11.32 11.32 0 0 1 -5.53-21.19 1 1 0 0 0 .53-.87v-33a5 5 0 1 1 10 0v33a1 1 0 0 0 .49.84 11.32 11.32 0 0 1 -5.49 21.22z"/><path d="m30 44.89v-30.25a1 1 0 1 0 -1.94 0v30.25a5.94 5.94 0 1 0 1.94 0zm-1 9.85a4 4 0 1 1 4-4 4 4 0 0 1 -4 4z"/><path d="m40.32 9.64h7a1 1 0 0 0 0-1.94h-7a1 1 0 1 0 0 1.94z"/><path d="m40.32 16.06h4.06a1 1 0 0 0 0-1.94h-4.06a1 1 0 0 0 0 1.94z"/><path d="m47.29 20.55h-7a1 1 0 1 0 0 1.93h7a1 1 0 1 0 0-1.93z"/><path d="m40.32 28.91h4.06a1 1 0 0 0 0-1.94h-4.06a1 1 0 0 0 0 1.94z"/><path d="m47.29 33.39h-7a1 1 0 0 0 0 1.94h7a1 1 0 1 0 0-1.94z"/></svg>

After

Width:  |  Height:  |  Size: 770 B

+1
View File
@@ -0,0 +1 @@
<svg id="layer_1" enable-background="new 0 0 200 200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"><g fill="rgb(0,0,0)"><path d="m61.3366 198.7365c-3.8893 0-7.7945-1.0847-11.3086-3.2781-32.6418-20.3714-44.9485-46.703-49.5247-65.2053-6.1066-30.8373 44.9333-36.4535 67.8505-35.056 1.761-6.9634 6.1301-13.08 12.1249-17.0214-9.0714-12.1387-21.2458-19.7867-36.2543-22.7586-19.3391-3.2847-23.4263-31.1087-5.8545-39.8477 33.3392-19.0024 97.1952-22.5083 96.3704 10.811-.6835 19.2868-6.9715 37.8308-18.7038 55.1859 5.1612 4.9953 8.292 11.7803 8.6884 19.0147 15.0429-1.7888 27.7494-8.5077 37.8247-20.0165 6.0052-6.8593 15.3868-9.1156 23.9022-5.7478 8.5361 3.3773 13.8491 11.4631 13.535 20.6005-1.3216 38.4536-17.9721 62.2774-31.708 75.4917-23.6412 20.7064-54.0319-20.679-64.2755-41.2153-6.816 1.9769-14.557 1.2532-20.8202-1.9875-5.969 13.9198-6.5027 28.2804-1.574 42.7574 5.0949 13.3396-6.2694 28.6219-20.2725 28.273zm-1.6188-94.5681c-14.1176.1632-54.2272 5.0317-50.2069 23.856 4.1646 16.8367 15.4261 40.8368 45.43 59.562 5.3197 3.3207 10.6838 1.7539 13.9293-.8201 3.2305-2.5623 5.9658-7.4048 3.9546-13.3126-6.3202-18.5652-4.873-36.9425 4.3011-54.6216.6379-1.2292 1.7915-2.1091 3.1458-2.3995 1.3551-.2882 2.7674.0404 3.8526.8993 3.4512 2.733 7.6019 4.1775 12.0037 4.1775 4.9261.8516 11.3607-5.6527 14.5071.4457 6.0281 15.2396 35.1102 56.5264 51.2108 42.2675 12.4987-12.025 27.6526-33.7782 28.8673-69.1245.0159-11.6249-13.2308-16.8886-21.1812-8.4221-12.9177 14.7553-29.5546 22.6907-49.4492 23.5865-1.3715.0602-2.7195-.4957-3.6482-1.5215-1.8205-1.8024-.9363-4.3611-.9455-6.5928-.0001-6.3459-3.1223-12.2987-8.3528-15.9233-1.0257-.7109-1.7221-1.8051-1.931-3.0357-.2093-1.2306.0861-2.4938.8196-3.5037 10.2153-12.9246 31.3669-58.5212 11.0023-65.4878-16.6655-4.8123-43.08-7.0587-74.2968 9.5628-10.0753 5.7972-8.0115 19.9044 3.2961 22.5543 19.2372 3.809 34.4279 14.2491 45.1507 31.0306 1.5812 2.3482.4574 5.827-2.1953 6.8094-6.7913 2.7009-11.5582 9.1434-12.144 16.4131-.1006 1.2455-.6991 2.3982-1.6611 3.1966-4.5407 2.4665-10.5485-.3007-15.459.4039z"/><path d="m96.1279 112.2302c-7.607 1.0321-15.4151-13.051-5.4426-14.7224 2.5623.0007 4.6397 2.0781 4.6397 4.6403 0 .4354.3675.8028.8029.8028 6.0654.0249 6.0675 9.2545 0 9.2793z"/><path d="m9.2329 99.228c-12.7712-.764 4.8333-40.6245 9.5289-46.5697 3.292-5.0803 11.0691-.1194 7.8098 5.0118-7.1818 11.1897-11.5808 24.0937-12.7217 37.3166-.2085 2.4172-2.2352 4.2413-4.617 4.2413z"/><path d="m39.2577 89.6348c-11.0543-1.6919 1.3997-18.9153 4.3572-24.1282 3.4934-4.9529 11.064.3241 7.6063 5.3167-3.325 4.7567-5.8564 9.9749-7.5229 15.5084-.6044 2.0077-2.4471 3.3031-4.4406 3.3031z"/><path d="m96.2071 193.9939c-3.6525.2417-8.8695-.1084-8.6734-4.9527.12-2.5591 2.2921-4.5182 4.8525-4.4162 13.2881.6302 26.6579-2.0181 38.6783-7.6414 5.4914-2.5456 9.4266 5.808 3.9316 8.4049-12.0948 5.6586-25.4224 8.6054-38.789 8.6054z"/><path d="m96.194 166.1857c-3.9048.076-10.1254.1951-9.7645-5.2634.2215-2.5524 2.4715-4.439 5.0229-4.2215 5.7823.502 11.5673.0847 17.1924-1.2392 2.4947-.584 4.9917.9597 5.5789 3.4539.8588 8.4162-12.5193 6.4771-18.0297 7.2702z"/><path d="m173.5515 66.6619c-1.6806 0-3.3021-.9157-4.1263-2.512-6.0995-11.8142-15.0751-22.0758-25.9565-29.6754-4.9499-3.4817.3164-11.067 5.3132-7.6072 6.2137 3.1209 41.191 37.1803 24.7696 39.7946z"/><path d="m149.9162 81.597c-1.7462 0-3.4186-.99-4.2065-2.6759-2.4571-5.2576-5.7103-10.0585-9.6698-14.27-4.1842-4.3187 2.6992-10.8071 6.7603-6.3556 3.7145 4.588 19.1197 21.1144 7.116 23.3015z"/></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

+1
View File
@@ -0,0 +1 @@
<svg height="472pt" viewBox="0 -87 472 472" width="472pt" xmlns="http://www.w3.org/2000/svg"><path d="m467.101562 26.527344c-3.039062-1.800782-6.796874-1.871094-9.898437-.179688l-108.296875 59.132813v-35.480469c-.03125-27.601562-22.398438-49.96875-50-50h-248.90625c-27.601562.03125-49.96875 22.398438-50 50v197.421875c.03125 27.601563 22.398438 49.96875 50 50h248.90625c27.601562-.03125 49.96875-22.398437 50-50v-34.835937l108.300781 59.132812c3.097657 1.691406 6.859375 1.625 9.894531-.175781 3.039063-1.804688 4.898438-5.074219 4.898438-8.601563v-227.816406c0-3.53125-1.863281-6.796875-4.898438-8.597656zm-138.203124 220.898437c-.015626 16.5625-13.4375 29.980469-30 30h-248.898438c-16.5625-.019531-29.980469-13.4375-30-30v-197.425781c.019531-16.558594 13.4375-29.980469 30-30h248.90625c16.558594.019531 29.980469 13.441406 30 30zm123.101562-1.335937-103.09375-56.289063v-81.535156l103.09375-56.285156zm0 0"/></svg>

After

Width:  |  Height:  |  Size: 916 B

+2
View File
@@ -0,0 +1,2 @@
<?xml version="1.0"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="512" height="512"><g id="Water"><path d="M24,46A16.0183,16.0183,0,0,1,8,30C8,16.0942,22.708,2.8125,23.3345,2.2539a.9983.9983,0,0,1,1.331,0C25.292,2.8125,40,16.0942,40,30A16.0183,16.0183,0,0,1,24,46ZM24,4.3721C21.1333,7.1372,10,18.6118,10,30a14,14,0,0,0,28,0C38,18.6118,26.8667,7.1372,24,4.3721Z"/><path d="M18.4976,40.5273a.9946.9946,0,0,1-.5-.1342A12.0449,12.0449,0,0,1,12,30a1,1,0,0,1,2,0,10.0373,10.0373,0,0,0,5,8.6616,1,1,0,0,1-.5019,1.8657Z"/></g></svg>

After

Width:  |  Height:  |  Size: 548 B

+73
View File
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<g>
<g>
<path d="M256,40c-5.52,0-10,4.48-10,10s4.48,10,10,10s10-4.48,10-10S261.52,40,256,40z"/>
</g>
</g>
<g>
<g>
<path d="M466,210C466,94.206,371.794,0,256,0S46,94.206,46,210c0,96.488,66.579,180.855,159.516,203.859
c-1.591,14.119-6.958,31.441-13.568,38.051l-0.131,0.131c-18.899,0.353-32.638,3.149-42.999,8.73
C133.677,468.949,126,482.82,126,502c0,5.522,4.478,10,10,10h240c5.522,0,10-4.478,10-10c0-19.187-7.68-33.058-22.824-41.229
c-10.344-5.58-24.082-8.378-42.992-8.731l-0.132-0.132c-6.61-6.609-11.977-23.931-13.568-38.05
C399.423,390.853,466,306.486,466,210z M316,472c33.23,0,45.303,7.689,48.794,20H147.226c2.172-7.762,6.862-11.345,11.087-13.626
C166.274,474.085,178.603,472,196,472H316z M215.517,452c5.068-10.601,8.238-23.466,9.638-34.27
C235.326,419.232,245.658,420,256,420c10.342,0,20.674-0.768,30.845-2.27c1.401,10.804,4.57,23.67,9.638,34.27H215.517z
M294.015,396.179c-0.019,0.004-0.037,0.007-0.056,0.011c-24.788,5.056-51.127,5.057-75.922-0.001
c-0.017-0.004-0.035-0.007-0.052-0.01C129.918,378.227,66,299.929,66,210c0-104.767,85.233-190,190-190s190,85.233,190,190
C446,299.929,382.082,378.227,294.015,396.179z"/>
</g>
</g>
<g>
<g>
<path d="M389.606,104.994c-23.072-29.303-55.544-50.505-91.434-59.701c-5.355-1.374-10.799,1.855-12.17,7.205
c-1.37,5.35,1.855,10.798,7.205,12.169c31.66,8.112,60.314,26.828,80.686,52.7c3.426,4.352,9.716,5.077,14.043,1.67
C392.275,115.621,393.023,109.333,389.606,104.994z"/>
</g>
</g>
<g>
<g>
<path d="M256,100c-60.654,0-110,49.346-110,110s49.346,110,110,110s110-49.346,110-110S316.654,100,256,100z M256,300
c-49.626,0-90-40.374-90-90c0-49.626,40.374-90,90-90c49.626,0,90,40.374,90,90C346,259.626,305.626,300,256,300z"/>
</g>
</g>
<g>
<g>
<path d="M256,140c-38.598,0-70,31.402-70,70c0,38.598,31.402,70,70,70c38.598,0,70-31.402,70-70C326,171.402,294.598,140,256,140z
M256,260c-27.57,0-50-22.43-50-50s22.43-50,50-50s50,22.43,50,50S283.57,260,256,260z"/>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+2 -2
View File
@@ -7,8 +7,8 @@
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png" />
<script type="module" crossorigin src="/assets/index-BarB10XI.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DiPSi5MU.css">
<script type="module" crossorigin src="/assets/index-BdU-188w.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Ca04bhbd.css">
</head>
<body>
<div id="root"></div>