添加背景页面增加收藏背景色功能
This commit is contained in:
parent
951813a539
commit
27b7d65e45
@ -1113,6 +1113,12 @@
|
|||||||
"Add custom background color to images. Free online tool to add background to transparent images. Supports JPG, PNG, WebP formats.": "为图片添加自定义背景颜色。免费在线工具,可为透明背景图片添加背景。支持 JPG、PNG、WebP 格式。",
|
"Add custom background color to images. Free online tool to add background to transparent images. Supports JPG, PNG, WebP formats.": "为图片添加自定义背景颜色。免费在线工具,可为透明背景图片添加背景。支持 JPG、PNG、WebP 格式。",
|
||||||
"add background, background color, image background, transparent background, online background tool, image processing, background editor, free tool": "添加背景、背景颜色、图片背景、透明背景、在线背景工具、图片处理、背景编辑器、免费工具",
|
"add background, background color, image background, transparent background, online background tool, image processing, background editor, free tool": "添加背景、背景颜色、图片背景、透明背景、在线背景工具、图片处理、背景编辑器、免费工具",
|
||||||
"Background Color": "背景颜色",
|
"Background Color": "背景颜色",
|
||||||
|
"Add to favorites": "添加到收藏",
|
||||||
|
"Remove from favorites": "从收藏中移除",
|
||||||
|
"Favorite Colors": "收藏颜色",
|
||||||
|
"Color already in favorites": "颜色已在收藏中",
|
||||||
|
"Maximum 12 favorite colors allowed. Please remove one first.": "最多允许12个收藏颜色,请先移除一个",
|
||||||
|
"Color added to favorites": "颜色已添加到收藏",
|
||||||
"Color Tones": "色调",
|
"Color Tones": "色调",
|
||||||
"Common Colors": "常用颜色",
|
"Common Colors": "常用颜色",
|
||||||
"Apply Background": "应用背景",
|
"Apply Background": "应用背景",
|
||||||
|
|||||||
@ -161,7 +161,17 @@
|
|||||||
<div v-if="uploadedImage" class="right-sidebar">
|
<div v-if="uploadedImage" class="right-sidebar">
|
||||||
<div class="sidebar-content">
|
<div class="sidebar-content">
|
||||||
<div class="color-picker-section">
|
<div class="color-picker-section">
|
||||||
<h4 class="section-title">{{ t('Background Color') }}</h4>
|
<div class="section-header">
|
||||||
|
<h4 class="section-title">{{ t('Background Color') }}</h4>
|
||||||
|
<button
|
||||||
|
class="add-favorite-btn"
|
||||||
|
@click="addToFavorites"
|
||||||
|
:title="t('Add to favorites')"
|
||||||
|
:disabled="favoriteColors.length >= MAX_FAVORITE_COLORS"
|
||||||
|
>
|
||||||
|
<i class="fa fa-star"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="color-picker-container">
|
<div class="color-picker-container">
|
||||||
<input
|
<input
|
||||||
v-model="backgroundColor"
|
v-model="backgroundColor"
|
||||||
@ -180,6 +190,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="favoriteColors.length > 0" class="favorite-colors-section">
|
||||||
|
<h4 class="section-title">{{ t('Favorite Colors') }}</h4>
|
||||||
|
<div class="favorite-colors-grid">
|
||||||
|
<div
|
||||||
|
v-for="(color, index) in favoriteColors"
|
||||||
|
:key="index"
|
||||||
|
class="favorite-color-item"
|
||||||
|
:class="{ 'active': color === backgroundColor }"
|
||||||
|
:style="{ backgroundColor: color }"
|
||||||
|
@click="selectCommonColor(color)"
|
||||||
|
:title="color"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="remove-favorite-btn"
|
||||||
|
@click.stop="removeFavoriteColor(color)"
|
||||||
|
:title="t('Remove from favorites')"
|
||||||
|
:aria-label="t('Remove from favorites')"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="common-colors-section">
|
<div class="common-colors-section">
|
||||||
<h4 class="section-title">{{ t('Common Colors') }}</h4>
|
<h4 class="section-title">{{ t('Common Colors') }}</h4>
|
||||||
<div class="common-colors-grid">
|
<div class="common-colors-grid">
|
||||||
@ -251,6 +284,65 @@ const colorShades = computed(() => {
|
|||||||
return generateColorShades(backgroundColor.value)
|
return generateColorShades(backgroundColor.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Favorite colors - persisted in localStorage
|
||||||
|
const favoriteColors = ref<string[]>([])
|
||||||
|
const MAX_FAVORITE_COLORS = 12
|
||||||
|
|
||||||
|
// Load favorite colors from localStorage
|
||||||
|
const loadFavoriteColors = () => {
|
||||||
|
try {
|
||||||
|
const saved = localStorage.getItem('add_background_favorite_colors')
|
||||||
|
if (saved) {
|
||||||
|
const parsed = JSON.parse(saved)
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
favoriteColors.value = parsed.slice(0, MAX_FAVORITE_COLORS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load favorite colors:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save favorite colors to localStorage
|
||||||
|
const saveFavoriteColors = () => {
|
||||||
|
try {
|
||||||
|
localStorage.setItem('add_background_favorite_colors', JSON.stringify(favoriteColors.value))
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to save favorite colors:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add current color to favorites
|
||||||
|
const addToFavorites = () => {
|
||||||
|
const color = backgroundColor.value.toUpperCase()
|
||||||
|
|
||||||
|
// Check if color already exists
|
||||||
|
if (favoriteColors.value.includes(color)) {
|
||||||
|
message.info(t('Color already in favorites'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if favorites is full
|
||||||
|
if (favoriteColors.value.length >= MAX_FAVORITE_COLORS) {
|
||||||
|
message.warning(t('Maximum 12 favorite colors allowed. Please remove one first.'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to beginning of array
|
||||||
|
favoriteColors.value.unshift(color)
|
||||||
|
saveFavoriteColors()
|
||||||
|
message.success(t('Color added to favorites'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove color from favorites
|
||||||
|
const removeFavoriteColor = (color: string) => {
|
||||||
|
const index = favoriteColors.value.indexOf(color)
|
||||||
|
if (index > -1) {
|
||||||
|
favoriteColors.value.splice(index, 1)
|
||||||
|
saveFavoriteColors()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 12 common background colors - light to dark
|
// 12 common background colors - light to dark
|
||||||
const commonColors = ref([
|
const commonColors = ref([
|
||||||
'#FFFFFF', // White
|
'#FFFFFF', // White
|
||||||
@ -547,6 +639,7 @@ const handleUrlSubmit = async () => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.addEventListener('resize', handleResize)
|
window.addEventListener('resize', handleResize)
|
||||||
window.addEventListener('paste', handlePaste)
|
window.addEventListener('paste', handlePaste)
|
||||||
|
loadFavoriteColors()
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
@ -1737,19 +1830,65 @@ const removeHistoryItem = (index: number) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.color-picker-section,
|
.color-picker-section,
|
||||||
|
.favorite-colors-section,
|
||||||
.common-colors-section {
|
.common-colors-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
border-bottom: 1px solid #e5e7eb;
|
||||||
|
}
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #1f2937;
|
color: #1f2937;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding-bottom: 12px;
|
flex: 1;
|
||||||
border-bottom: 1px solid #e5e7eb;
|
}
|
||||||
|
|
||||||
|
.add-favorite-btn {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 6px;
|
||||||
|
background: white;
|
||||||
|
color: #fbbf24;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
padding: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
border-color: #fbbf24;
|
||||||
|
background: #fffbeb;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active:not(:disabled) {
|
||||||
|
transform: scale(0.95);
|
||||||
|
background: #fef3c7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: #cbd5e1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-picker-container {
|
.color-picker-container {
|
||||||
@ -1800,12 +1939,18 @@ const removeHistoryItem = (index: number) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.favorite-colors-grid,
|
||||||
.common-colors-grid {
|
.common-colors-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.favorite-colors-grid {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.favorite-color-item,
|
||||||
.common-color-item {
|
.common-color-item {
|
||||||
aspect-ratio: 1;
|
aspect-ratio: 1;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@ -1841,6 +1986,58 @@ const removeHistoryItem = (index: number) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.favorite-color-item {
|
||||||
|
.remove-favorite-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
right: 2px;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: none;
|
||||||
|
background: rgba(15, 23, 42, 0.75);
|
||||||
|
color: white;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.8);
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0;
|
||||||
|
line-height: 1;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 10px;
|
||||||
|
height: 2px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(239, 68, 68, 0.9);
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .remove-favorite-btn {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.canvas-processing-overlay {
|
.canvas-processing-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -2146,6 +2343,7 @@ const removeHistoryItem = (index: number) => {
|
|||||||
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
|
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.favorite-colors-grid,
|
||||||
.common-colors-grid {
|
.common-colors-grid {
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
}
|
}
|
||||||
@ -2191,6 +2389,7 @@ const removeHistoryItem = (index: number) => {
|
|||||||
width: 240px;
|
width: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.favorite-colors-grid,
|
||||||
.common-colors-grid {
|
.common-colors-grid {
|
||||||
grid-template-columns: repeat(4, 1fr);
|
grid-template-columns: repeat(4, 1fr);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user