diff --git a/packages/alto/src/components/Loader/Loader.vue b/packages/alto/src/components/Loader/Loader.vue index 0c573db5..7cf2adc5 100644 --- a/packages/alto/src/components/Loader/Loader.vue +++ b/packages/alto/src/components/Loader/Loader.vue @@ -15,44 +15,23 @@ withDefaults( -.loader-block .label.xl { - font: var(--text-xl-regular); -} + diff --git a/packages/alto/src/components/Loader/internal/Bar.vue b/packages/alto/src/components/Loader/internal/Bar.vue index 9d1a39d9..f2f0b284 100644 --- a/packages/alto/src/components/Loader/internal/Bar.vue +++ b/packages/alto/src/components/Loader/internal/Bar.vue @@ -5,31 +5,11 @@ defineProps(); diff --git a/packages/alto/src/components/Loader/internal/Brand.vue b/packages/alto/src/components/Loader/internal/Brand.vue index df37a394..7d99552d 100644 --- a/packages/alto/src/components/Loader/internal/Brand.vue +++ b/packages/alto/src/components/Loader/internal/Brand.vue @@ -12,17 +12,20 @@ const width = computed(() => `${props.size}px`); diff --git a/packages/alto/src/components/Radio/Internal/Radio.vue b/packages/alto/src/components/Radio/Internal/Radio.vue index b688c532..81977f1c 100644 --- a/packages/alto/src/components/Radio/Internal/Radio.vue +++ b/packages/alto/src/components/Radio/Internal/Radio.vue @@ -20,54 +20,10 @@ const id = Utils.uid('radio_'); - - diff --git a/packages/alto/src/components/Radio/RadioGroup.vue b/packages/alto/src/components/Radio/RadioGroup.vue index e1a761c1..f6ba4645 100644 --- a/packages/alto/src/components/Radio/RadioGroup.vue +++ b/packages/alto/src/components/Radio/RadioGroup.vue @@ -22,7 +22,7 @@ const handleRadioCheck = (radio: RadioData) => model.value = radio.value; - diff --git a/packages/alto/src/components/RadioList/RadioList.vue b/packages/alto/src/components/RadioList/RadioList.vue index 84d84267..c0447c23 100644 --- a/packages/alto/src/components/RadioList/RadioList.vue +++ b/packages/alto/src/components/RadioList/RadioList.vue @@ -13,68 +13,15 @@ const model = computed({ diff --git a/packages/alto/src/components/Skeleton/Skeleton.stories.ts b/packages/alto/src/components/Skeleton/Skeleton.stories.ts index b697abb7..66232740 100644 --- a/packages/alto/src/components/Skeleton/Skeleton.stories.ts +++ b/packages/alto/src/components/Skeleton/Skeleton.stories.ts @@ -9,7 +9,7 @@ const meta: Meta = { argTypes: { type: { control: 'select', - options: ['text', 'media'], + options: ['text', 'media', 'card'], }, lines: { control: { type: 'number' }, diff --git a/packages/alto/src/components/Skeleton/Skeleton.vue b/packages/alto/src/components/Skeleton/Skeleton.vue index d4e4fd5c..06c62244 100644 --- a/packages/alto/src/components/Skeleton/Skeleton.vue +++ b/packages/alto/src/components/Skeleton/Skeleton.vue @@ -11,77 +11,17 @@ withDefaults( diff --git a/packages/styles/package.json b/packages/styles/package.json index b3707498..b0ad9d00 100644 --- a/packages/styles/package.json +++ b/packages/styles/package.json @@ -13,7 +13,11 @@ "./alert": "./dist/alert.css", "./checkbox": "./dist/checkbox.css", "./badge": "./dist/badge.css", - "./divider": "./dist/divider.css" + "./divider": "./dist/divider.css", + "./radio-list": "./dist/radio-list.css", + "./loader": "./dist/loader.css", + "./radio-group": "./dist/radio-group.css", + "./skeleton": "./dist/skeleton.css" }, "files": [ "dist" diff --git a/packages/styles/src/css/index.css b/packages/styles/src/css/index.css index 3da562fe..93d362aa 100644 --- a/packages/styles/src/css/index.css +++ b/packages/styles/src/css/index.css @@ -1,3 +1,223 @@ +.alert { + --border-left-color: var(--orange-500); + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: stretch; + position: relative; + box-sizing: border-box; + width: 400px; + max-width: 100%; + margin-bottom: 12px; + padding: 12px; + overflow: hidden; + border: 1px solid var(--gray-200); + border-left-width: 0; + border-radius: 4px; + background-color: var(--base-white); + box-shadow: var(--shadow-xs-gray); + gap: 8px; +} +.alert::before { + content: ""; + position: absolute; + top: 0; + left: 0; + width: 4px; + height: 100%; + background-color: var(--border-left-color); +} +.alert.success { + --border-left-color: var(--green-600); +} +.alert.info { + --border-left-color: var(--blue-500); +} +.alert.error { + --border-left-color: var(--red-500); +} +.alert .content-container { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: stretch; + width: 100%; + gap: 4px; +} +.alert .content-container .description { + color: var(--gray-900); + font: var(--text-sm-regular); + padding-bottom: 4px; +} +.alert .icon { + width: 18px; + height: 18px; + color: var(--orange-500); +} +.alert .icon.success { + color: var(--green-600); +} +.alert .icon.info { + color: var(--blue-500); +} +.alert .icon.error { + color: var(--red-500); +} +.alert .close-button { + padding: 0; + color: var(--gray-500); + cursor: pointer; +} +.alert .main { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: stretch; + width: 100%; + gap: 8px; +} +.alert .title { + font: var(--text-sm-medium); +} +.alert .title.success { + color: var(--green-600); +} +.alert .title.info { + color: var(--blue-500); +} +.alert .title.error { + color: var(--red-500); +} +.alert .title.warning { + color: var(--orange-500); +} + +.avatar-wrapper { + --size: 56px; + --icon-size: 26px; + --font: var(--text-xl-medium); + display: flex; + align-items: center; + margin: 0; + padding: 0; + border: 0; + outline: none; + background-color: transparent; + gap: 10px; +} +.avatar-wrapper.avatar-xs { + --size: 24px; + --icon-size: 13px; + --font: var(--text-xs-medium); +} +.avatar-wrapper.avatar-sm { + --size: 32px; + --icon-size: 16px; + --font: var(--text-sm-medium); +} +.avatar-wrapper.avatar-md { + --size: 40px; + --icon-size: 20px; + --font: var(--text-md-medium); +} +.avatar-wrapper.avatar-lg { + --size: 48px; + --icon-size: 23px; + --font: var(--text-lg-medium); +} +.avatar-wrapper.avatar-xxl { + --size: 64px; + --font: var(--display-xs-medium); +} +.avatar-wrapper .avatar { + display: flex; + position: relative; + align-items: center; + justify-content: center; + width: var(--size); + height: var(--size); + overflow: hidden; + transition: opacity 150ms ease-in-out; + border: 1px solid transparent; + border-radius: 50%; + opacity: 1; + background-color: var(--brand-50); +} +.avatar-wrapper .avatar img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center bottom; +} +.avatar-wrapper .avatar-initials { + color: var(--brand-500); + font: var(--font); + text-transform: uppercase; +} +.avatar-wrapper .avatar img, .avatar-wrapper .avatar-.initials { + position: relative; + z-index: 1; +} +.avatar-wrapper .avatar-initials i { + width: var(--icon-size); + height: var(--icon-size); +} +.avatar-wrapper .avatar a[href] { + position: absolute; + z-index: 2; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.avatar-wrapper.clickable .avatar { + cursor: pointer; +} +.avatar-wrapper.clickable .avatar:hover { + opacity: 0.9; +} +.avatar-wrapper.clickable:focus .avatar { + border: 1px solid var(--brand-500); + box-shadow: var(--focus-shadow-xs-red); +} + +.badge { + --background-color: var(--gray-300); + --size: 24px; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + width: min-content; + height: var(--size); + padding: 0 6px; + border-radius: 100px; + background-color: var(--background-color); + color: var(--base-white); + font: var(--text-sm-medium); +} +.badge.size-sm { + --size: 20px; +} +.badge.size-md { + --size: 24px; +} +.badge.state-neutral { + --background-color: var(--gray-500); +} +.badge.state-danger { + --background-color: var(--red-500); +} +.badge.state-info { + --background-color: var(--blue-500); +} +.badge.state-warning { + --background-color: var(--yellow-500); +} +.badge.state-success { + --background-color: var(--green-600); +} + .button { --text-color: var(--base-white); --background-color: var(--base-black); @@ -159,3 +379,144 @@ .button.secondary.size-lg, .button.tertiary.size-lg { --text-style: var(--text-md-medium); } + +.action-button { + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + border: 1px solid var(--gray-200); + border-radius: 50%; + outline: none; + background-color: var(--base-white); + cursor: pointer; +} +.action-button i { + width: 18px; + height: 18px; + color: var(--gray-500); +} +.action-button:hover, .action-button:active { + border: 1px solid var(--gray-300); + background-color: var(--gray-50); +} +.action-button:focus { + border: 1px solid var(--brand-500); + box-shadow: var(--focus-shadow-xs-brand); +} + +.checkbox-content { + display: flex; + align-items: center; +} +.checkbox-content .label { + display: inline-block; + flex: 1; + font: var(--text-sm-regular); + cursor: pointer; +} +.checkbox-content .checkbox { + display: block; + box-sizing: border-box; + cursor: pointer; + user-select: none; +} +.checkbox-content .checkbox.has-label { + margin-inline-end: 8px; +} +.checkbox-content .checkbox .input { + position: absolute; + opacity: 0; +} +.checkbox-content .checkbox .checkmark { + display: grid; + width: 16px; + height: 16px; + border: 1px solid var(--gray-200); + border-radius: 4px; + background-color: var(--base-white); + box-shadow: var(--shadow-xs-gray); + place-items: center; +} +.checkbox-content .checkbox .checkmark i { + display: none; + width: 14px; + height: 14px; + color: var(--base-white); +} +.checkbox-content .checkbox input:checked ~ .checkmark { + border: 1px solid transparent; + background-color: var(--brand-500); +} +.checkbox-content .checkbox input:checked ~ .checkmark i { + display: inline-block; +} +.checkbox-content .checkbox input:disabled ~ .checkmark { + border: 1px solid var(--gray-200); + background: var(--base-white); + box-shadow: none; + cursor: default; +} +.checkbox-content .checkbox input:enabled:is(:focus, :active) ~ .checkmark { + box-shadow: var(--focus-shadow-xs-brand); +} +.checkbox-content:hover .checkbox input:enabled ~ .checkmark { + background-color: var(--gray-50); +} +.checkbox-content .checkbox input:disabled:checked ~ .checkmark { + background-color: var(--gray-100); +} +.checkbox-content:hover .checkbox input:enabled:checked ~ .checkmark { + background-color: var(--brand-600); +} +.checkbox-content .checkbox:has(.input:disabled) ~ .label { + color: var(--gray-300); +} + +.radio-list { + display: flex; + box-sizing: border-box; + flex-direction: column; + gap: 8px; +} +.radio-list__item { + display: flex; + align-items: center; + gap: 8px; + padding: 11.5px 16px; + border: 1px solid var(--gray-200); + border-radius: 8px; + box-shadow: var(--shadow-xs-gray); + cursor: pointer; +} +.radio-list__item__name, .radio-list__item__suffix { + color: var(--gray-900); + font: var(--text-sm-regular); +} +.radio-list__item__name { + flex-grow: 1; +} +.radio-list__item__trigger { + width: 14px; + height: 14px; + margin: 0; + transition: 75ms all linear; + border: 1px solid var(--gray-200); + border-radius: 50%; + outline: 2px solid var(--base-white); + background-color: var(--base-white); + appearance: none; +} +.radio-list__item__trigger:hover { + border-color: var(--gray-300); + background-color: var(--gray-50); +} +.radio-list__item__trigger:active { + background-color: var(--gray-100); +} +.radio-list__item__trigger:checked { + border: 3px solid var(--base-white); + outline-color: var(--brand-500); + background-color: var(--brand-500); +} diff --git a/packages/styles/src/css/loader.css b/packages/styles/src/css/loader.css new file mode 100644 index 00000000..49f1d6f9 --- /dev/null +++ b/packages/styles/src/css/loader.css @@ -0,0 +1,85 @@ +.loader { + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; +} +.loader__label { + margin: 0; + color: var(--brand-500); + font: var(--text-md-regular); +} +.loader__label--xs { + font: var(--text-xs-regular); +} +.loader__label--sm { + font: var(--text-sm-regular); +} +.loader__label--lg { + font: var(--text-lg-regular); +} +.loader__label--xl { + font: var(--text-xl-regular); +} +.loader__bar { + position: relative; + width: 160px; + height: 4px; + overflow: hidden; + border-radius: 2px; + background-color: var(--gray-100); +} +.loader__bar::before { + content: ""; + display: block; + width: 100%; + height: 100%; + animation: progress 1200ms ease-in-out backwards alternate infinite; + border-radius: 2px; + background-color: var(--brand-500); +} +.loader__brand { + stroke: var(--brand-500); + fill: var(--brand-500); +} +.loader__brand path { + animation: draw 1500ms linear forwards infinite; + stroke-dasharray: 163.58; + fill: var(--gray-100); +} +.loader__spinner { + box-sizing: border-box; + width: 50px; + animation: s4 1s infinite linear; + border: 4px solid var(--gray-100); + border-radius: 50%; + border-right-color: var(--brand-500); + aspect-ratio: 1; +} + +@keyframes progress { + 0% { + transform: translateX(-93%); + } + 100% { + transform: translateX(93%); + } +} +@keyframes draw { + 0% { + stroke-dashoffset: 163.58; + } + 40%, 50% { + stroke-dashoffset: 0; + fill: var(--gray-100); + } + 85%, 100% { + stroke-dashoffset: 0; + fill: var(--brand-500); + } +} +@keyframes s4 { + 100% { + transform: rotate(1turn); + } +} diff --git a/packages/styles/src/css/radio-group.css b/packages/styles/src/css/radio-group.css new file mode 100644 index 00000000..cdeecdfc --- /dev/null +++ b/packages/styles/src/css/radio-group.css @@ -0,0 +1,39 @@ +.radio-group { + all: unset; + box-sizing: border-box; +} +.radio-group__item { + display: flex; + box-sizing: border-box; + align-items: center; + gap: 8px; +} +.radio-group__item__label { + color: var(--gray-900); + font: var(--text-sm-regular); + cursor: pointer; +} +.radio-group__item__trigger { + width: 18px; + height: 18px; + margin: 0; + transition: 75ms all linear; + border: 1px solid var(--gray-200); + border-radius: 50%; + background-color: var(--base-white); + appearance: none; + cursor: pointer; +} +.radio-group__item__trigger:hover { + border-color: var(--gray-300); + background-color: var(--gray-50); +} +.radio-group__item__trigger:active { + background-color: var(--gray-100); +} +.radio-group__item__trigger:checked { + border: 4px solid var(--brand-500); +} +.radio-group__item__trigger:checked:hover { + border-color: var(--brand-600); +} diff --git a/packages/styles/src/css/radio-list.css b/packages/styles/src/css/radio-list.css new file mode 100644 index 00000000..a88ede69 --- /dev/null +++ b/packages/styles/src/css/radio-list.css @@ -0,0 +1,46 @@ +.radio-list { + display: flex; + box-sizing: border-box; + flex-direction: column; + gap: 8px; +} +.radio-list__item { + display: flex; + align-items: center; + gap: 8px; + padding: 11.5px 16px; + border: 1px solid var(--gray-200); + border-radius: 8px; + box-shadow: var(--shadow-xs-gray); + cursor: pointer; +} +.radio-list__item__name, .radio-list__item__suffix { + color: var(--gray-900); + font: var(--text-sm-regular); +} +.radio-list__item__name { + flex-grow: 1; +} +.radio-list__item__trigger { + width: 14px; + height: 14px; + margin: 0; + transition: 75ms all linear; + border: 1px solid var(--gray-200); + border-radius: 50%; + outline: 2px solid var(--base-white); + background-color: var(--base-white); + appearance: none; +} +.radio-list__item__trigger:hover { + border-color: var(--gray-300); + background-color: var(--gray-50); +} +.radio-list__item__trigger:active { + background-color: var(--gray-100); +} +.radio-list__item__trigger:checked { + border: 3px solid var(--base-white); + outline-color: var(--brand-500); + background-color: var(--brand-500); +} diff --git a/packages/styles/src/css/skeleton.css b/packages/styles/src/css/skeleton.css new file mode 100644 index 00000000..08628861 --- /dev/null +++ b/packages/styles/src/css/skeleton.css @@ -0,0 +1,51 @@ +.skeleton__pulse { + animation: blink 2s linear infinite; +} +.skeleton__content { + display: flex; + flex-direction: column; + width: 100%; + row-gap: 15px; + justify-items: flex-start; +} +.skeleton__content__line { + height: 1.2vh; + border-bottom: 1px solid var(--gray-300); + background-color: var(--gray-300); +} +.skeleton__content .yc-skeleton__pulse:last-child { + width: 80%; +} +.skeleton__media, .skeleton__card { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + min-height: 40px; + border-radius: 6px; + background-color: var(--gray-200); +} +.skeleton__media__icon { + min-width: 80px; + min-height: 80px; + color: var(--gray-300); +} + +@keyframes blink { + 0% { + opacity: 0.3; + } + 25% { + opacity: 0.7; + } + 50% { + opacity: 1; + } + 75% { + opacity: 0.7; + } + 100% { + opacity: 0.3; + } +} diff --git a/packages/styles/src/scss/components/loader.scss b/packages/styles/src/scss/components/loader.scss new file mode 100644 index 00000000..d535e846 --- /dev/null +++ b/packages/styles/src/scss/components/loader.scss @@ -0,0 +1,95 @@ +.loader { + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + + &__label { + margin: 0; + color: var(--brand-500); + font: var(--text-md-regular); + + &--xs { + font: var(--text-xs-regular); + } + + &--sm { + font: var(--text-sm-regular); + } + + &--lg { + font: var(--text-lg-regular); + } + + &--xl { + font: var(--text-xl-regular); + } + } + + &__bar { + position: relative; + width: 160px; + height: 4px; + overflow: hidden; + border-radius: 2px; + background-color: var(--gray-100); + + &::before { + content: ""; + display: block; + width: 100%; + height: 100%; + animation: progress 1200ms ease-in-out backwards alternate infinite; + border-radius: 2px; + background-color: var(--brand-500); + } + } + + &__brand { + stroke: var(--brand-500); + fill: var(--brand-500); + + path { + animation: draw 1500ms linear forwards infinite; + stroke-dasharray: 163.58; + fill: var(--gray-100); + } + } + + &__spinner { + box-sizing: border-box; + width: 50px; + animation: s4 1s infinite linear; + border: 4px solid var(--gray-100); + border-radius: 50%; + border-right-color: var(--brand-500); + aspect-ratio: 1; + } +} + +@keyframes progress { + 0% { transform: translateX(-93%); } + 100% { transform: translateX(93%); } +} + +@keyframes draw { + 0% { stroke-dashoffset: 163.58; } + + 40%, + 50% { + stroke-dashoffset: 0; + fill: var(--gray-100); + } + + 85%, + 100% { + stroke-dashoffset: 0; + fill: var(--brand-500); + } +} + +@keyframes s4 { + 100% { + transform: rotate(1turn); + } +} diff --git a/packages/styles/src/scss/components/radio-group.scss b/packages/styles/src/scss/components/radio-group.scss new file mode 100644 index 00000000..30d1e4c8 --- /dev/null +++ b/packages/styles/src/scss/components/radio-group.scss @@ -0,0 +1,46 @@ +.radio-group { + all: unset; + box-sizing: border-box; + + &__item { + display: flex; + box-sizing: border-box; + align-items: center; + gap: 8px; + + &__label { + color: var(--gray-900); + font: var(--text-sm-regular); + cursor: pointer; + } + + &__trigger { + width: 18px; + height: 18px; + margin: 0; + transition: 75ms all linear; + border: 1px solid var(--gray-200); + border-radius: 50%; + background-color: var(--base-white); + appearance: none; + cursor: pointer; + + &:hover { + border-color: var(--gray-300); + background-color: var(--gray-50); + } + + &:active { + background-color: var(--gray-100); + } + + &:checked { + border: 4px solid var(--brand-500); + + &:hover { + border-color: var(--brand-600); + } + } + } + } +} diff --git a/packages/styles/src/scss/components/radio-list.scss b/packages/styles/src/scss/components/radio-list.scss new file mode 100644 index 00000000..5da53b3c --- /dev/null +++ b/packages/styles/src/scss/components/radio-list.scss @@ -0,0 +1,54 @@ +.radio-list { + display: flex; + box-sizing: border-box; + flex-direction: column; + gap: 8px; + + &__item { + display: flex; + align-items: center; + gap: 8px; + padding: 11.5px 16px; + border: 1px solid var(--gray-200); + border-radius: 8px; + box-shadow: var(--shadow-xs-gray); + cursor: pointer; + + &__name, + &__suffix { + color: var(--gray-900); + font: var(--text-sm-regular); + } + + &__name { + flex-grow: 1; + } + + &__trigger { + width: 14px; + height: 14px; + margin: 0; + transition: 75ms all linear; + border: 1px solid var(--gray-200); + border-radius: 50%; + outline: 2px solid var(--base-white); + background-color: var(--base-white); + appearance: none; + + &:hover { + border-color: var(--gray-300); + background-color: var(--gray-50); + } + + &:active { + background-color: var(--gray-100); + } + + &:checked { + border: 3px solid var(--base-white); + outline-color: var(--brand-500); + background-color: var(--brand-500); + } + } + } +} diff --git a/packages/styles/src/scss/components/skeleton.scss b/packages/styles/src/scss/components/skeleton.scss new file mode 100644 index 00000000..ed1030cd --- /dev/null +++ b/packages/styles/src/scss/components/skeleton.scss @@ -0,0 +1,65 @@ +.skeleton { + &__pulse { + animation: blink 2s linear infinite; + } + + &__content { + display: flex; + flex-direction: column; + width: 100%; + row-gap: 15px; + justify-items: flex-start; + + &__line { + height: 1.2vh; + border-bottom: 1px solid var(--gray-300); + background-color: var(--gray-300); + } + + .yc-skeleton__pulse:last-child { + width: 80%; + } + } + + &__media, + &__card { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + min-height: 40px; + border-radius: 6px; + background-color: var(--gray-200); + } + + &__media { + &__icon { + min-width: 80px; + min-height: 80px; + color: var(--gray-300); + } + } +} + +@keyframes blink { + 0% { + opacity: 0.3; + } + + 25% { + opacity: 0.7; + } + + 50% { + opacity: 1; + } + + 75% { + opacity: 0.7; + } + + 100% { + opacity: 0.3; + } +} diff --git a/packages/styles/src/scss/index.scss b/packages/styles/src/scss/index.scss index f475220d..7c08252a 100644 --- a/packages/styles/src/scss/index.scss +++ b/packages/styles/src/scss/index.scss @@ -1 +1,7 @@ -@import 'components/button'; +@import "components/alert"; +@import "components/avatar"; +@import "components/badge"; +@import "components/button"; +@import "components/action-button"; +@import "components/checkbox"; +@import "components/radio-list";