mirror of
https://github.com/katanemo/plano.git
synced 2026-04-25 00:36:34 +02:00
adding logo cloud component to katanemo-www (#718)
This commit is contained in:
parent
a278e67d9a
commit
8749593773
7 changed files with 870 additions and 4 deletions
68
apps/katanemo-www/public/logos/chase.svg
Normal file
68
apps/katanemo-www/public/logos/chase.svg
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 28.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="STANDARD_UPDATE" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
|
||||
y="0px" viewBox="0 0 1000 141.83" style="enable-background:new 0 0 1000 141.83;" xml:space="preserve">
|
||||
<path d="M267.52,104.26c2.51,1.01,6.23,1.66,11.16,1.96v2.11h-55.64v-2.11c4.92-0.3,8.65-0.95,11.16-1.96c2.51-1,4.25-2.61,5.2-4.83
|
||||
c0.95-2.21,1.43-5.48,1.43-9.8V22.37h-0.45l-38.15,87.92h-0.45l-40.87-87.61h-0.45v66.95c0,4.32,0.5,7.59,1.51,9.8
|
||||
c1,2.21,2.74,3.82,5.2,4.83c2.46,1.01,6.16,1.66,11.08,1.96v2.11H135.8v-2.11c4.92-0.3,8.62-0.95,11.08-1.96
|
||||
c2.46-1,4.2-2.61,5.2-4.83c1-2.21,1.51-5.48,1.51-9.8V22.22c0-4.32-0.5-7.59-1.51-9.8c-1.01-2.21-2.74-3.82-5.2-4.83
|
||||
c-2.47-1-6.16-1.66-11.08-1.96V3.52h38.08l34.78,75.93l33.73-75.93h36.29v2.11c-4.93,0.3-8.65,0.96-11.16,1.96
|
||||
c-2.51,1.01-4.27,2.64-5.28,4.9c-1.01,2.26-1.51,5.5-1.51,9.73v67.41c0,4.32,0.5,7.59,1.51,9.8
|
||||
C263.25,101.65,265.01,103.25,267.52,104.26z M343.12,53.44c3.11,5.73,4.67,12.21,4.67,19.45c0,7.24-1.56,13.72-4.67,19.45
|
||||
c-3.12,5.73-7.46,10.16-13.04,13.27c-5.58,3.12-11.94,4.68-19.08,4.68c-7.14,0-13.47-1.56-19-4.68c-5.53-3.11-9.88-7.54-13.04-13.27
|
||||
c-3.17-5.73-4.75-12.21-4.75-19.45c0-7.24,1.58-13.72,4.75-19.45s7.51-10.15,13.04-13.27c5.53-3.12,11.86-4.68,19-4.68
|
||||
c7.14,0,13.5,1.56,19.08,4.68C335.66,43.29,340,47.71,343.12,53.44z M328.04,72.89c0-7.14-0.68-13.27-2.04-18.4
|
||||
c-1.36-5.13-3.32-9.02-5.88-11.69c-2.56-2.66-5.61-4-9.12-4c-3.52,0-6.56,1.33-9.12,4c-2.56,2.67-4.52,6.56-5.88,11.69
|
||||
c-1.36,5.13-2.04,11.26-2.04,18.4c0,7.14,0.68,13.27,2.04,18.4c1.36,5.13,3.32,9.02,5.88,11.69c2.56,2.67,5.6,4,9.12,4
|
||||
c3.52,0,6.56-1.33,9.12-4c2.56-2.66,4.52-6.56,5.88-11.69C327.36,86.16,328.04,80.03,328.04,72.89z M398.92,51.63
|
||||
c2.61,0,4.98,0.45,7.09,1.36V36.4c-1.31-0.6-2.86-0.9-4.67-0.9c-4.63,0-8.72,2.04-12.29,6.11c-3.57,4.07-6.35,8.75-8.93,18.07h-0.34
|
||||
V36.1h-0.6l-29.86,8.6v1.96c3.42,0,6.06,0.33,7.92,0.98c1.86,0.65,3.19,1.71,4,3.17c0.8,1.46,1.21,3.44,1.21,5.96v37.4
|
||||
c0,3.12-0.3,5.43-0.9,6.94c-0.6,1.51-1.71,2.64-3.32,3.39c-1.61,0.75-4.17,1.33-7.69,1.73v2.11h41.92v-2.11
|
||||
c-3.52-0.3-6.16-0.83-7.92-1.58c-1.76-0.75-2.99-1.91-3.69-3.47c-0.7-1.56-1.06-3.9-1.06-7.01V64.53
|
||||
C382.95,57.1,389.91,51.63,398.92,51.63z M453.56,46.52 M618.97,101.02c-0.6-1.56-0.9-3.89-0.9-7.01V59.62
|
||||
c0-16.15-8.94-24.13-20.66-24.13c-11.72,0-19.25,8.3-22.47,12.72h-0.3V36.1h-0.6l-29.86,8.6v1.96c3.32,0,5.93,0.33,7.84,0.98
|
||||
c1.91,0.65,3.27,1.68,4.07,3.09c0.8,1.41,1.21,3.37,1.21,5.88V94c0,3.12-0.3,5.46-0.9,7.01c-0.6,1.56-1.71,2.71-3.32,3.47
|
||||
c-1.61,0.75-4.17,1.33-7.69,1.73v2.11h39.21v-2.11c-2.71-0.4-4.8-0.98-6.26-1.73c-1.46-0.75-2.44-1.91-2.94-3.47
|
||||
c-0.5-1.56-0.75-3.89-0.75-7.01V53.69c3.47-4.21,7.55-8.25,14.18-8.25c9.11,0,11.91,6.87,11.91,14.63V94c0,3.12-0.28,5.46-0.83,7.01
|
||||
c-0.55,1.56-1.51,2.71-2.87,3.47c-1.36,0.75-3.44,1.33-6.26,1.73v2.11h38.76v-2.11c-3.32-0.4-5.76-0.98-7.31-1.73
|
||||
C620.65,103.73,619.58,102.58,618.97,101.02z M1000,87.52c-3.33,7.27-12.62,22.77-31.52,22.77c-17.95,0-32.87-14.68-32.87-36.79
|
||||
c0-6.94,1.51-13.32,4.52-19.15c3.02-5.83,7.11-10.43,12.29-13.8c5.18-3.37,10.88-5.05,17.12-5.05c18.11,0,27.14,12.76,27.14,26.06v3
|
||||
h-44.93c0,0.27-0.01,0.53-0.01,0.8c0,16,7.12,31.37,25.03,31.37c13.62,0,19.32-7.54,21.56-10.25L1000,87.52z M952.06,59.47h28.18
|
||||
c-0.19-10.93-3.45-20.47-12.36-20.51C959.52,38.93,953.46,46.73,952.06,59.47z M799.99,101.02c-0.6-1.56-0.9-3.89-0.9-7.01V59.62
|
||||
c0-5.23-0.88-9.65-2.64-13.27c-1.76-3.62-4.2-6.33-7.31-8.14c-3.12-1.81-6.69-2.71-10.71-2.71c-4.63,0-8.72,1.18-12.29,3.54
|
||||
c-3.57,2.36-6.96,5.76-10.18,10.18h-0.3V0h-0.6L725.2,8.6v1.96c3.32,0,5.93,0.33,7.84,0.98c1.91,0.65,3.27,1.68,4.07,3.09
|
||||
c0.8,1.41,1.21,3.37,1.21,5.88V94c0,3.12-0.3,5.46-0.9,7.01c-0.6,1.56-1.71,2.71-3.32,3.47c-1.61,0.75-4.17,1.33-7.69,1.73v2.11
|
||||
h39.21v-2.11c-2.71-0.4-4.8-0.98-6.26-1.73c-1.46-0.75-2.44-1.91-2.94-3.47c-0.5-1.56-0.75-3.89-0.75-7.01V53.69
|
||||
c3.47-4.21,7.55-8.25,14.18-8.25c3.72,0,6.63,1.23,8.75,3.69c2.11,2.46,3.17,6.11,3.17,10.93V94c0,3.12-0.28,5.46-0.83,7.01
|
||||
c-0.55,1.56-1.51,2.71-2.87,3.47c-1.36,0.75-3.44,1.33-6.26,1.73v2.11h38.76v-2.11c-3.32-0.4-5.76-0.98-7.31-1.73
|
||||
C801.67,103.73,800.6,102.58,799.99,101.02z M690.46,101.82c-22.24,0.15-39.88-17.73-39.88-46.74c0-30.66,16.43-48.54,35.22-48.54
|
||||
c18.79,0,26.85,16.93,30.96,33.56l3.01-0.05V9.45c-7.06-3.91-18.64-8.32-35.47-8.32c-32.46,0-56.96,23.75-56.96,55.46
|
||||
c0,30.21,20.44,54.1,55.61,53.95c19.39-0.15,32.91-11.72,39.37-20.59l-2.1-2.25C715.86,92.66,707.14,101.67,690.46,101.82z
|
||||
M914.35,66.41l-10.4-4.98c-6.91-3.09-10.86-7.18-10.86-12.21c0-5.7,5.22-9.6,12.52-9.6c10.63,0,16.14,5.88,18.42,18.95h3.14v-19
|
||||
c-3.12-1.21-11.36-4.07-19.75-4.07c-16.59,0-26.69,10.43-26.69,22.47c0,4.63,1.23,8.67,3.69,12.14c2.46,3.47,6.16,6.46,11.08,8.97
|
||||
l10.86,5.43c7.43,3.39,10.41,6.73,10.41,11.76c0,5.56-4.48,9.91-12.97,9.91c-12.41,0-18.31-11.77-19.93-21.22h-3.14v19.45
|
||||
c4.73,3.06,13.63,5.88,21.87,5.88c15.9,0,26.99-9.74,26.99-23.52C929.58,76.84,924.28,70.63,914.35,66.41z M90.03,62.64v26.99
|
||||
c0,4.22,0.6,7.46,1.81,9.73c1.21,2.26,3.22,3.9,6.03,4.9c2.81,1.01,7.09,1.66,12.82,1.96v2.11H52.33v-2.11
|
||||
c4.92-0.3,8.62-0.95,11.08-1.96c2.46-1,4.2-2.61,5.2-4.83c1-2.21,1.51-5.48,1.51-9.8V22.68c0-13.79-6.23-16.59-15.69-16.59
|
||||
c-10.38,0-16.73,2.79-16.73,16.14v74.91c0,16.93-11,33.03-32.72,33.03c-1.68,0-3.34-0.1-4.98-0.29v-1.81
|
||||
c5.16-0.31,9.34-2.06,12.52-5.29c3.52-3.57,5.28-9.42,5.28-17.57V22.22c0-4.22-0.5-7.47-1.51-9.73c-1.01-2.26-2.77-3.89-5.28-4.9
|
||||
c-2.51-1-6.18-1.66-11.01-1.96V3.52h103.05c23.44,0,37.95,11.72,37.95,29.41c0,20.25-19.89,29.71-37.67,29.71H90.03z M90.03,58.59
|
||||
h7.19c12.23,0,22.52-7.16,22.52-25.51c0-22.43-14.81-25.51-22.15-25.51h-7.56V58.59z M538.1,102.31c2.49,0,4.68-1.09,6.07-2.03v3.58
|
||||
c-2.78,2.6-7.94,6.38-15.7,6.38c-6.54,0-12.03-4.15-13.49-10.48h-0.39c-2.55,4.82-10.34,10.91-18.84,10.91
|
||||
c-10.2,0-17.71-6.8-17.71-17.14c0-8.08,5.53-13.46,14.73-16.72l21.82-7.86V58.82c0-9.21-6.66-13.46-13.88-13.46
|
||||
c-7.37,0-14.17,3.12-21.25,10.34l-2.12-1.98c6.23-10.06,16.15-18.28,30.46-18.28c13.6,0,24.51,8.93,24.37,23.38l-0.28,36.13
|
||||
C531.87,100.04,534,102.31,538.1,102.31z M514.59,73.67l-8.78,3.56c-6.8,2.69-11.19,5.81-11.19,13.03c0,6.09,4.25,10.34,10.2,10.34
|
||||
c3.12,0,7.65-2.41,9.78-5.1V73.67z M871.01,102.31c2.5,0,4.68-1.1,6.08-2.03v3.58c-2.78,2.6-7.94,6.39-15.71,6.39
|
||||
c-6.54,0-12.03-4.15-13.49-10.48h-0.39c-2.55,4.82-10.34,10.91-18.84,10.91c-10.2,0-17.71-6.8-17.71-17.14
|
||||
c0-8.08,5.53-13.46,14.73-16.72l21.82-7.86V58.82c0-9.21-6.66-13.46-13.88-13.46c-7.37,0-14.17,3.12-21.25,10.34l-2.13-1.98
|
||||
c6.23-10.06,16.15-18.28,30.46-18.28c13.6,0,24.51,8.93,24.37,23.38l-0.28,36.13C864.78,100.04,866.9,102.31,871.01,102.31z
|
||||
M847.49,73.67l-8.78,3.56c-6.8,2.69-11.19,5.81-11.19,13.03c0,6.09,4.25,10.34,10.2,10.34c3.12,0,7.65-2.41,9.78-5.1V73.67z
|
||||
M460.13,40.45c6.45,5.03,9.3,12.27,9.3,18.45c0,16.23-13.87,24.64-29.66,24.64c-4.16,0-8.18-0.59-11.85-1.75
|
||||
c-2.04,1.57-3.79,3.62-3.79,6.02c0,5.16,8.41,6.2,13.43,6.49l17.12,1.18c13.72,0.89,22.42,5.75,22.42,18
|
||||
c0,15.49-18.32,28.33-45,28.33c-15.49,0-26.56-5.31-26.56-14.76c0-8.21,4.52-12.91,16.14-18.49c-7.6-2.21-9.36-6.74-9.36-11.17
|
||||
c0-6.06,5.41-11.5,12.74-16.66c-8.78-3.7-14.95-11.03-14.95-21.85c0-16.23,13.87-24.64,29.66-24.64c7.26,0,13.04,1.65,17.49,4.24
|
||||
c3.32-6.67,9.87-14.43,21.61-14.43v13.85C472.6,35.96,464.95,36.97,460.13,40.45z M417.93,120.58c0,8.56,9.74,12.39,22.43,12.39
|
||||
c12.1,0,28.47-5.46,28.47-14.17c0-5.02-2.8-6.2-10.18-6.79L429,109.81c-1.74-0.13-3.31-0.33-4.72-0.6
|
||||
C420.01,112.54,417.93,115.96,417.93,120.58z M451.13,58.91c0-13.87-4.57-20.51-11.36-20.51s-11.36,6.64-11.36,20.51
|
||||
s4.57,20.51,11.36,20.51S451.13,72.78,451.13,58.91z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.5 KiB |
4
apps/katanemo-www/public/logos/hp.svg
Normal file
4
apps/katanemo-www/public/logos/hp.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="1014" height="1012" version="1.1" viewBox="-10 0 1014 1012" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m498 1012h-15l103-284h143q19 0 37-12.5t24-30.5l111-309q15-39-4.5-65.5t-59.5-26.5h-198l-164 457-94 258q-84-20-156-66-71-46-123.5-111t-81.5-146q-30-80-30-170 0-87 28-166 28-78 78-142t118-110 148-68l-96 266-163 442h107l137-376h81l-137 376h107l128-350q14-38-5-65t-59-27h-90l103-286h23q105 0 197 40t160.5 108.5 108.5 160.5 40 197-40 197-108.5 160.5-160.5 108.5-197 40zm305-662h-81l-113 310h81z" fill="#024ad8"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 571 B |
9
apps/katanemo-www/public/logos/huggingface.svg
Normal file
9
apps/katanemo-www/public/logos/huggingface.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 46 KiB |
3
apps/katanemo-www/public/logos/sandisk.svg
Normal file
3
apps/katanemo-www/public/logos/sandisk.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="108.08" fill="none" viewBox="0 0 1000 108.08">
|
||||
<path fill="#e10600" d="M255.96 0c-11.96 0-23.37 5.8-30.8 15.26l-74.1 92.82h37.55l61.12-75.26c3.03-3.7 5.24-5.53 10-5.53 6.07 0 10.26 5.26 10.26 11.48v32.68c0 5.27-2.7 9.6-7.7 9.6h-7.56v27H297V40.4c0-5.54.15-40.39-41.05-40.39zM32.69.03C14.72.03 0 14.48 0 32.45c0 11.61 2.57 24.71 20.67 31.74l114.4 43.9V86.47c0-9.26-8.86-11.79-8.86-11.79L37.14 43.25c-3.37-1.21-5.53-3.38-5.53-7.97a8.3 8.3 0 0 1 8.37-8.24h59.66c4.03 0 8.28 3.29 8.28 7.7v7.57h27.02V.03H32.69zm291.6 0v108.06h42.42V81.07h-7.57c-5 0-7.83-4.32-7.83-9.59V38.93c0-7.97 7.83-13.91 15.13-10.8 2.7 1.2 5 3.64 6.08 6.48l19.72 51.32c5.13 13.51 17.96 22.16 32.41 22.16h.81c18.64 0 33.9-14.86 33.9-33.64V.03h-27v73.75a7.4 7.4 0 0 1-6.36 7.29 7.1 7.1 0 0 1-7.42-4.6l-24.72-67.8c-1.9-5.4-6.35-8.64-11.75-8.64H324.3zm162.27 0v27.15h81.04c14.32 0 26.88 12.56 26.88 26.88 0 14.31-12.56 26.88-26.88 26.88h-81.04v27.15h81.04a54.22 54.22 0 0 0 47.41-27.97 54.52 54.52 0 0 0 6.62-26.06c0-9.46-2.43-18.24-6.62-26.07A53.79 53.79 0 0 0 567.61.03h-81.05zm146.28 0v27.01h5.67c.67 0 1.35 0 2.16.14 4.98.67 7.97 4.73 7.97 10.13v70.78h27.01V.03h-42.81zm102.65 0c-17.97 0-32.7 14.45-32.7 32.42 0 11.61 2.58 24.71 20.67 31.74l114.4 43.9V86.47c0-9.26-8.85-11.79-8.85-11.79l-89.07-31.43c-3.37-1.21-5.53-3.38-5.53-7.97a8.3 8.3 0 0 1 8.37-8.24h59.66c4.03 0 8.28 3.29 8.28 7.7v7.57h27.02V.03H735.49zm129.44 0v108.06h26.75V69.32a3.25 3.25 0 0 1 3.24-3.24h29.45a6.3 6.3 0 0 1 4.45 1.75l42.28 38.3a7.56 7.56 0 0 0 5.09 1.96H1000V81.07h-12.97c-4.05 0-7.97-1.48-11.07-4.05l-20.12-17.7a6.96 6.96 0 0 1 0-10.4l20.12-17.69a18.23 18.23 0 0 1 11.07-4.05H1000V.03h-23.81c-1.88 0-3.7.7-5.1 1.96l-42.27 38.29a6.6 6.6 0 0 1-4.45 1.76h-29.45a3.25 3.25 0 0 1-3.24-3.25V.03h-26.75zM0 81.07v27.01h26.74V81.07H0zm702.55 0v27.01h26.74V81.07h-26.74z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
165
apps/katanemo-www/public/logos/tmobile.svg
Normal file
165
apps/katanemo-www/public/logos/tmobile.svg
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 12.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 51448) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="svg2008"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.48.5 r10040"
|
||||
sodipodi:docname="T-Mobile_logo.svg"
|
||||
width="523"
|
||||
height="123"
|
||||
viewBox="44 334 523 123"
|
||||
overflow="visible"
|
||||
enable-background="new 44 334 523 123"
|
||||
xml:space="preserve"><metadata
|
||||
id="metadata27"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs25">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
units="mm"
|
||||
inkscape:cy="-177.77119"
|
||||
borderopacity="1.0"
|
||||
pagecolor="#ffffff"
|
||||
inkscape:zoom="0.78723292"
|
||||
inkscape:cx="503.25509"
|
||||
id="base"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:current-layer="svg2008"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1018"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
bordercolor="#666666"
|
||||
width="186.67mm"
|
||||
height="27.6mm"
|
||||
inkscape:document-units="px"
|
||||
showgrid="false"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
showguides="false"
|
||||
inkscape:guide-bbox="true">
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="62.635787,-253.72888"
|
||||
id="guide3247" /><sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="243.25454,-217.78617"
|
||||
id="guide3265" /><sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="342.87554,-242.11217"
|
||||
id="guide4070" /></sodipodi:namedview>
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="path3209"
|
||||
sodipodi:cx="366.91431"
|
||||
sodipodi:cy="41.449261"
|
||||
sodipodi:rx="2.5044003"
|
||||
sodipodi:ry="2.5044003"
|
||||
d="m 369.41871,41.449261 a 2.5044003,2.5044003 0 1 1 -5.0088,0 2.5044003,2.5044003 0 1 1 5.0088,0 z"
|
||||
transform="matrix(2.5267527,0,0,2.592437,-506.01172,255.1969)" /><rect
|
||||
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3211"
|
||||
width="16.107"
|
||||
height="16.437"
|
||||
x="523.84003"
|
||||
y="391.16901" /><rect
|
||||
y="391.16901"
|
||||
x="204.39101"
|
||||
height="16.437"
|
||||
width="16.107"
|
||||
id="rect3213"
|
||||
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /><rect
|
||||
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3215"
|
||||
width="16.107"
|
||||
height="16.437"
|
||||
x="156.07899"
|
||||
y="391.16901" /><rect
|
||||
y="391.16901"
|
||||
x="108.5"
|
||||
height="16.437"
|
||||
width="16.107"
|
||||
id="rect3217"
|
||||
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /><rect
|
||||
style="color:#000000;fill:#999b9e;fill-opacity:1;fill-rule:nonzero;stroke:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect3219"
|
||||
width="16.107"
|
||||
height="16.437"
|
||||
x="59.225998"
|
||||
y="391.16901" /><path
|
||||
style="fill:#ed008c"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3221"
|
||||
d="m 97.909,358.36 h 1.911 c 12.343,0 18.096,6.603 20.5,24.212 l 3.822,-0.169 -0.51,-27.938 H 60.824 l -0.619,27.938 3.678,0.169 c 0.637,-6.603 1.401,-10.159 3.059,-13.715 2.931,-6.604 9.048,-10.497 16.566,-10.497 h 2.676 v 60.784 c 0,6.434 -0.382,8.466 -1.91,9.99 -1.275,1.185 -3.824,1.693 -6.756,1.693 h -2.931 v 4.063 h 34.919 v -4.063 h -2.949 c -2.913,0 -5.48,-0.509 -6.736,-1.693 -1.529,-1.524 -1.911,-3.557 -1.911,-9.99 V 358.36" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3223"
|
||||
d="m 264.053,434.891 20.35,-71.006 v 55.721 c 0,6.081 -0.346,8.218 -1.726,9.697 -1.036,1.15 -3.437,1.644 -6.099,1.644 h -1.035 v 3.944 h 28.765 v -3.944 h -1.497 c -2.646,0 -5.062,-0.493 -6.097,-1.644 -1.382,-1.479 -1.727,-3.616 -1.727,-9.697 v -47.502 c 0,-6.082 0.345,-8.383 1.727,-9.862 1.15,-0.986 3.451,-1.644 6.097,-1.644 h 1.497 v -3.781 h -22.321 l -16.799,57.364 -16.437,-57.364 h -22.206 v 3.781 h 2.07 c 6.099,0 7.249,1.315 7.249,9.205 v 45.2 c 0,7.232 -0.345,10.191 -1.381,12.328 -1.15,2.137 -3.583,3.616 -6.098,3.616 h -1.841 v 3.944 h 23.701 v -3.944 h -1.495 c -2.991,0 -5.408,-1.151 -6.805,-3.452 -1.364,-2.301 -1.709,-4.438 -1.709,-12.492 v -51.117 l 20.233,71.006 h 3.584"
|
||||
style="fill:#999b9e;fill-opacity:1" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3225"
|
||||
d="m 329.044,379.335 c -14.267,0 -23.586,11.177 -23.586,28.765 0,16.93 9.319,28.436 23.226,28.436 14.035,0 23.355,-11.506 23.355,-28.6 0,-16.931 -9.32,-28.601 -22.995,-28.601 m -0.46,3.78 c 4.126,0 7.692,2.63 9.648,7.068 1.841,4.109 2.646,9.698 2.646,17.752 0,16.6 -4.027,24.818 -12.195,24.818 -8.153,0 -12.082,-8.219 -12.082,-24.983 0,-7.89 0.821,-13.478 2.662,-17.587 1.826,-4.273 5.524,-7.068 9.321,-7.068"
|
||||
style="fill:#999b9e;fill-opacity:1" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3227"
|
||||
d="m 371.155,355.995 -16.339,0.822 v 3.616 h 0.789 c 4.833,0 5.885,1.644 5.885,9.369 v 53.419 c 0,6.903 -0.23,8.712 -1.15,11.67 h 3.797 c 2.859,-4.767 3.566,-5.588 4.717,-5.588 0.559,0 1.117,0.164 1.94,0.986 5.653,4.602 8.069,5.588 13.247,5.588 12.409,0 21.384,-11.999 21.384,-29.093 0,-16.108 -8.301,-26.956 -20.71,-26.956 -6.443,0 -11.144,3.123 -13.56,8.711 v -32.544 m 11.933,27.942 c 7.381,0 11.177,7.89 11.177,23.34 0,16.272 -3.912,24.655 -11.391,24.655 -8.284,0 -12.641,-8.548 -12.641,-24.162 0,-7.89 1.037,-13.313 3.453,-17.423 2.169,-3.944 5.868,-6.41 9.402,-6.41"
|
||||
style="fill:#999b9e;fill-opacity:1" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#999b9e;fill-opacity:1"
|
||||
d="m 426.711,380.157 -16.782,0.986 v 3.616 h 1.266 c 4.815,0 5.852,1.644 5.852,9.205 v 27.778 c 0,7.562 -1.036,9.37 -5.852,9.37 h -1.825 v 3.779 h 25.051 v -3.779 h -1.809 c -4.849,0 -5.9,-1.645 -5.9,-9.37 v -41.585"
|
||||
id="path3229" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3231"
|
||||
d="m 455.819,355.995 -16.782,0.822 v 3.616 h 1.251 c 4.832,0 5.867,1.644 5.867,9.369 v 51.939 c 0,7.726 -1.035,9.37 -5.867,9.37 h -1.825 v 3.779 h 25.065 v -3.779 h -1.841 c -4.849,0 -5.868,-1.645 -5.868,-9.37 v -65.746"
|
||||
style="fill:#999b9e;fill-opacity:1" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3233"
|
||||
d="m 509.306,407.606 c -0.56,-17.423 -8.844,-28.271 -21.368,-28.271 -12.098,0 -20.826,11.834 -20.826,28.271 0,17.587 8.613,28.929 21.96,28.929 8.629,0 14.612,-4.603 19.56,-14.794 l -3.451,-1.808 c -4.027,8.547 -8.054,11.999 -14.268,11.999 -9.089,0 -12.984,-7.231 -13.101,-24.326 h 31.494 m -31.378,-4.11 c 0.099,-12.327 4.108,-20.052 10.568,-20.052 6.443,0 10.239,7.561 10.125,20.052 h -20.693"
|
||||
style="fill:#999b9e;fill-opacity:1" /><g
|
||||
id="g3235"
|
||||
style="fill:#999b9e;fill-opacity:1">
|
||||
<g
|
||||
id="g3237"
|
||||
style="fill:#999b9e;fill-opacity:1">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 545.988,377.995 c 0.972,0 1.921,0.249 2.847,0.748 0.926,0.499 1.647,1.213 2.163,2.141 0.518,0.928 0.776,1.896 0.776,2.904 0,0.998 -0.255,1.957 -0.765,2.877 -0.508,0.921 -1.223,1.636 -2.14,2.145 -0.919,0.509 -1.879,0.764 -2.882,0.764 -1.003,0 -1.963,-0.254 -2.882,-0.764 -0.918,-0.509 -1.634,-1.223 -2.144,-2.145 -0.512,-0.92 -0.768,-1.879 -0.768,-2.877 0,-1.008 0.259,-1.976 0.779,-2.904 0.519,-0.928 1.242,-1.643 2.166,-2.141 0.93,-0.499 1.879,-0.748 2.85,-0.748 z m 0,0.964 c -0.812,0 -1.604,0.208 -2.372,0.625 -0.769,0.417 -1.371,1.011 -1.806,1.785 -0.434,0.774 -0.65,1.581 -0.65,2.418 0,0.833 0.213,1.631 0.64,2.395 0.426,0.764 1.023,1.359 1.789,1.786 0.767,0.427 1.567,0.64 2.399,0.64 0.834,0 1.632,-0.213 2.399,-0.64 0.766,-0.426 1.361,-1.021 1.785,-1.786 0.424,-0.764 0.637,-1.562 0.637,-2.395 0,-0.837 -0.216,-1.644 -0.648,-2.418 -0.432,-0.773 -1.033,-1.368 -1.805,-1.785 -0.771,-0.417 -1.56,-0.625 -2.368,-0.625 z m -2.54,8.023 v -6.23 h 2.145 c 0.731,0 1.263,0.058 1.59,0.173 0.329,0.115 0.59,0.316 0.784,0.603 0.195,0.286 0.293,0.591 0.293,0.913 0,0.455 -0.164,0.852 -0.49,1.189 -0.324,0.337 -0.757,0.527 -1.296,0.568 0.221,0.092 0.397,0.202 0.53,0.33 0.252,0.245 0.559,0.657 0.922,1.235 l 0.761,1.22 h -1.233 L 546.899,386 c -0.435,-0.769 -0.784,-1.251 -1.047,-1.447 -0.184,-0.145 -0.453,-0.217 -0.806,-0.217 h -0.592 v 2.647 h -1.006 z m 1.007,-3.502 h 1.226 c 0.584,0 0.983,-0.087 1.197,-0.262 0.214,-0.175 0.319,-0.406 0.319,-0.694 0,-0.185 -0.051,-0.351 -0.154,-0.497 -0.103,-0.146 -0.244,-0.256 -0.428,-0.328 -0.182,-0.072 -0.52,-0.107 -1.013,-0.107 h -1.147 v 1.888 z"
|
||||
id="path3239"
|
||||
style="fill:#999b9e;fill-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.4 KiB |
|
|
@ -1,5 +1,6 @@
|
|||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import LogoSlider from "../components/LogoSlider";
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
|
|
@ -23,25 +24,34 @@ export default function HomePage() {
|
|||
Bringing industry-leading research and open-source technologies to
|
||||
accelerate the development of AI agents.
|
||||
</p>
|
||||
<p className="mt-6 sm:mt-12 font-light tracking-[-0.4px] max-w-2xl text-xs sm:text-sm md:text-sm lg:text-sm text-white/50">
|
||||
Trusted by leading companies to deliver agents to production.
|
||||
</p>
|
||||
<LogoSlider />
|
||||
<div className="mt-18 flex flex-col gap-3 text-lg sm:text-xl lg:text-3xl font-light tracking-wide sm:tracking-[-0.03em] leading-snug">
|
||||
<Link
|
||||
href="https://huggingface.co/katanemo"
|
||||
className="flex items-center gap-2 text-[#31C887] hover:text-[#45e394] transition-colors"
|
||||
>
|
||||
<span>Models Research</span>
|
||||
<span aria-hidden className="text-emerald-300">↗</span>
|
||||
<span aria-hidden className="text-emerald-300">
|
||||
↗
|
||||
</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="https://planoai.dev"
|
||||
className="flex items-center gap-2 text-[#31C887] hover:text-[#45e394] transition-colors"
|
||||
>
|
||||
<span>Plano - Open Source Agent Infrastructure</span>
|
||||
<span aria-hidden className="text-emerald-300">↗</span>
|
||||
<span aria-hidden className="text-emerald-300">
|
||||
↗
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="mt-24">
|
||||
<div className="sm:max-w-7xl max-w-72 mb-4 text-sm sm:text-base lg:text-lg text-white/70 tracking-[-0.3px] sm:tracking-[0.8px]! font-light">
|
||||
Move faster and more reliably by letting Katanemo do the heavy-lifting.
|
||||
Move faster and more reliably by letting Katanemo do the
|
||||
heavy-lifting.
|
||||
</div>
|
||||
<a
|
||||
href="mailto:interest@katanemo.com"
|
||||
|
|
@ -54,7 +64,6 @@ export default function HomePage() {
|
|||
© 2026 Katanemo Labs, Inc.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className="pointer-events-none absolute top-50 right-[-20vw] sm:right-[-10vw] md:right-[-5vw] lg:right-[-20vw] xl:right-[-7vw] 2xl:right-[-17vw] hidden lg:block">
|
||||
<Image
|
||||
|
|
|
|||
608
apps/katanemo-www/src/components/LogoSlider.tsx
Normal file
608
apps/katanemo-www/src/components/LogoSlider.tsx
Normal file
|
|
@ -0,0 +1,608 @@
|
|||
"use client";
|
||||
|
||||
import Image from "next/image";
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
|
||||
export type LogoItem =
|
||||
| {
|
||||
node: React.ReactNode;
|
||||
href?: string;
|
||||
title?: string;
|
||||
ariaLabel?: string;
|
||||
}
|
||||
| {
|
||||
src: string;
|
||||
alt?: string;
|
||||
href?: string;
|
||||
title?: string;
|
||||
srcSet?: string;
|
||||
sizes?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
};
|
||||
|
||||
export interface LogoLoopProps {
|
||||
logos: LogoItem[];
|
||||
speed?: number;
|
||||
direction?: "left" | "right" | "up" | "down";
|
||||
width?: number | string;
|
||||
logoHeight?: number;
|
||||
gap?: number;
|
||||
pauseOnHover?: boolean;
|
||||
hoverSpeed?: number;
|
||||
fadeOut?: boolean;
|
||||
fadeOutColor?: string;
|
||||
scaleOnHover?: boolean;
|
||||
renderItem?: (item: LogoItem, key: React.Key) => React.ReactNode;
|
||||
ariaLabel?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const ANIMATION_CONFIG = {
|
||||
SMOOTH_TAU: 0.25,
|
||||
MIN_COPIES: 2,
|
||||
COPY_HEADROOM: 2,
|
||||
} as const;
|
||||
|
||||
const toCssLength = (value?: number | string): string | undefined =>
|
||||
typeof value === "number" ? `${value}px` : (value ?? undefined);
|
||||
|
||||
const cx = (...parts: Array<string | false | null | undefined>) =>
|
||||
parts.filter(Boolean).join(" ");
|
||||
|
||||
const isNodeItem = (
|
||||
item: LogoItem,
|
||||
): item is Extract<LogoItem, { node: React.ReactNode }> => "node" in item;
|
||||
|
||||
const isImageItem = (
|
||||
item: LogoItem,
|
||||
): item is Extract<LogoItem, { src: string }> => "src" in item;
|
||||
|
||||
const useResizeObserver = (
|
||||
callback: () => void,
|
||||
elements: Array<React.RefObject<Element | null>>,
|
||||
dependencies: React.DependencyList,
|
||||
) => {
|
||||
useEffect(() => {
|
||||
if (!window.ResizeObserver) {
|
||||
const handleResize = () => callback();
|
||||
window.addEventListener("resize", handleResize);
|
||||
callback();
|
||||
return () => window.removeEventListener("resize", handleResize);
|
||||
}
|
||||
|
||||
const observers: Array<ResizeObserver | null> = [];
|
||||
for (const ref of elements) {
|
||||
if (!ref.current) {
|
||||
observers.push(null);
|
||||
continue;
|
||||
}
|
||||
const observer = new ResizeObserver(callback);
|
||||
observer.observe(ref.current);
|
||||
observers.push(observer);
|
||||
}
|
||||
|
||||
callback();
|
||||
|
||||
return () => {
|
||||
for (const observer of observers) {
|
||||
observer?.disconnect();
|
||||
}
|
||||
};
|
||||
}, [callback, elements, ...elements, ...dependencies]);
|
||||
};
|
||||
|
||||
const useImageLoader = (
|
||||
seqRef: React.RefObject<HTMLUListElement | null>,
|
||||
onLoad: () => void,
|
||||
dependencies: React.DependencyList,
|
||||
) => {
|
||||
useEffect(() => {
|
||||
const images = seqRef.current?.querySelectorAll("img") ?? [];
|
||||
|
||||
if (images.length === 0) {
|
||||
onLoad();
|
||||
return;
|
||||
}
|
||||
|
||||
let remainingImages = images.length;
|
||||
const handleImageLoad = () => {
|
||||
remainingImages -= 1;
|
||||
if (remainingImages === 0) {
|
||||
onLoad();
|
||||
}
|
||||
};
|
||||
|
||||
images.forEach((img) => {
|
||||
const htmlImg = img as HTMLImageElement;
|
||||
if (htmlImg.complete) {
|
||||
handleImageLoad();
|
||||
} else {
|
||||
htmlImg.addEventListener("load", handleImageLoad, { once: true });
|
||||
htmlImg.addEventListener("error", handleImageLoad, { once: true });
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
images.forEach((img) => {
|
||||
img.removeEventListener("load", handleImageLoad);
|
||||
img.removeEventListener("error", handleImageLoad);
|
||||
});
|
||||
};
|
||||
}, [onLoad, seqRef, ...dependencies]);
|
||||
};
|
||||
|
||||
const useAnimationLoop = (
|
||||
trackRef: React.RefObject<HTMLDivElement | null>,
|
||||
targetVelocity: number,
|
||||
seqWidth: number,
|
||||
seqHeight: number,
|
||||
isHovered: boolean,
|
||||
hoverSpeed: number | undefined,
|
||||
isVertical: boolean,
|
||||
) => {
|
||||
const rafRef = useRef<number | null>(null);
|
||||
const lastTimestampRef = useRef<number | null>(null);
|
||||
const offsetRef = useRef(0);
|
||||
const velocityRef = useRef(0);
|
||||
|
||||
useEffect(() => {
|
||||
const track = trackRef.current;
|
||||
if (!track) return;
|
||||
|
||||
const prefersReduced =
|
||||
typeof window !== "undefined" &&
|
||||
window.matchMedia &&
|
||||
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
|
||||
const seqSize = isVertical ? seqHeight : seqWidth;
|
||||
|
||||
if (seqSize > 0) {
|
||||
offsetRef.current = ((offsetRef.current % seqSize) + seqSize) % seqSize;
|
||||
const transformValue = isVertical
|
||||
? `translate3d(0, ${-offsetRef.current}px, 0)`
|
||||
: `translate3d(${-offsetRef.current}px, 0, 0)`;
|
||||
track.style.transform = transformValue;
|
||||
}
|
||||
|
||||
if (prefersReduced) {
|
||||
track.style.transform = isVertical
|
||||
? "translate3d(0, 0, 0)"
|
||||
: "translate3d(0, 0, 0)";
|
||||
return () => {
|
||||
lastTimestampRef.current = null;
|
||||
};
|
||||
}
|
||||
|
||||
const animate = (timestamp: number) => {
|
||||
if (lastTimestampRef.current === null) {
|
||||
lastTimestampRef.current = timestamp;
|
||||
}
|
||||
|
||||
const deltaTime =
|
||||
Math.max(0, timestamp - lastTimestampRef.current) / 1000;
|
||||
lastTimestampRef.current = timestamp;
|
||||
|
||||
const target =
|
||||
isHovered && hoverSpeed !== undefined ? hoverSpeed : targetVelocity;
|
||||
|
||||
const easingFactor =
|
||||
1 - Math.exp(-deltaTime / ANIMATION_CONFIG.SMOOTH_TAU);
|
||||
velocityRef.current += (target - velocityRef.current) * easingFactor;
|
||||
|
||||
if (seqSize > 0) {
|
||||
let nextOffset = offsetRef.current + velocityRef.current * deltaTime;
|
||||
nextOffset = ((nextOffset % seqSize) + seqSize) % seqSize;
|
||||
offsetRef.current = nextOffset;
|
||||
|
||||
const transformValue = isVertical
|
||||
? `translate3d(0, ${-offsetRef.current}px, 0)`
|
||||
: `translate3d(${-offsetRef.current}px, 0, 0)`;
|
||||
track.style.transform = transformValue;
|
||||
}
|
||||
|
||||
rafRef.current = requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
rafRef.current = requestAnimationFrame(animate);
|
||||
|
||||
return () => {
|
||||
if (rafRef.current !== null) {
|
||||
cancelAnimationFrame(rafRef.current);
|
||||
rafRef.current = null;
|
||||
}
|
||||
lastTimestampRef.current = null;
|
||||
};
|
||||
}, [
|
||||
trackRef,
|
||||
targetVelocity,
|
||||
seqWidth,
|
||||
seqHeight,
|
||||
isHovered,
|
||||
hoverSpeed,
|
||||
isVertical,
|
||||
]);
|
||||
};
|
||||
|
||||
export const LogoLoop = React.memo<LogoLoopProps>(
|
||||
({
|
||||
logos,
|
||||
speed = 120,
|
||||
direction = "left",
|
||||
width = "100%",
|
||||
logoHeight = 28,
|
||||
gap = 32,
|
||||
pauseOnHover,
|
||||
hoverSpeed,
|
||||
fadeOut = false,
|
||||
fadeOutColor,
|
||||
scaleOnHover = false,
|
||||
renderItem,
|
||||
ariaLabel = "Partner logos",
|
||||
className,
|
||||
style,
|
||||
}) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const trackRef = useRef<HTMLDivElement>(null);
|
||||
const seqRef = useRef<HTMLUListElement>(null);
|
||||
|
||||
const [seqWidth, setSeqWidth] = useState<number>(0);
|
||||
const [seqHeight, setSeqHeight] = useState<number>(0);
|
||||
const [copyCount, setCopyCount] = useState<number>(
|
||||
ANIMATION_CONFIG.MIN_COPIES,
|
||||
);
|
||||
const [isHovered, setIsHovered] = useState<boolean>(false);
|
||||
|
||||
const effectiveHoverSpeed = useMemo(() => {
|
||||
if (hoverSpeed !== undefined) return hoverSpeed;
|
||||
if (pauseOnHover === true) return 0;
|
||||
if (pauseOnHover === false) return undefined;
|
||||
return 0;
|
||||
}, [hoverSpeed, pauseOnHover]);
|
||||
|
||||
const isVertical = direction === "up" || direction === "down";
|
||||
|
||||
const targetVelocity = useMemo(() => {
|
||||
const magnitude = Math.abs(speed);
|
||||
let directionMultiplier: number;
|
||||
if (isVertical) {
|
||||
directionMultiplier = direction === "up" ? 1 : -1;
|
||||
} else {
|
||||
directionMultiplier = direction === "left" ? 1 : -1;
|
||||
}
|
||||
const speedMultiplier = speed < 0 ? -1 : 1;
|
||||
return magnitude * directionMultiplier * speedMultiplier;
|
||||
}, [speed, direction, isVertical]);
|
||||
|
||||
const updateDimensions = useCallback(() => {
|
||||
const containerWidth = containerRef.current?.clientWidth ?? 0;
|
||||
const sequenceRect = seqRef.current?.getBoundingClientRect?.();
|
||||
const sequenceWidth = sequenceRect?.width ?? 0;
|
||||
const sequenceHeight = sequenceRect?.height ?? 0;
|
||||
if (isVertical) {
|
||||
const parentHeight =
|
||||
containerRef.current?.parentElement?.clientHeight ?? 0;
|
||||
if (containerRef.current && parentHeight > 0) {
|
||||
const targetHeight = Math.ceil(parentHeight);
|
||||
if (containerRef.current.style.height !== `${targetHeight}px`)
|
||||
containerRef.current.style.height = `${targetHeight}px`;
|
||||
}
|
||||
if (sequenceHeight > 0) {
|
||||
setSeqHeight(Math.ceil(sequenceHeight));
|
||||
const viewport =
|
||||
containerRef.current?.clientHeight ??
|
||||
parentHeight ??
|
||||
sequenceHeight;
|
||||
const copiesNeeded =
|
||||
Math.ceil(viewport / sequenceHeight) +
|
||||
ANIMATION_CONFIG.COPY_HEADROOM;
|
||||
setCopyCount(Math.max(ANIMATION_CONFIG.MIN_COPIES, copiesNeeded));
|
||||
}
|
||||
} else if (sequenceWidth > 0) {
|
||||
setSeqWidth(Math.ceil(sequenceWidth));
|
||||
const copiesNeeded =
|
||||
Math.ceil(containerWidth / sequenceWidth) +
|
||||
ANIMATION_CONFIG.COPY_HEADROOM;
|
||||
setCopyCount(Math.max(ANIMATION_CONFIG.MIN_COPIES, copiesNeeded));
|
||||
}
|
||||
}, [isVertical]);
|
||||
|
||||
useResizeObserver(
|
||||
updateDimensions,
|
||||
[containerRef, seqRef],
|
||||
[logos, gap, logoHeight, isVertical],
|
||||
);
|
||||
|
||||
useImageLoader(seqRef, updateDimensions, [
|
||||
logos,
|
||||
gap,
|
||||
logoHeight,
|
||||
isVertical,
|
||||
]);
|
||||
|
||||
useAnimationLoop(
|
||||
trackRef,
|
||||
targetVelocity,
|
||||
seqWidth,
|
||||
seqHeight,
|
||||
isHovered,
|
||||
effectiveHoverSpeed,
|
||||
isVertical,
|
||||
);
|
||||
|
||||
const cssVariables = useMemo(
|
||||
() =>
|
||||
({
|
||||
"--logoloop-gap": `${gap}px`,
|
||||
"--logoloop-logoHeight": `${logoHeight}px`,
|
||||
...(fadeOutColor && { "--logoloop-fadeColor": fadeOutColor }),
|
||||
}) as React.CSSProperties,
|
||||
[gap, logoHeight, fadeOutColor],
|
||||
);
|
||||
|
||||
const rootClasses = useMemo(
|
||||
() =>
|
||||
cx(
|
||||
"relative group",
|
||||
isVertical
|
||||
? "overflow-hidden h-full inline-block"
|
||||
: "overflow-x-hidden",
|
||||
"[--logoloop-gap:32px]",
|
||||
"[--logoloop-logoHeight:28px]",
|
||||
"[--logoloop-fadeColorAuto:#ffffff]",
|
||||
"dark:[--logoloop-fadeColorAuto:#0b0b0b]",
|
||||
scaleOnHover && "py-[calc(var(--logoloop-logoHeight)*0.1)]",
|
||||
className,
|
||||
),
|
||||
[isVertical, scaleOnHover, className],
|
||||
);
|
||||
|
||||
const handleMouseEnter = useCallback(() => {
|
||||
if (effectiveHoverSpeed !== undefined) setIsHovered(true);
|
||||
}, [effectiveHoverSpeed]);
|
||||
const handleMouseLeave = useCallback(() => {
|
||||
if (effectiveHoverSpeed !== undefined) setIsHovered(false);
|
||||
}, [effectiveHoverSpeed]);
|
||||
|
||||
const renderLogoItem = useCallback(
|
||||
(item: LogoItem, key: React.Key) => {
|
||||
if (renderItem) {
|
||||
return (
|
||||
<li
|
||||
className={cx(
|
||||
"flex-none text-[length:var(--logoloop-logoHeight)] leading-[1]",
|
||||
isVertical
|
||||
? "mb-[var(--logoloop-gap)]"
|
||||
: "mr-[var(--logoloop-gap)]",
|
||||
scaleOnHover && "overflow-visible group/item",
|
||||
)}
|
||||
key={key}
|
||||
>
|
||||
{renderItem(item, key)}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
const content = isNodeItem(item) ? (
|
||||
<span
|
||||
className={cx(
|
||||
"inline-flex items-center",
|
||||
"motion-reduce:transition-none",
|
||||
scaleOnHover &&
|
||||
"transition-transform duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover/item:scale-120",
|
||||
)}
|
||||
aria-hidden={!!item.href && !item.ariaLabel}
|
||||
>
|
||||
{item.node}
|
||||
</span>
|
||||
) : (
|
||||
<Image
|
||||
className={cx(
|
||||
"h-[var(--logoloop-logoHeight)] w-auto block object-contain",
|
||||
"[-webkit-user-drag:none] pointer-events-none",
|
||||
"[image-rendering:-webkit-optimize-contrast]",
|
||||
"motion-reduce:transition-none",
|
||||
scaleOnHover &&
|
||||
"transition-transform duration-300 ease-[cubic-bezier(0.4,0,0.2,1)] group-hover/item:scale-120",
|
||||
)}
|
||||
src={item.src}
|
||||
sizes={item.sizes}
|
||||
width={item.width ?? 120}
|
||||
height={item.height ?? 32}
|
||||
alt={item.alt ?? ""}
|
||||
title={item.title}
|
||||
draggable={false}
|
||||
/>
|
||||
);
|
||||
|
||||
const itemAriaLabel = isNodeItem(item)
|
||||
? (item.ariaLabel ?? item.title)
|
||||
: (item.alt ?? item.title);
|
||||
|
||||
const inner = item.href ? (
|
||||
<a
|
||||
className={cx(
|
||||
"inline-flex items-center no-underline rounded",
|
||||
"transition-opacity duration-200 ease-linear",
|
||||
"hover:opacity-80",
|
||||
"focus-visible:outline focus-visible:outline-current focus-visible:outline-offset-2",
|
||||
)}
|
||||
href={item.href}
|
||||
aria-label={itemAriaLabel || "logo link"}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
{content}
|
||||
</a>
|
||||
) : (
|
||||
content
|
||||
);
|
||||
|
||||
return (
|
||||
<li
|
||||
className={cx(
|
||||
"flex-none text-[length:var(--logoloop-logoHeight)] leading-[1]",
|
||||
isVertical
|
||||
? "mb-[var(--logoloop-gap)]"
|
||||
: "mr-[var(--logoloop-gap)]",
|
||||
scaleOnHover && "overflow-visible group/item",
|
||||
)}
|
||||
key={key}
|
||||
>
|
||||
{inner}
|
||||
</li>
|
||||
);
|
||||
},
|
||||
[isVertical, scaleOnHover, renderItem],
|
||||
);
|
||||
|
||||
const logoLists = useMemo(
|
||||
() =>
|
||||
Array.from({ length: copyCount }, (_, copyIndex) => (
|
||||
<ul
|
||||
className={cx("flex items-center", isVertical && "flex-col")}
|
||||
// biome-ignore lint/suspicious/noArrayIndexKey: Static copies for animation.
|
||||
key={`copy-${copyIndex}`}
|
||||
aria-hidden={copyIndex > 0}
|
||||
ref={copyIndex === 0 ? seqRef : undefined}
|
||||
>
|
||||
{logos.map((item, itemIndex) =>
|
||||
renderLogoItem(item, `${copyIndex}-${itemIndex}`),
|
||||
)}
|
||||
</ul>
|
||||
)),
|
||||
[copyCount, logos, renderLogoItem, isVertical],
|
||||
);
|
||||
|
||||
const containerStyle = useMemo(
|
||||
(): React.CSSProperties => ({
|
||||
width: isVertical
|
||||
? toCssLength(width) === "100%"
|
||||
? undefined
|
||||
: toCssLength(width)
|
||||
: (toCssLength(width) ?? "100%"),
|
||||
...cssVariables,
|
||||
...style,
|
||||
}),
|
||||
[width, cssVariables, style, isVertical],
|
||||
);
|
||||
|
||||
return (
|
||||
<section
|
||||
ref={containerRef}
|
||||
className={rootClasses}
|
||||
style={containerStyle}
|
||||
aria-label={ariaLabel}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
{fadeOut &&
|
||||
(isVertical ? (
|
||||
<>
|
||||
<div
|
||||
aria-hidden
|
||||
className={cx(
|
||||
"pointer-events-none absolute inset-x-0 top-0 z-10",
|
||||
"h-[clamp(24px,8%,120px)]",
|
||||
"bg-[linear-gradient(to_bottom,var(--logoloop-fadeColor,var(--logoloop-fadeColorAuto))_0%,rgba(0,0,0,0)_100%)]",
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
aria-hidden
|
||||
className={cx(
|
||||
"pointer-events-none absolute inset-x-0 bottom-0 z-10",
|
||||
"h-[clamp(24px,8%,120px)]",
|
||||
"bg-[linear-gradient(to_top,var(--logoloop-fadeColor,var(--logoloop-fadeColorAuto))_0%,rgba(0,0,0,0)_100%)]",
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
aria-hidden
|
||||
className={cx(
|
||||
"pointer-events-none absolute inset-y-0 left-0 z-10",
|
||||
"w-[clamp(24px,8%,120px)]",
|
||||
"bg-[linear-gradient(to_right,var(--logoloop-fadeColor,var(--logoloop-fadeColorAuto))_0%,rgba(0,0,0,0)_100%)]",
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
aria-hidden
|
||||
className={cx(
|
||||
"pointer-events-none absolute inset-y-0 right-0 z-10",
|
||||
"w-[clamp(24px,8%,120px)]",
|
||||
"bg-[linear-gradient(to_left,var(--logoloop-fadeColor,var(--logoloop-fadeColorAuto))_0%,rgba(0,0,0,0)_100%)]",
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
))}
|
||||
|
||||
<div
|
||||
className={cx(
|
||||
"flex will-change-transform select-none relative z-0",
|
||||
"motion-reduce:transform-none",
|
||||
isVertical ? "flex-col h-max w-full" : "flex-row w-max",
|
||||
)}
|
||||
ref={trackRef}
|
||||
>
|
||||
{logoLists}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
LogoLoop.displayName = "LogoLoop";
|
||||
|
||||
const logos: LogoItem[] = [
|
||||
{ src: "/logos/chase.svg", alt: "Chase" },
|
||||
{ src: "/logos/hp.svg", alt: "HP" },
|
||||
{ src: "/logos/huggingface.svg", alt: "Hugging Face" },
|
||||
{ src: "/logos/sandisk.svg", alt: "SanDisk" },
|
||||
{ src: "/logos/tmobile.svg", alt: "T-Mobile" },
|
||||
];
|
||||
|
||||
export default function LogoSlider() {
|
||||
return (
|
||||
<div className="mt-5 w-full max-w-90 sm:max-w-152">
|
||||
<LogoLoop
|
||||
logos={logos}
|
||||
speed={40}
|
||||
logoHeight={17}
|
||||
gap={30}
|
||||
fadeOut={false}
|
||||
renderItem={(item, key) => {
|
||||
if (isImageItem(item)) {
|
||||
return (
|
||||
<Image
|
||||
key={key}
|
||||
src={item.src}
|
||||
alt={item.alt ?? ""}
|
||||
width={item.width ?? 120}
|
||||
height={item.height ?? 32}
|
||||
className="h-[var(--logoloop-logoHeight)] w-auto opacity-70 brightness-0 invert"
|
||||
draggable={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <span key={key}>{item.node}</span>;
|
||||
}}
|
||||
className="relative"
|
||||
style={{
|
||||
WebkitMaskImage:
|
||||
"linear-gradient(to right, transparent 0%, black 10%, black 90%, transparent 100%)",
|
||||
maskImage:
|
||||
"linear-gradient(to right, transparent 0%, black 10%, black 90%, transparent 100%)",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue