feat: 增加一些新组件
|
@ -1,3 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14.5 5L9.26369 10.6391C8.55114 11.4065 8.55114 12.5935 9.26369 13.3609L14.5 19" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/>
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.34863 13.6543C8.34863 13.9619 8.46289 14.2256 8.70898 14.4541L15.5469 21.1514C15.7402 21.3447 15.9863 21.4502 16.2764 21.4502C16.8564 21.4502 17.3223 20.9932 17.3223 20.4043C17.3223 20.1143 17.1992 19.8594 17.0059 19.6572L10.8447 13.6543L17.0059 7.65137C17.1992 7.44922 17.3223 7.18555 17.3223 6.9043C17.3223 6.31543 16.8564 5.8584 16.2764 5.8584C15.9863 5.8584 15.7402 5.96387 15.5469 6.15723L8.70898 12.8457C8.46289 13.083 8.34863 13.3467 8.34863 13.6543Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 259 B After Width: | Height: | Size: 596 B |
3
packages/web/assets/icons/discovery.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="41" height="40" viewBox="0 0 41 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.72705 28.9858C9.72705 31.6978 11.1207 33.1041 13.8077 33.1041H27.1796C29.8666 33.1041 31.2603 31.6978 31.2603 28.9858V10.039C31.2603 7.33955 29.8666 5.92075 27.1796 5.92075H13.8077C11.1207 5.92075 9.72705 7.33955 9.72705 10.039V28.9858ZM14.9 12.9897C14.2346 12.9897 13.6821 12.4372 13.6821 11.7718C13.6821 11.1188 14.2346 10.5538 14.9 10.5538C15.5655 10.5538 16.118 11.1063 16.118 11.7718C16.118 12.4498 15.5655 12.9897 14.9 12.9897ZM18.5914 12.6381C18.1143 12.6381 17.7251 12.2489 17.7251 11.7718C17.7251 11.3072 18.1143 10.918 18.5914 10.918H26.4514C26.9159 10.918 27.3052 11.3072 27.3052 11.7718C27.3052 12.2489 26.9159 12.6381 26.4514 12.6381H18.5914ZM14.9 16.882C14.222 16.882 13.6821 16.3295 13.6821 15.6641C13.6821 14.9986 14.222 14.4587 14.9 14.4587C15.5655 14.4587 16.118 14.986 16.118 15.6641C16.118 16.3295 15.5655 16.882 14.9 16.882ZM18.5914 16.5178C18.1018 16.5178 17.7251 16.1412 17.7251 15.6641C17.7251 15.1869 18.1018 14.8103 18.5914 14.8103H26.4514C26.9285 14.8103 27.3052 15.1869 27.3052 15.6641C27.3052 16.1412 26.9285 16.5178 26.4514 16.5178H18.5914ZM14.9 20.9626C14.2346 20.9626 13.6821 20.3976 13.6821 19.7447C13.6821 19.0792 14.2346 18.5268 14.9 18.5268C15.5655 18.5268 16.118 19.0667 16.118 19.7447C16.118 20.4101 15.5655 20.9626 14.9 20.9626ZM18.5914 20.5859C18.1143 20.5859 17.7251 20.2093 17.7251 19.7447C17.7251 19.2676 18.1018 18.8909 18.5914 18.8909H26.4514C26.9285 18.8909 27.3052 19.2676 27.3052 19.7447C27.3052 20.2093 26.9159 20.5859 26.4514 20.5859H18.5914Z" fill="currentColor"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.6 KiB |
3
packages/web/assets/icons/explore.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="41" height="40" viewBox="0 0 41 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20.4999 32.4763C27.594 32.4763 33.4701 26.6127 33.4701 19.5062C33.4701 12.4121 27.594 6.53601 20.4874 6.53601C13.3933 6.53601 7.52979 12.4121 7.52979 19.5062C7.52979 26.6127 13.4059 32.4763 20.4999 32.4763ZM20.4999 30.4674C15.0884 30.4674 10.5055 26.4118 9.67683 21.2012C9.75216 21.2137 9.81494 21.2137 9.89028 21.2137C11.2337 21.2137 12.1252 20.0712 12.1252 18.3259C12.1252 17.7735 12.2257 17.6102 12.5898 17.4344L13.3933 17.0578C13.8202 16.8443 14.2095 17.0076 14.4731 17.3717L15.9673 19.5564C17.3484 21.5528 18.7547 22.3689 20.0479 22.3689C21.2909 22.3689 22.1322 21.5779 22.1322 20.36C22.1322 19.6443 21.7681 19.029 21.1779 18.6398C20.8013 18.3761 20.9143 18.0748 21.2533 18.0748C24.3169 18.0748 25.9366 16.9699 25.9366 14.7475C25.9366 11.8094 23.4505 11.6462 23.4505 10.8929C23.4505 10.4409 24.0156 10.1897 24.4048 9.28573C28.498 10.8803 31.4611 14.8856 31.4611 19.5062C31.4611 20.6613 31.2728 21.7788 30.9338 22.8334C30.2809 22.2935 29.7536 22.0675 29.1383 22.0675C28.6612 22.0675 28.3975 22.1931 28.1339 22.281C27.8702 22.3563 27.7446 22.2433 27.707 22.0173C27.5814 21.1007 27.0038 20.7366 26.0747 20.7366H25.4218C24.6559 20.7366 24.0407 21.1384 23.5761 21.8541L23.3752 22.168C23.0613 22.6577 22.7851 23.0595 22.5089 23.3231C22.2452 23.5617 22.0443 23.6747 21.5295 23.8379L20.9519 24.0137C20.073 24.2899 19.8094 25.0558 20.0479 25.9096L20.6506 28.0315C20.8766 28.81 21.3412 29.2118 22.0945 29.2118C22.421 29.2118 22.8228 29.0862 23.2371 28.8853L23.4254 28.7975C23.7142 28.6593 23.9277 28.6091 24.1411 28.6091C24.6308 28.6091 24.9572 28.8477 25.3339 29.3248C23.8774 30.053 22.2326 30.4674 20.4999 30.4674Z" fill="currentColor"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -1,3 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.89791 17.7681C6.22939 17.7681 6.51566 17.6702 6.8396 17.4818L14.5614 12.9467C15.0059 12.683 15.2846 12.3741 15.375 12.005V16.8867C15.375 17.6024 15.7442 17.9715 16.4599 17.9715H18.2302C18.9459 17.9715 19.315 17.6024 19.315 16.8867V6.52061C19.315 5.78986 18.9459 5.43579 18.2302 5.43579H16.4599C15.7442 5.43579 15.375 5.80493 15.375 6.52061V11.3948C15.2846 11.0256 15.0134 10.7318 14.5614 10.4606L6.8396 5.92547C6.50813 5.73713 6.22939 5.6392 5.89038 5.6392C5.22743 5.6392 4.67749 6.1364 4.67749 7.05549V16.3518C4.67749 17.2709 5.23497 17.7681 5.89791 17.7681Z" fill="currentColor"/>
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.6514 13.6543C19.6426 13.3467 19.5283 13.083 19.291 12.8457L12.4531 6.15723C12.251 5.96387 12.0137 5.8584 11.7236 5.8584C11.1348 5.8584 10.6777 6.31543 10.6777 6.9043C10.6777 7.18555 10.792 7.44922 10.9941 7.65137L17.1465 13.6543L10.9941 19.6572C10.792 19.8594 10.6777 20.1143 10.6777 20.4043C10.6777 20.9932 11.1348 21.4502 11.7236 21.4502C12.0049 21.4502 12.251 21.3447 12.4531 21.1514L19.291 14.4541C19.5371 14.2256 19.6514 13.9619 19.6514 13.6543Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 698 B After Width: | Height: | Size: 590 B |
|
@ -1,3 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19.457 6.143L19.9427 5.26889L19.9426 5.26883L19.457 6.143ZM13.457 2.81L13.9426 1.93583L13.9424 1.93571L13.457 2.81ZM10.543 2.81L10.0576 1.93571L10.0574 1.93583L10.543 2.81ZM4.543 6.143L4.05739 5.26883L4.05728 5.26889L4.543 6.143ZM15 21V22C15.5523 22 16 21.5523 16 21H15ZM9 21H8C8 21.5523 8.44772 22 9 22V21ZM6 20C4.89528 20 4 19.1047 4 18H2C2 20.2093 3.79072 22 6 22V20ZM18 20H6V22H18V20ZM20 18C20 19.1047 19.1047 20 18 20V22C20.2093 22 22 20.2093 22 18H20ZM20 8.76501V18H22V8.76501H20ZM18.9713 7.01712C19.606 7.36984 20 8.03935 20 8.76501H22C22 7.31266 21.212 5.97417 19.9427 5.26889L18.9713 7.01712ZM12.9714 3.68418L18.9714 7.01718L19.9426 5.26883L13.9426 1.93583L12.9714 3.68418ZM11.0284 3.6843C11.6325 3.34891 12.3675 3.34891 12.9716 3.6843L13.9424 1.93571C12.7345 1.2651 11.2655 1.2651 10.0576 1.93571L11.0284 3.6843ZM5.02861 7.01718L11.0286 3.68418L10.0574 1.93583L4.05739 5.26883L5.02861 7.01718ZM4 8.76501C4 8.03854 4.39379 7.36993 5.02872 7.01712L4.05728 5.26889C2.78821 5.97408 2 7.31147 2 8.76501H4ZM4 18V8.76501H2V18H4ZM15 20H9V22H15V20ZM14 14.25V21H16V14.25H14ZM13 13C13.4452 13 14 13.4452 14 14.25H16C16 12.5686 14.7648 11 13 11V13ZM11 13H13V11H11V13ZM10 14.25C10 13.4452 10.5548 13 11 13V11C9.23524 11 8 12.5686 8 14.25H10ZM10 21V14.25H8V21H10Z" fill="currentColor"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.4 KiB |
|
@ -1,6 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 8C4.66667 8 6 8.4 6 10C6 11.6 6 15.3333 6 17C6 17.6667 6.4 19 8 19" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
<circle cx="5.5" cy="4.5" r="1.5" fill="currentColor"/>
|
||||
<path d="M9 5H17C17.6667 5 19 5.4 19 7C19 8.6 19 15 19 18C19 18.6667 18.6 20 17 20M9 8H16" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
<circle cx="12.5" cy="14.5" r="3.5" stroke="currentColor" stroke-width="2"/>
|
||||
<svg width="41" height="40" viewBox="0 0 41 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M28.4478 7.25166H12.5522C12.6275 6.14675 13.293 5.54407 14.4858 5.54407H26.5017C27.707 5.54407 28.3599 6.14675 28.4478 7.25166ZM31.0092 10.8803H9.99079C10.1666 9.68748 10.7693 9.00947 12.1002 9.00947H28.8998C30.2307 9.00947 30.8334 9.68748 31.0092 10.8803ZM29.5151 33.4556H11.4724C8.84821 33.4556 7.49219 32.0996 7.49219 29.5131V16.8694C7.49219 14.2704 8.84821 12.9269 11.4724 12.9269H29.5151C32.1267 12.9269 33.4953 14.2829 33.4953 16.8694V29.5131C33.4953 32.0996 32.1267 33.4556 29.5151 33.4556ZM20.8529 21.5675L23.7 20.8949C24.3235 20.7581 24.5 20.6099 24.5 19.9145V17.589C24.5 17.0988 24.3 16.8936 23.6412 17.0532L20.0647 17.9196C19.4529 18.0678 19.3118 18.2046 19.3118 18.9114V24.0868C19.3118 24.6112 19.2647 24.691 18.6765 24.8392L17.5588 25.1241C16.4059 25.4205 15.5 26.0931 15.5 27.2445C15.5 28.2704 16.3 29 17.5353 29C19.3 29 20.5118 27.7802 20.5118 26.0475V22.1488C20.5118 21.7271 20.5941 21.6359 20.8529 21.5675Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 535 B After Width: | Height: | Size: 1.1 KiB |
|
@ -1,11 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11 18C12.1046 18 13 17.1046 13 16C13 14.8954 12.1046 14 11 14C9.89543 14 9 14.8954 9 16C9 17.1046 9.89543 18 11 18Z" fill="currentColor"/>
|
||||
<path d="M7.15385 3C7.15385 3.55228 6.67169 4 6.07692 4C5.48215 4 5 3.55228 5 3C5 2.44772 5.48215 2 6.07692 2C6.67169 2 7.15385 2.44772 7.15385 3Z" fill="currentColor"/>
|
||||
<path d="M19 3C19 3.55228 18.5178 4 17.9231 4C17.3283 4 16.8462 3.55228 16.8462 3C16.8462 2.44772 17.3283 2 17.9231 2C18.5178 2 19 2.44772 19 3Z" fill="currentColor"/>
|
||||
<path d="M6.07692 2H17.9231V4H6.07692V2Z" fill="currentColor"/>
|
||||
<rect x="11" y="11" width="2" height="5" fill="currentColor"/>
|
||||
<circle cx="12" cy="11" r="1" fill="currentColor"/>
|
||||
<circle cx="14" cy="11" r="1" fill="currentColor"/>
|
||||
<rect x="12" y="10" width="2" height="2" fill="currentColor"/>
|
||||
<path d="M4 10V18C4 19.6569 5.34315 21 7 21H17C18.6569 21 20 19.6569 20 18V10C20 8.34315 18.6569 7 17 7H7C5.34315 7 4 8.34315 4 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
3
packages/web/assets/icons/my.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="41" height="40" viewBox="0 0 41 40" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20.4874 6.53601C13.3934 6.53601 7.52982 12.4121 7.52982 19.5062C7.52982 19.7573 7.54238 19.9958 7.55493 20.2344C8.11994 20.0586 8.72262 19.9582 9.33786 19.9582C12.301 19.9582 14.7996 22.1052 15.3395 24.9177C16.7709 24.1518 18.5538 23.7375 20.5 23.7375C23.8524 23.7375 26.7528 24.9554 28.1967 27.1401C26.2882 29.1867 23.3125 30.3544 20.5 30.3544C18.5287 30.3544 16.5072 29.7768 14.8247 28.7347C14.5108 29.3876 14.0965 29.9651 13.5817 30.4423C15.5906 31.7355 17.9637 32.4763 20.5 32.4763C27.594 32.4763 33.4701 26.6127 33.4701 19.5062C33.4701 12.4121 27.594 6.53601 20.4874 6.53601ZM20.5 21.5653C18.039 21.5528 16.1305 19.4936 16.1305 16.7815C16.118 14.2202 18.0641 12.0857 20.5 12.0857C22.9358 12.0857 24.8694 14.2202 24.8694 16.7815C24.8694 19.4936 22.9609 21.5904 20.5 21.5653ZM9.33786 30.4172C11.7109 30.4172 13.6822 28.4584 13.6822 26.0728C13.6822 23.6998 11.7109 21.7411 9.33786 21.7411C6.96481 21.7411 5.0061 23.6998 5.0061 26.0728C5.0061 28.4584 6.96481 30.4172 9.33786 30.4172Z" fill="currentColor"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -1,6 +0,0 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14Z" fill="currentColor"/>
|
||||
<path d="M14 17C14 15.895 13.105 15 12 15C10.895 15 10 15.895 10 17C10 17.749 10.677 20.83 10.677 20.83L10.683 20.829C10.762 21.49 11.318 22.004 12 22.004C12.682 22.004 13.238 21.49 13.317 20.829L13.323 20.83C13.323 20.83 14 17.741 14 17Z" fill="currentColor"/>
|
||||
<path d="M11.271 6.043C8.675 6.351 6.517 8.397 6.086 10.975C5.83 12.507 6.161 13.953 6.888 15.131C7.322 15.834 8.361 15.775 8.684 15.015C8.808 14.724 8.798 14.386 8.628 14.12C8.037 13.197 7.803 12.029 8.188 10.781C8.597 9.455 9.718 8.412 11.071 8.105C13.679 7.515 16 9.491 16 12C16 12.783 15.764 13.506 15.371 14.121C15.201 14.386 15.193 14.725 15.316 15.015C15.639 15.775 16.678 15.835 17.112 15.132C17.674 14.22 18 13.148 18 12C18 8.451 14.904 5.613 11.271 6.043Z" fill="currentColor"/>
|
||||
<path d="M10.095 2.177C6.08201 2.922 2.87 6.169 2.16 10.189C1.384 14.584 3.502 18.578 6.921 20.601C7.66 21.038 8.572 20.381 8.406 19.539C8.35 19.256 8.17 19.021 7.922 18.873C5.231 17.271 3.551 14.14 4.106 10.682C4.665 7.203 7.58001 4.443 11.081 4.05C15.902 3.511 20 7.286 20 12C20 14.923 18.422 17.48 16.075 18.875C15.828 19.022 15.647 19.257 15.592 19.539C15.426 20.38 16.335 21.041 17.073 20.604C20.019 18.864 22 15.662 22 12C22 5.863 16.443 0.999003 10.095 2.177Z" fill="currentColor"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB |
|
@ -1,4 +1,3 @@
|
|||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="7.5" cy="7.5" r="6.5" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M13.2071 11.7929L12.5 11.0858L11.0858 12.5L11.7929 13.2071L13.2071 11.7929ZM16.2929 17.7071C16.6834 18.0976 17.3166 18.0976 17.7071 17.7071C18.0976 17.3166 18.0976 16.6834 17.7071 16.2929L16.2929 17.7071ZM11.7929 13.2071L16.2929 17.7071L17.7071 16.2929L13.2071 11.7929L11.7929 13.2071Z" fill="currentColor"/>
|
||||
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.5322 19.0332C13.9297 19.0332 15.2393 18.6113 16.3291 17.8906L20.1787 21.749C20.4336 21.9951 20.7588 22.1182 21.1104 22.1182C21.8398 22.1182 22.376 21.5469 22.376 20.8262C22.376 20.4922 22.2617 20.167 22.0156 19.9209L18.1924 16.0801C18.9834 14.9551 19.4492 13.5928 19.4492 12.1162C19.4492 8.31055 16.3379 5.19922 12.5322 5.19922C8.73535 5.19922 5.61523 8.31055 5.61523 12.1162C5.61523 15.9219 8.72656 19.0332 12.5322 19.0332ZM12.5322 17.1875C9.74609 17.1875 7.46094 14.9023 7.46094 12.1162C7.46094 9.33008 9.74609 7.04492 12.5322 7.04492C15.3184 7.04492 17.6035 9.33008 17.6035 12.1162C17.6035 14.9023 15.3184 17.1875 12.5322 17.1875Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 496 B After Width: | Height: | Size: 773 B |
|
@ -1,13 +1,10 @@
|
|||
import React from 'react'
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react'
|
||||
import { NowPlaying } from './NowPlaying'
|
||||
import NowPlaying from './NowPlaying'
|
||||
|
||||
export default {
|
||||
title: 'NowPlaying',
|
||||
component: NowPlaying,
|
||||
argTypes: {
|
||||
backgroundColor: { control: 'color' },
|
||||
},
|
||||
parameters: {
|
||||
viewport: {
|
||||
defaultViewport: 'iphone8p',
|
||||
|
@ -18,7 +15,3 @@ export default {
|
|||
const Template: ComponentStory<typeof NowPlaying> = args => <NowPlaying />
|
||||
|
||||
export const Primary = Template.bind({})
|
||||
Primary.args = {
|
||||
primary: true,
|
||||
label: 'NowPlaying',
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
|||
import cx from 'classnames'
|
||||
import SvgIcon from './SvgIcon'
|
||||
|
||||
export const NowPlaying = () => {
|
||||
const NowPlaying = () => {
|
||||
return (
|
||||
<div className='relative flex aspect-square w-full flex-col justify-end overflow-hidden rounded-3xl'>
|
||||
{/* Cover */}
|
||||
|
@ -38,10 +38,12 @@ export const NowPlaying = () => {
|
|||
|
||||
{/* Controls */}
|
||||
<div className='mt-4 flex w-full items-center justify-between'>
|
||||
<SvgIcon
|
||||
name='shuffle'
|
||||
className='h-7 w-7 text-black/90 dark:text-white/40'
|
||||
/>
|
||||
<button>
|
||||
<SvgIcon
|
||||
name='shuffle'
|
||||
className='h-7 w-7 text-black/90 dark:text-white/40'
|
||||
/>
|
||||
</button>
|
||||
|
||||
<div className='text-black/95 dark:text-white/80'>
|
||||
<button className='rounded-full bg-black/10 p-[10px] dark:bg-white/10'>
|
||||
|
@ -55,12 +57,16 @@ export const NowPlaying = () => {
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<SvgIcon
|
||||
name='repeat-1'
|
||||
className='h-7 w-7 text-black/90 dark:text-white/40'
|
||||
/>
|
||||
<button>
|
||||
<SvgIcon
|
||||
name='repeat-1'
|
||||
className='h-7 w-7 text-black/90 dark:text-white/40'
|
||||
/>{' '}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NowPlaying
|
||||
|
|
16
packages/web/components/Sidebar.stories.tsx
Normal file
|
@ -0,0 +1,16 @@
|
|||
import React from 'react'
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react'
|
||||
import Sidebar from './Sidebar'
|
||||
|
||||
export default {
|
||||
title: 'Sidebar',
|
||||
component: Sidebar,
|
||||
} as ComponentMeta<typeof Sidebar>
|
||||
|
||||
const Template: ComponentStory<typeof Sidebar> = args => (
|
||||
<div className='h-[calc(100vh_-_32px)] w-min rounded-l-3xl bg-[#F8F8F8] dark:bg-black'>
|
||||
<Sidebar />
|
||||
</div>
|
||||
)
|
||||
|
||||
export const Primary = Template.bind({})
|
|
@ -1,107 +1,29 @@
|
|||
import { NavLink } from 'react-router-dom'
|
||||
import SvgIcon from './SvgIcon'
|
||||
import useUserPlaylists from '@/web/hooks/useUserPlaylists'
|
||||
import { scrollToTop } from '@/web/utils/common'
|
||||
import { prefetchPlaylist } from '@/web/hooks/usePlaylist'
|
||||
import { player } from '@/web/store'
|
||||
import { Mode, TrackListSourceType } from '@/web/utils/player'
|
||||
import React from 'react'
|
||||
import cx from 'classnames'
|
||||
import { useMemo } from 'react'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
const primaryTabs = [
|
||||
{
|
||||
name: '主页',
|
||||
icon: 'home',
|
||||
route: '/',
|
||||
},
|
||||
{
|
||||
name: '播客',
|
||||
icon: 'podcast',
|
||||
route: '/podcast',
|
||||
},
|
||||
{
|
||||
name: '音乐库',
|
||||
icon: 'music-library',
|
||||
route: '/library',
|
||||
},
|
||||
] as const
|
||||
|
||||
const PrimaryTabs = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className={cx(window.env?.isMac && 'app-region-drag', 'h-14')}></div>
|
||||
{primaryTabs.map(tab => (
|
||||
<NavLink
|
||||
onClick={() => scrollToTop()}
|
||||
key={tab.route}
|
||||
to={tab.route}
|
||||
className={({ isActive }) =>
|
||||
cx(
|
||||
'btn-hover-animation mx-3 flex cursor-default items-center rounded-lg px-3 py-2 transition-colors duration-200 after:scale-[0.97] after:bg-black/[.06] dark:after:bg-white/20',
|
||||
!isActive && 'text-gray-700 dark:text-white',
|
||||
isActive && 'text-brand-500 '
|
||||
)
|
||||
}
|
||||
>
|
||||
<SvgIcon className='mr-3 h-6 w-6' name={tab.icon} />
|
||||
<span className='font-semibold'>{tab.name}</span>
|
||||
</NavLink>
|
||||
))}
|
||||
|
||||
<div className='mx-5 my-2 h-px bg-black opacity-5 dark:bg-white dark:opacity-10'></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Playlists = () => {
|
||||
const { data: playlists } = useUserPlaylists()
|
||||
const playerSnapshot = useSnapshot(player)
|
||||
const currentPlaylistID = useMemo(
|
||||
() => playerSnapshot.trackListSource?.id,
|
||||
[playerSnapshot.trackListSource]
|
||||
)
|
||||
const playlistMode = useMemo(
|
||||
() => playerSnapshot.trackListSource?.type,
|
||||
[playerSnapshot.trackListSource]
|
||||
)
|
||||
const mode = useMemo(() => playerSnapshot.mode, [playerSnapshot.mode])
|
||||
|
||||
return (
|
||||
<div className='mb-16 overflow-auto pb-2'>
|
||||
{playlists?.playlist?.map(playlist => (
|
||||
<NavLink
|
||||
onMouseOver={() => prefetchPlaylist({ id: playlist.id })}
|
||||
key={playlist.id}
|
||||
onClick={() => scrollToTop()}
|
||||
to={`/playlist/${playlist.id}`}
|
||||
className={({ isActive }: { isActive: boolean }) =>
|
||||
cx(
|
||||
'btn-hover-animation line-clamp-1 my-px mx-3 flex cursor-default items-center justify-between rounded-lg px-3 py-[0.38rem] text-sm text-black opacity-70 transition-colors duration-200 after:scale-[0.97] after:bg-black/[.06] dark:text-white dark:after:bg-white/20',
|
||||
isActive && 'after:scale-100 after:opacity-100'
|
||||
)
|
||||
}
|
||||
>
|
||||
<span className='line-clamp-1'>{playlist.name}</span>
|
||||
{playlistMode === TrackListSourceType.Playlist &&
|
||||
mode === Mode.TrackList &&
|
||||
currentPlaylistID === playlist.id && (
|
||||
<SvgIcon className='h-5 w-5' name='volume-half' />
|
||||
)}
|
||||
</NavLink>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
import SvgIcon from './SvgIcon'
|
||||
|
||||
const Sidebar = () => {
|
||||
return (
|
||||
<div
|
||||
id='sidebar'
|
||||
className='grid h-screen max-w-sm grid-rows-[12rem_auto] border-r border-gray-300/10 bg-gray-50 bg-opacity-[.85] dark:border-gray-500/10 dark:bg-gray-900 dark:bg-opacity-80'
|
||||
>
|
||||
<PrimaryTabs />
|
||||
<Playlists />
|
||||
<div className='relative flex h-full w-[104px] flex-col justify-center'>
|
||||
<div className='grid grid-cols-1 justify-items-center gap-12 text-black/10 dark:text-white/20'>
|
||||
<SvgIcon
|
||||
name='my'
|
||||
className='h-10 w-10 text-brand-600 dark:text-brand-700'
|
||||
/>
|
||||
<SvgIcon name='explore' className='h-10 w-10' />
|
||||
<SvgIcon name='discovery' className='h-10 w-10' />
|
||||
<SvgIcon name='lyrics' className='h-10 w-10' />
|
||||
</div>
|
||||
<div
|
||||
className='absolute bottom-8 right-0 left-0 flex rotate-180 items-center font-medium text-brand-600 dark:text-brand-700'
|
||||
style={{
|
||||
writingMode: 'vertical-rl',
|
||||
textOrientation: 'mixed',
|
||||
letterSpacing: '0.5px',
|
||||
}}
|
||||
>
|
||||
<span>USER PAGE</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
16
packages/web/components/Topbar.stories.tsx
Normal file
|
@ -0,0 +1,16 @@
|
|||
import React from 'react'
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react'
|
||||
import Topbar from './Topbar'
|
||||
|
||||
export default {
|
||||
title: 'Topbar',
|
||||
component: Topbar,
|
||||
} as ComponentMeta<typeof Topbar>
|
||||
|
||||
const Template: ComponentStory<typeof Topbar> = args => (
|
||||
<div className='w-[calc(100vw_-_32px)] rounded-3xl bg-[#F8F8F8] px-11 dark:bg-black'>
|
||||
<Topbar />
|
||||
</div>
|
||||
)
|
||||
|
||||
export const Primary = Template.bind({})
|
|
@ -1,114 +1,44 @@
|
|||
import SvgIcon from '@/web/components/SvgIcon'
|
||||
import useScroll from '@/web/hooks/useScroll'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
import Avatar from './Avatar'
|
||||
import cx from 'classnames'
|
||||
|
||||
const NavigationButtons = () => {
|
||||
const navigate = useNavigate()
|
||||
enum ACTION {
|
||||
Back = 'back',
|
||||
Forward = 'forward',
|
||||
}
|
||||
const handleNavigate = (action: ACTION) => {
|
||||
if (action === ACTION.Back) navigate(-1)
|
||||
if (action === ACTION.Forward) navigate(1)
|
||||
}
|
||||
return (
|
||||
<div className='flex gap-1'>
|
||||
{[ACTION.Back, ACTION.Forward].map(action => (
|
||||
<div
|
||||
onClick={() => handleNavigate(action)}
|
||||
key={action}
|
||||
className='app-region-no-drag btn-hover-animation rounded-lg p-2 text-gray-500 transition duration-300 after:rounded-full after:bg-black/[.06] hover:text-gray-900 dark:text-gray-300 dark:after:bg-white/10 dark:hover:text-gray-200'
|
||||
>
|
||||
<SvgIcon className='h-5 w-5' name={action} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const SearchBox = () => {
|
||||
const { type } = useParams()
|
||||
const [keywords, setKeywords] = useState('')
|
||||
const navigate = useNavigate()
|
||||
const toSearch = (e: React.KeyboardEvent) => {
|
||||
if (!keywords) return
|
||||
if (e.key === 'Enter') {
|
||||
navigate(`/search/${keywords}${type ? `/${type}` : ''}`)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='app-region-no-drag group flex w-[16rem] cursor-text items-center rounded-full bg-gray-500 bg-opacity-5 pl-2.5 pr-2 transition duration-300 hover:bg-opacity-10 dark:bg-gray-300 dark:bg-opacity-5'>
|
||||
<SvgIcon
|
||||
className='mr-2 h-4 w-4 text-gray-500 transition duration-300 group-hover:text-gray-600 dark:text-gray-400 dark:group-hover:text-gray-200'
|
||||
name='search'
|
||||
/>
|
||||
<input
|
||||
value={keywords}
|
||||
onChange={e => setKeywords(e.target.value)}
|
||||
onKeyDown={toSearch}
|
||||
type='text'
|
||||
className='flex-grow bg-transparent placeholder:text-gray-500 dark:text-white dark:placeholder:text-gray-400'
|
||||
placeholder='搜索'
|
||||
/>
|
||||
<div
|
||||
onClick={() => setKeywords('')}
|
||||
className={cx(
|
||||
'cursor-default rounded-full p-1 text-gray-600 transition hover:bg-gray-400/20 dark:text-white/50 dark:hover:bg-white/20',
|
||||
!keywords && 'hidden'
|
||||
)}
|
||||
>
|
||||
<SvgIcon className='h-4 w-4' name='x' />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Settings = () => {
|
||||
const navigate = useNavigate()
|
||||
return (
|
||||
<div
|
||||
onClick={() => navigate('/settings')}
|
||||
className='app-region-no-drag btn-hover-animation rounded-lg p-2.5 text-gray-500 transition duration-300 after:rounded-full after:bg-black/[.06] hover:text-gray-900 dark:text-gray-300 dark:after:bg-white/10 dark:hover:text-gray-200'
|
||||
>
|
||||
<SvgIcon className='h-[1.125rem] w-[1.125rem]' name='settings' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
import SvgIcon from './SvgIcon'
|
||||
|
||||
const Topbar = () => {
|
||||
/**
|
||||
* Show topbar background when scroll down
|
||||
*/
|
||||
const [mainContainer, setMainContainer] = useState<HTMLElement | null>(null)
|
||||
const scroll = useScroll(mainContainer, { throttle: 100 })
|
||||
|
||||
useEffect(() => {
|
||||
setMainContainer(document.getElementById('mainContainer'))
|
||||
}, [setMainContainer])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
'sticky z-30 flex h-16 min-h-[4rem] w-full cursor-default items-center justify-between px-8 transition duration-300',
|
||||
window.env?.isMac && 'app-region-drag',
|
||||
window.env?.isEnableTitlebar ? 'top-8' : 'top-0',
|
||||
!scroll.arrivedState.top &&
|
||||
'bg-white bg-opacity-[.86] backdrop-blur-xl backdrop-saturate-[1.8] dark:bg-[#222] dark:bg-opacity-[.86]'
|
||||
)}
|
||||
>
|
||||
<div className='flex gap-2'>
|
||||
<NavigationButtons />
|
||||
<SearchBox />
|
||||
<div className='flex w-full items-center justify-between pt-11 pb-10'>
|
||||
{/* Left Part */}
|
||||
<div className='flex items-center'>
|
||||
{/* Navigation Buttons */}
|
||||
<button className='rounded-full bg-[#E9E9E9] p-[10px] dark:bg-[#0E0E0E]'>
|
||||
<SvgIcon name='back' className='h-7 w-7 text-[#717171]' />
|
||||
</button>
|
||||
<button className='ml-[10px] rounded-full bg-[#E9E9E9] p-[10px] dark:bg-[#0E0E0E]'>
|
||||
<SvgIcon name='forward' className='h-7 w-7 text-[#717171]' />
|
||||
</button>
|
||||
|
||||
{/* Dividing line */}
|
||||
<div className='mx-6 h-4 w-px bg-black/20 dark:bg-white/20'></div>
|
||||
|
||||
{/* Search Box */}
|
||||
<div className='flex min-w-[284px] items-center rounded-full bg-[#E9E9E9] p-[10px] text-[#717171] dark:bg-[#0E0E0E]'>
|
||||
<SvgIcon name='search' className='mr-[10px] h-7 w-7' />
|
||||
<input
|
||||
placeholder='Search Song Name'
|
||||
className='bg-transparent placeholder:text-[#717171]'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex items-center gap-3'>
|
||||
<Settings />
|
||||
<Avatar />
|
||||
{/* Right Part */}
|
||||
<div className='flex'>
|
||||
<button className='rounded-full bg-[#E9E9E9] p-[10px] dark:bg-[#0E0E0E]'>
|
||||
<SvgIcon name='placeholder' className='h-7 w-7 text-[#717171]' />
|
||||
</button>
|
||||
|
||||
{/* Avatar */}
|
||||
<div>
|
||||
<img
|
||||
className='ml-3 h-12 w-12 rounded-full'
|
||||
src='http://p1.music.126.net/AetIV1GOZiLKk1yy8PMPfw==/109951165378042240.jpg'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -88,7 +88,7 @@
|
|||
url('@/web/assets/fonts/Barlow-Black.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@100;300;400;500;700;900&display=swap');
|
||||
|
||||
body,
|
||||
input {
|
||||
|
|