From a10f6dea891358129b018206d00cb14446d51521 Mon Sep 17 00:00:00 2001 From: LeoKu Date: Sat, 16 Apr 2022 14:15:19 +0800 Subject: [PATCH] feat: support color pick --- src/assets/widgets/clothes/collared.svg | 4 +- src/assets/widgets/clothes/crew.svg | 4 +- src/assets/widgets/clothes/open.svg | 4 +- src/assets/widgets/tops/danny.svg | 4 +- src/assets/widgets/tops/fonze.svg | 12 ++--- src/assets/widgets/tops/funny.svg | 2 +- src/assets/widgets/tops/pixie.svg | 4 +- src/assets/widgets/tops/punk.svg | 6 +-- src/assets/widgets/tops/wave.svg | 4 +- src/components/Configurator.vue | 68 ++++++++++++++++++++++--- src/components/VueColorAvatar.vue | 11 ++-- src/layouts/Sider.vue | 4 +- src/types/index.ts | 2 +- src/utils/constant.ts | 28 ++++++---- src/utils/index.ts | 33 ++++++++---- 15 files changed, 135 insertions(+), 55 deletions(-) diff --git a/src/assets/widgets/clothes/collared.svg b/src/assets/widgets/clothes/collared.svg index 672d2e0..7140886 100644 --- a/src/assets/widgets/clothes/collared.svg +++ b/src/assets/widgets/clothes/collared.svg @@ -9,7 +9,7 @@ clothes - collared @@ -54,4 +54,4 @@ stroke-linejoin="round" /> - \ No newline at end of file + diff --git a/src/assets/widgets/clothes/crew.svg b/src/assets/widgets/clothes/crew.svg index 5cfa1bf..208f280 100644 --- a/src/assets/widgets/clothes/crew.svg +++ b/src/assets/widgets/clothes/crew.svg @@ -9,7 +9,7 @@ clothes - crew @@ -20,4 +20,4 @@ stroke-width="4" /> - \ No newline at end of file + diff --git a/src/assets/widgets/clothes/open.svg b/src/assets/widgets/clothes/open.svg index 350499b..725c6c5 100644 --- a/src/assets/widgets/clothes/open.svg +++ b/src/assets/widgets/clothes/open.svg @@ -9,9 +9,9 @@ clothes - open - \ No newline at end of file + diff --git a/src/assets/widgets/tops/danny.svg b/src/assets/widgets/tops/danny.svg index 519572d..0f58839 100644 --- a/src/assets/widgets/tops/danny.svg +++ b/src/assets/widgets/tops/danny.svg @@ -9,9 +9,9 @@ tops - danny - \ No newline at end of file + diff --git a/src/assets/widgets/tops/fonze.svg b/src/assets/widgets/tops/fonze.svg index a439d46..ba3c444 100644 --- a/src/assets/widgets/tops/fonze.svg +++ b/src/assets/widgets/tops/fonze.svg @@ -9,23 +9,23 @@ tops - fonze - \ No newline at end of file + diff --git a/src/assets/widgets/tops/funny.svg b/src/assets/widgets/tops/funny.svg index 4da507b..e13d3f4 100644 --- a/src/assets/widgets/tops/funny.svg +++ b/src/assets/widgets/tops/funny.svg @@ -23,4 +23,4 @@ stroke-width="4" /> - \ No newline at end of file + diff --git a/src/assets/widgets/tops/pixie.svg b/src/assets/widgets/tops/pixie.svg index a3420de..84bbfe7 100644 --- a/src/assets/widgets/tops/pixie.svg +++ b/src/assets/widgets/tops/pixie.svg @@ -9,7 +9,7 @@ tops - pixie @@ -19,4 +19,4 @@ stroke-width="4" /> - \ No newline at end of file + diff --git a/src/assets/widgets/tops/punk.svg b/src/assets/widgets/tops/punk.svg index 007555f..ca82b60 100644 --- a/src/assets/widgets/tops/punk.svg +++ b/src/assets/widgets/tops/punk.svg @@ -14,11 +14,11 @@ /> - \ No newline at end of file + diff --git a/src/assets/widgets/tops/wave.svg b/src/assets/widgets/tops/wave.svg index d26cc77..462b843 100644 --- a/src/assets/widgets/tops/wave.svg +++ b/src/assets/widgets/tops/wave.svg @@ -9,9 +9,9 @@ tops - wave - \ No newline at end of file + diff --git a/src/components/Configurator.vue b/src/components/Configurator.vue index 40ee789..5e69a76 100644 --- a/src/components/Configurator.vue +++ b/src/components/Configurator.vue @@ -22,11 +22,11 @@ -
    +
    • + />
    + +
    + 颜色 +
      +
    • +
      +
    • +
    +
    @@ -70,9 +90,14 @@ import { useI18n } from 'vue-i18n' import PerfectScrollbar from '@/components/PerfectScrollbar.vue' import SectionWrapper from '@/components/SectionWrapper.vue' -import { type WidgetShape, type WrapperShape, WidgetType } from '@/enums' +import { + type WidgetShape, + type WrapperShape, + BeardShape, + WidgetType, +} from '@/enums' import { useAvatarOption } from '@/hooks' -import { SETTINGS } from '@/utils/constant' +import { AVATAR_LAYER, SETTINGS } from '@/utils/constant' import { previewData } from '@/utils/dynamic-data' const { t } = useI18n() @@ -156,6 +181,24 @@ function switchWidget(widgetType: WidgetType, widgetShape: WidgetShape) { [widgetType]: { ...avatarOption.value.widgets?.[widgetType], shape: widgetShape, + ...(widgetShape === BeardShape.Scruff + ? { zIndex: AVATAR_LAYER['mouth'].zIndex - 1 } + : undefined), + }, + }, + }) + } +} + +function setWidgetColor(widgetType: WidgetType, fillColor: string) { + if (avatarOption.value.widgets?.[widgetType]) { + setAvatarOption({ + ...avatarOption.value, + widgets: { + ...avatarOption.value.widgets, + [widgetType]: { + ...avatarOption.value.widgets?.[widgetType], + fillColor, }, }, }) @@ -206,12 +249,23 @@ function switchWidget(widgetType: WidgetType, widgetShape: WidgetShape) { } } - .bg-color-list { + .color-picker { + margin-top: 1rem; + + summary { + color: darken(var.$color-text, 20); + font-size: small; + cursor: pointer; + user-select: none; + } + } + + .color-list { display: flex; flex-wrap: wrap; align-items: center; - .bg-color-list__item { + .color-list__item { position: relative; z-index: 1; width: calc(100% / 7); diff --git a/src/components/VueColorAvatar.vue b/src/components/VueColorAvatar.vue index eeee0a0..0ed44ea 100644 --- a/src/components/VueColorAvatar.vue +++ b/src/components/VueColorAvatar.vue @@ -26,7 +26,7 @@ import { ref, toRefs, watchEffect } from 'vue' import { WrapperShape } from '@/enums' import { type AvatarOption } from '@/types' import { getRandomAvatarOption } from '@/utils' -import { AVATAR_LAYER, NONE } from '@/utils/constant' +import { AVATAR_LAYER, NONE, SETTINGS } from '@/utils/constant' import { widgetData } from '@/utils/dynamic-data' import Background from './widgets/Background.vue' @@ -62,9 +62,9 @@ const svgContent = ref('') watchEffect(async () => { const sortedList = Object.entries(avatarOption.value.widgets).sort( - (i, ii) => { - const ix = AVATAR_LAYER[i[0]]?.zIndex ?? 0 - const iix = AVATAR_LAYER[ii[0]]?.zIndex ?? 0 + ([prevShape, prev], [nextShape, next]) => { + const ix = prev.zIndex ?? AVATAR_LAYER[prevShape]?.zIndex ?? 0 + const iix = next.zIndex ?? AVATAR_LAYER[nextShape]?.zIndex ?? 0 return ix - iix } ) @@ -86,9 +86,12 @@ watchEffect(async () => { const svgRawList = await Promise.all(promises).then((raw) => { return raw.map((svgRaw, i) => { + const widgetFillColor = sortedList[i][1].fillColor + const content = svgRaw .slice(svgRaw.indexOf('>', svgRaw.indexOf('', '') + .replaceAll('$fillColor', widgetFillColor || 'transparent') return ` diff --git a/src/layouts/Sider.vue b/src/layouts/Sider.vue index 9d59815..46ea8f3 100644 --- a/src/layouts/Sider.vue +++ b/src/layouts/Sider.vue @@ -41,13 +41,13 @@ const { isCollapsed, openSider, closeSider } = useSider() .trigger { position: absolute; top: 50%; - left: 0; + left: 1px; display: flex; align-items: center; justify-content: center; width: 1.2rem; height: 4rem; - background-color: lighten(var.$color-configurator, 2); + background-color: var.$color-configurator; border-radius: 0.4rem 0 0 0.4rem; transform: translate(-100%, -50%); cursor: pointer; diff --git a/src/types/index.ts b/src/types/index.ts index 211cf3e..c75bb7f 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -67,7 +67,7 @@ export interface AvatarSettings { glassesShape: GlassesShape[] clothesShape: ClothesShape[] + commonColors: string[] backgroundColor: string[] skinColor: string[] - clothesColor: string[] } diff --git a/src/utils/constant.ts b/src/utils/constant.ts index 4899fe0..efad4ff 100644 --- a/src/utils/constant.ts +++ b/src/utils/constant.ts @@ -71,7 +71,7 @@ export const SETTINGS: Readonly = { beardShape: Object.values(BeardShape), clothesShape: Object.values(ClothesShape), - backgroundColor: [ + commonColors: [ '#6BD9E9', '#FC909F', '#F4D150', @@ -84,15 +84,20 @@ export const SETTINGS: Readonly = { '#48A99A', '#C09FFF', '#FD6F5D', - 'linear-gradient(45deg, #E3648C, #D97567)', - 'linear-gradient(62deg, #8EC5FC, #E0C3FC)', - 'linear-gradient(90deg, #ffecd2, #fcb69f)', - 'linear-gradient(120deg, #a1c4fd, #c2e9fb)', - 'linear-gradient(-135deg, #fccb90, #d57eeb)', - 'transparent', ], + + get backgroundColor() { + return [ + ...this.commonColors, + 'linear-gradient(45deg, #E3648C, #D97567)', + 'linear-gradient(62deg, #8EC5FC, #E0C3FC)', + 'linear-gradient(90deg, #ffecd2, #fcb69f)', + 'linear-gradient(120deg, #a1c4fd, #c2e9fb)', + 'linear-gradient(-135deg, #fccb90, #d57eeb)', + 'transparent', + ] + }, skinColor: ['#F9C9B6', '#AC6651'], - clothesColor: ['#9287FF', '#6BD9E9', '#FC909F', '#F4D150', '#77311D'], } export const SCREEN = { @@ -107,7 +112,7 @@ export const SPECIAL_AVATARS: Readonly = [ { wrapperShape: 'squircle', background: { - color: '#E0DDFF', + color: 'linear-gradient(62deg, #8EC5FC, #E0C3FC)', }, widgets: { face: { @@ -115,6 +120,7 @@ export const SPECIAL_AVATARS: Readonly = [ }, tops: { shape: TopsShape.Pixie, + fillColor: '#d2eff3', }, ear: { shape: EarShape.Attached, @@ -142,13 +148,14 @@ export const SPECIAL_AVATARS: Readonly = [ }, clothes: { shape: ClothesShape.Crew, + fillColor: '#e0ddff', }, }, }, { wrapperShape: 'squircle', background: { - color: '#F4D150', + color: '#fd6f5d', }, widgets: { face: { @@ -183,6 +190,7 @@ export const SPECIAL_AVATARS: Readonly = [ }, clothes: { shape: ClothesShape.Crew, + fillColor: '#f4d150', }, }, }, diff --git a/src/utils/index.ts b/src/utils/index.ts index 164cdaf..b0cca9e 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -7,7 +7,7 @@ import { } from '@/enums' import { type AvatarOption, type None } from '@/types' -import { NONE, SETTINGS, SPECIAL_AVATARS } from './constant' +import { AVATAR_LAYER, NONE, SETTINGS, SPECIAL_AVATARS } from './constant' /** * get a random value from an array @@ -34,6 +34,12 @@ function getRandomValue( return randomValue } +export function getRandomFillColor() { + return SETTINGS.commonColors[ + Math.floor(Math.random() * SETTINGS.commonColors.length) + ] +} + export function getRandomAvatarOption( presetOption: Partial = {}, useOption: Partial = {} @@ -48,6 +54,10 @@ export function getRandomAvatarOption( topList = SETTINGS.topsShape.filter((shape) => !topList.includes(shape)) } + const beardShape = getRandomValue(beardList, { + usually: [NONE], + }) + const avatarOption: AvatarOption = { gender, @@ -68,6 +78,7 @@ export function getRandomAvatarOption( shape: getRandomValue(topList, { avoid: [useOption.widgets?.tops?.shape], }), + fillColor: getRandomFillColor(), }, ear: { shape: getRandomValue(SETTINGS.earShape, { @@ -105,14 +116,18 @@ export function getRandomAvatarOption( }), }, beard: { - shape: getRandomValue(beardList, { - usually: [NONE], - }), + shape: beardShape, + + // HACK: + ...(beardShape === BeardShape.Scruff + ? { zIndex: AVATAR_LAYER['mouth'].zIndex - 1 } + : undefined), }, clothes: { shape: getRandomValue(SETTINGS.clothesShape, { avoid: [useOption.widgets?.clothes?.shape], }), + fillColor: getRandomFillColor(), }, }, } @@ -141,22 +156,22 @@ export function showConfetti() { const duration = performance.now() + 1 * 1000 - const colors = ['#6967fe', '#85e9f4', '#e16984'] + const confettiColors = ['#6967fe', '#85e9f4', '#e16984'] void (function frame() { myConfetti({ - particleCount: colors.length, + particleCount: confettiColors.length, angle: 60, spread: 55, origin: { x: 0 }, - colors: colors, + colors: confettiColors, }) myConfetti({ - particleCount: colors.length, + particleCount: confettiColors.length, angle: 120, spread: 55, origin: { x: 1 }, - colors: colors, + colors: confettiColors, }) if (performance.now() < duration) { -- GitLab