diff --git a/components/cl-tabbar.vue b/components/cl-tabbar.vue
index 676c126..09fc624 100644
--- a/components/cl-tabbar.vue
+++ b/components/cl-tabbar.vue
@@ -240,4 +240,33 @@ export default {
// margin-bottom: 30px;
}
}
+
+/* iPhone安全区域适配 */
+
+/* 绿色主题的安全区域适配 */
+.greenEd {
+ ::v-deep .u-tabbar__content {
+ background: linear-gradient(to bottom, #fff, #b6fdda);
+
+ /* 绿色主题的安全区域背景 */
+ &::after {
+ background: #b6fdda;
+ }
+ }
+}
+
+/* 针对不同屏幕尺寸的优化 */
+@media screen and (max-height: 667px) {
+ /* iPhone SE等小屏设备 */
+ ::v-deep .u-tabbar__content__item-wrapper {
+ height: 70px;
+ }
+}
+
+@media screen and (min-height: 812px) {
+ /* iPhone X及以上机型 */
+ ::v-deep .u-tabbar__content__item-wrapper {
+ height: 80px;
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index 4d803a4..680a00a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"qrcodejs2": "0.0.2",
"swiper": "^3.4.2",
"uqrcodejs": "^4.0.7",
+ "vconsole": "^3.15.1",
"vue-clipboard2": "^0.3.3",
"vue-i18n": "^9.2.2",
"vue-tree-color": "^2.3.2",
@@ -64,6 +65,15 @@
"node": ">=6.0.0"
}
},
+ "node_modules/@babel/runtime": {
+ "version": "7.27.6",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
+ "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
"node_modules/@babel/types": {
"version": "7.27.0",
"resolved": "https://mirrors.cloud.tencent.com/npm/@babel/types/-/types-7.27.0.tgz",
@@ -1821,6 +1831,29 @@
"node": ">=0.10.0"
}
},
+ "node_modules/copy-text-to-clipboard": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz",
+ "integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/core-js": {
+ "version": "3.43.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.43.0.tgz",
+ "integrity": "sha512-N6wEbTTZSYOY2rYAn85CuvWWkCK6QweMn7/4Nr3w+gDBeBhk/x4EJeY6FPo4QzDoJZxVTv8U7CMvgWk6pOHHqA==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://mirrors.cloud.tencent.com/npm/core-util-is/-/core-util-is-1.0.3.tgz",
@@ -4357,6 +4390,11 @@
"dev": true,
"peer": true
},
+ "node_modules/mutation-observer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/mutation-observer/-/mutation-observer-1.0.3.tgz",
+ "integrity": "sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA=="
+ },
"node_modules/nan": {
"version": "2.22.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/nan/-/nan-2.22.2.tgz",
@@ -6469,6 +6507,18 @@
"base64-arraybuffer": "^1.0.2"
}
},
+ "node_modules/vconsole": {
+ "version": "3.15.1",
+ "resolved": "https://registry.npmjs.org/vconsole/-/vconsole-3.15.1.tgz",
+ "integrity": "sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.17.2",
+ "copy-text-to-clipboard": "^3.0.1",
+ "core-js": "^3.11.0",
+ "mutation-observer": "^1.0.3"
+ }
+ },
"node_modules/vm-browserify": {
"version": "1.1.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/vm-browserify/-/vm-browserify-1.1.2.tgz",
diff --git a/package.json b/package.json
index 27b2ced..0ec7876 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"qrcodejs2": "0.0.2",
"swiper": "^3.4.2",
"uqrcodejs": "^4.0.7",
+ "vconsole": "^3.15.1",
"vue-clipboard2": "^0.3.3",
"vue-i18n": "^9.2.2",
"vue-tree-color": "^2.3.2",
diff --git a/pages/mine/index.vue b/pages/mine/index.vue
index 289b7c2..01288a0 100644
--- a/pages/mine/index.vue
+++ b/pages/mine/index.vue
@@ -402,13 +402,13 @@ export default {
menuKey: 'selfHelp',
ifshow: true,
},
- {
- url: '/pages/mine/share/index',
- name: '个人推广',
- imgurl: '../../static/images/list.svg',
- menuKey: 'share',
- ifshow: false,
- },
+ // {
+ // url: '/pages/mine/share/index',
+ // name: '个人推广',
+ // imgurl: '../../static/images/list.svg',
+ // menuKey: 'share',
+ // ifshow: false,
+ // },
{
url: '/pages/userSecure/index',
name: '账号安全',
diff --git a/pages/mine/share/index.vue b/pages/mine/share/index.vue
index c651fb2..6847130 100644
--- a/pages/mine/share/index.vue
+++ b/pages/mine/share/index.vue
@@ -1,37 +1,70 @@
-
-
-
-
-
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+ {{ desensitization(userInfo.memberCode) }}
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
@@ -39,6 +72,8 @@
import html2canvas from 'html2canvas'
import { getShareCode } from '@/config/share'
import clTabbar from '@/components/cl-tabbar.vue'
+import VConsole from 'vconsole'
+const vConsole = new VConsole()
export default {
name: 'ShareQRCode',
components: {
@@ -52,16 +87,20 @@ export default {
canvasHeight: 800,
isLoaded: false,
shareButtonShow: true,
+ isWechat: false, // 是否微信环境
+ generatedImageUrl: '', // 生成的图片URL,用于微信长按保存
+ backgroundImageLoaded: false, // 背景图片是否加载完成
+ userInfo: uni.getStorageSync('User'),
}
},
onLoad() {
+ this.checkWechatEnvironment()
this.handleGetShareCode()
// Get screen width to set canvas width dynamically
uni.getSystemInfo({
success: res => {
this.canvasWidth = res.windowWidth
- // Set canvas height to a fixed 800px as requested
- this.canvasHeight = 800
+ this.canvasHeight = res.windowHeight
},
})
},
@@ -72,6 +111,20 @@ export default {
}, 100)
},
methods: {
+ desensitization(str) {
+ if (!str) return ''
+ if (str.length <= 8) return str.slice(0, 4) + '****'
+ const len = str.length - 6
+ const placeholder = '*'.repeat(len)
+ return str.slice(0, 4) + placeholder + str.slice(-2)
+ },
+ // 检测微信环境
+ checkWechatEnvironment() {
+ const ua = navigator.userAgent.toLowerCase()
+ this.isWechat = ua.includes('micromessenger')
+ console.log('微信环境检测:', this.isWechat)
+ },
+
handleGetShareCode() {
// Don't show loading toast, use the placeholder loader instead
// uni.showLoading({ title: '加载中...' })
@@ -80,6 +133,11 @@ export default {
// The screenshot shows the base64 string is in data.datStr
if (res.code === 200 && res.data && res.data.dataStr) {
this.qrCodeImage = 'data:image/png;base64,' + res.data.dataStr
+ this.$nextTick(() => {
+ if (this.isWechat) {
+ this.sharePage()
+ }
+ })
} else {
uni.showToast({
title: '获取分享码失败',
@@ -104,388 +162,163 @@ export default {
})
return
}
- this.shareButtonShow = false
- uni.showLoading({ title: '正在生成图片...' })
+
+ // 统一使用html2canvas生成图片
+ uni.showLoading({ title: '加载中...' })
try {
- // --- Button Swap Logic ---
+ // 隐藏按钮,等待DOM更新
this.shareButtonShow = false
- // Wait for DOM to update with the fake button
await this.$nextTick()
- // #ifdef H5
- // Capture the entire container as requested
- await this.captureWithHtml2Canvas()
- // #endif
-
- // #ifndef H5
- // Draw the entire container using Canvas
- await this.generateImageWithCanvas()
- // #endif
+ // 使用html2canvas截取页面
+ await this.capturePageWithHtml2Canvas()
} catch (error) {
uni.hideLoading()
uni.showToast({ title: '图片生成失败,请稍后重试', icon: 'none' })
console.error('sharePage error:', error)
} finally {
- // --- Always swap back to the real button ---
+ // 恢复按钮显示
this.shareButtonShow = true
}
},
- // --- H5-specific method ---
- captureWithHtml2Canvas() {
- return new Promise((resolve, reject) => {
- // #ifdef H5
- // Target the entire #shareContainer as per instruction
- const element = document.getElementById('shareContainer')
- if (!element) {
- uni.hideLoading()
- return reject(new Error('Share container element not found'))
- }
+ // 生成的图片加载成功
+ onGeneratedImageLoad() {
+ console.log('生成的图片加载成功')
+ },
- html2canvas(element, {
- useCORS: true,
- allowTaint: true,
- backgroundColor: null,
- scale: window.devicePixelRatio || 2,
- logging: false,
- })
- .then(canvas => {
- this.saveImageToAlbum(canvas.toDataURL('image/png', 1.0))
- resolve()
- })
- .catch(err => {
- console.error('html2canvas capture failed:', err)
- reject(err)
- })
- // #endif
+ // 生成的图片加载失败
+ onGeneratedImageError(e) {
+ console.error('生成的图片加载失败:', e)
+ uni.showToast({
+ title: '图片显示失败',
+ icon: 'none',
})
},
- // A robust canvas-based image generation for all platforms
- async generateImageWithCanvas() {
- try {
- // Load all required images before drawing
- const [bgImageTempPath, qrCodeTempPath] = await Promise.all([
- this.getLocalImageTempPath('/static/images/share-bg.png'),
- this.base64ToTempFilePath(this.qrCodeImage),
- ])
+ // 关闭全屏图片
+ closeFullscreenImage() {
+ this.generatedImageUrl = ''
+ console.log('关闭全屏图片')
+ },
- if (!bgImageTempPath || !qrCodeTempPath) {
- throw new Error('Image resource failed to load')
- }
+ // 背景图片加载成功
+ onBackgroundImageLoad() {
+ this.backgroundImageLoaded = true
+ console.log('背景图片加载成功')
+ },
- const ctx = uni.createCanvasContext('shareCanvas', this)
- // Draw the entire scene to the canvas
- this.drawSceneToCanvas(ctx, bgImageTempPath, qrCodeTempPath)
+ // 背景图片加载失败
+ onBackgroundImageError(e) {
+ console.error('背景图片加载失败:', e)
+ },
- return new Promise(resolve => {
+ // 使用html2canvas截取整个页面
+ async capturePageWithHtml2Canvas() {
+ console.log('开始使用html2canvas截取页面')
+
+ return new Promise((resolve, reject) => {
+ // 确保所有图片都已加载完成
+ const waitForImages = () => {
+ if (!this.backgroundImageLoaded || !this.qrCodeImage) {
+ setTimeout(waitForImages, 100)
+ return
+ }
+
+ // 额外等待确保渲染完成
setTimeout(() => {
- ctx.draw(false, () => {
- setTimeout(() => {
- this.saveCanvasToAlbum()
- resolve()
- }, 500)
- })
- }, 100)
- })
- } catch (error) {
- console.error('generateImageWithCanvas error:', error)
- throw error
- }
- },
-
- // Main drawing function to replicate the entire scene on canvas
- drawSceneToCanvas(ctx, bgPath, qrPath) {
- const canvasWidth = this.canvasWidth
- const canvasHeight = this.canvasHeight // Fixed at 800px
-
- // 1. Draw background image
- ctx.drawImage(bgPath, 0, 0, canvasWidth, canvasHeight)
-
- // 2. Draw portal frame (calculations for centering)
- const portalWidth = canvasWidth * 0.85
- const portalPadding = 20
- // The white card's width is the portal's inner width
- const cardWidth = portalWidth - portalPadding * 2
- // The card is a square, so its height is its width
- const cardHeight = cardWidth
- const buttonHeight = 50
- const buttonMargin = 20
- const portalHeight =
- portalPadding * 2 + cardHeight + buttonMargin + buttonHeight
- const portalX = (canvasWidth - portalWidth) / 2
- const portalY = (canvasHeight - portalHeight) / 2
- this.drawPortalFrame(ctx, portalX, portalY, portalWidth, portalHeight)
-
- // 3. Draw the white QR card
- const cardX = portalX + portalPadding
- const cardY = portalY + portalPadding
- this.drawQrCodeCard(ctx, cardX, cardY, cardWidth, cardHeight)
-
- // 4. Draw the FAKE button to match the CSS
- const buttonX = cardX
- const buttonY = cardY + cardHeight + buttonMargin
- this.drawStyledButton(
- ctx,
- buttonX,
- buttonY,
- cardWidth,
- buttonHeight,
- '保存图片并分享'
- )
-
- // 5. Draw the actual QR image (or loader placeholder) on top
- // If qrPath is null/empty, this block is skipped, leaving the white card empty (like a placeholder)
- if (qrPath) {
- // Padding inside the white card
- const imagePadding = cardWidth * 0.1
- const qrCodeSize = cardWidth - imagePadding * 2
- const qrCodeX = cardX + imagePadding
- const qrCodeY = cardY + imagePadding
- ctx.drawImage(qrPath, qrCodeX, qrCodeY, qrCodeSize, qrCodeSize)
- } else {
- // Draw loader manually if QR is not available
- // This part is complex, for now we show an empty card which is better than broken UI
- }
- },
-
- // Helper: Draws the portal frame to match CSS
- drawPortalFrame(ctx, x, y, width, height) {
- const radius = 25 // 50rpx
- ctx.save()
- this.drawRoundedRect(ctx, x, y, width, height, radius)
- // Frosted glass effect
- const portalGradient = ctx.createLinearGradient(x, y, x, y + height)
- portalGradient.addColorStop(0, 'rgba(255, 255, 255, 0.4)')
- portalGradient.addColorStop(1, 'rgba(255, 255, 255, 0.2)')
- ctx.fillStyle = portalGradient
- ctx.fill()
- // Inner glow border
- ctx.shadowColor = 'rgba(255, 255, 255, 0.5)'
- ctx.shadowBlur = 10
- ctx.strokeStyle = 'rgba(255, 255, 255, 0.6)'
- ctx.lineWidth = 1.5
- ctx.stroke()
- ctx.restore()
- },
-
- // New/Refactored Helper: Draws the single white QR Code card
- drawQrCodeCard(ctx, x, y, width, height) {
- const borderRadius = 20 // 40rpx
-
- ctx.save()
- this.drawRoundedRect(ctx, x, y, width, height, borderRadius)
- // Card background
- ctx.fillStyle = 'rgba(255, 255, 255, 0.98)'
- // Card shadow
- ctx.shadowColor = 'rgba(50, 50, 90, 0.1)'
- ctx.shadowBlur = 30
- ctx.shadowOffsetY = 15
- ctx.fill()
- // Card border
- ctx.strokeStyle = '#f0f0f0'
- ctx.lineWidth = 1
- ctx.stroke()
- ctx.restore()
- },
-
- // Helper: Draws the styled button
- drawStyledButton(ctx, x, y, width, height, text) {
- const radius = height / 2
-
- ctx.save()
- this.drawRoundedRect(ctx, x, y, width, height, radius)
- // Background gradient
- const gradient = ctx.createLinearGradient(x, y, x + width, y)
- gradient.addColorStop(0, '#0ff0fc')
- gradient.addColorStop(0.5, '#0072ff')
- gradient.addColorStop(1, '#00c6ff')
- ctx.fillStyle = gradient
- // Shadow
- ctx.shadowColor = 'rgba(0, 114, 255, 0.35)'
- ctx.shadowBlur = 20
- ctx.shadowOffsetY = 8
- ctx.fill()
- ctx.restore()
-
- // Text
- ctx.save()
- ctx.fillStyle = '#ffffff'
- ctx.font = '17px sans-serif'
- ctx.textAlign = 'center'
- ctx.textBaseline = 'middle'
- ctx.fillText(text, x + width / 2, y + height / 2)
- ctx.restore()
- },
-
- // Helper: Draw a rectangle with rounded corners
- drawRoundedRect(ctx, x, y, width, height, radius) {
- if (width < 2 * radius) radius = width / 2
- if (height < 2 * radius) radius = height / 2
- ctx.beginPath()
- ctx.moveTo(x + radius, y)
- ctx.arcTo(x + width, y, x + width, y + height, radius)
- ctx.arcTo(x + width, y + height, x, y + height, radius)
- ctx.arcTo(x, y + height, x, y, radius)
- ctx.arcTo(x, y, x + width, y, radius)
- ctx.closePath()
- },
-
- saveCanvasToAlbum() {
- try {
- // 统一的canvas转换参数
- const options = {
- canvasId: 'shareCanvas',
- fileType: 'png',
- quality: 1,
- success: res => {
- console.log('canvas转换成功:', res)
- if (res.tempFilePath) {
- this.saveImageToAlbum(res.tempFilePath)
- } else {
- uni.hideLoading()
- uni.showToast({ title: '图片生成失败', icon: 'none' })
+ const element = document.getElementById('shareContainer')
+ if (!element) {
+ reject(new Error('找不到页面容器'))
+ return
}
- },
- fail: err => {
- console.error('canvas转换失败:', err)
- uni.hideLoading()
- uni.showToast({ title: '图片转换失败', icon: 'none' })
- },
+
+ console.log(
+ '开始html2canvas截取,容器尺寸:',
+ element.offsetWidth,
+ 'x',
+ element.offsetHeight
+ )
+
+ html2canvas(element, {
+ useCORS: true,
+ allowTaint: true,
+ backgroundColor: null,
+ scale: Math.max(3, window.devicePixelRatio * 2),
+ logging: true, // 开启日志便于调试
+ width: element.offsetWidth,
+ height: element.offsetHeight,
+ windowWidth: element.offsetWidth,
+ windowHeight: element.offsetHeight,
+ scrollX: 0,
+ scrollY: 0,
+ x: 0,
+ y: 0,
+ })
+ .then(canvas => {
+ const dataUrl = canvas.toDataURL('image/png', 1.0)
+
+ // 根据环境处理结果
+ if (this.isWechat) {
+ // 微信环境:设置图片供长按保存
+ this.generatedImageUrl = dataUrl
+ uni.hideLoading()
+ } else {
+ // 普通浏览器:直接下载图片
+ this.downloadImage(dataUrl)
+ uni.hideLoading()
+ uni.showToast({
+ title: '图片已开始下载',
+ icon: 'success',
+ })
+ }
+
+ resolve()
+ })
+ .catch(err => {
+ console.error('html2canvas截取失败:', err)
+ reject(err)
+ })
+ }, 1000) // 增加等待时间到1000ms
}
- // 调用canvas转换API
- uni.canvasToTempFilePath(options, this)
- } catch (error) {
- console.error('saveCanvasToAlbum error:', error)
- uni.hideLoading()
- uni.showToast({ title: '保存失败', icon: 'none' })
- }
+ // 开始等待图片加载
+ waitForImages()
+ })
},
- // 新增:统一的图片保存方法
- saveImageToAlbum(filePath) {
- // #ifdef H5
- // For H5, trigger download instead of saving to album
+ // 原生图片加载器
+ loadImage(src) {
+ return new Promise((resolve, reject) => {
+ const img = new Image()
+ img.crossOrigin = 'anonymous'
+
+ img.onload = () => {
+ console.log(
+ `图片加载成功: ${src.substring(0, 50)}...`,
+ `${img.width}x${img.height}`
+ )
+ resolve(img)
+ }
+
+ img.onerror = error => {
+ console.error(`图片加载失败: ${src}`, error)
+ reject(new Error(`图片加载失败: ${src}`))
+ }
+
+ img.src = src
+ })
+ },
+
+ // 下载图片
+ downloadImage(dataUrl) {
const link = document.createElement('a')
- link.href = filePath
+ link.href = dataUrl
link.download = `share_page_${Date.now()}.png`
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
- uni.hideLoading()
- uni.showToast({
- title: '图片已开始下载',
- icon: 'success',
- })
- // #endif
-
- // #ifndef H5
- // For App and Mini Programs
- uni.saveImageToPhotosAlbum({
- filePath: filePath,
- success: () => {
- uni.hideLoading()
- uni.showToast({
- title: '图片已保存到相册',
- icon: 'success',
- })
- },
- fail: err => {
- uni.hideLoading()
- if (
- err.errMsg &&
- (err.errMsg.includes('auth deny') ||
- err.errMsg.includes('auth denied'))
- ) {
- uni.showModal({
- title: '提示',
- content: '需要您授权保存相册',
- showCancel: false,
- success: () => {
- uni.openSetting({
- success(settingdata) {
- if (settingdata.authSetting['scope.writePhotosAlbum']) {
- uni.showToast({
- title: '授权成功,请重试',
- icon: 'none',
- })
- } else {
- uni.showToast({
- title: '获取权限失败',
- icon: 'none',
- })
- }
- },
- })
- },
- })
- } else {
- uni.showToast({ title: '保存失败', icon: 'none' })
- console.error('saveImageToPhotosAlbum fail:', err)
- }
- },
- })
- // #endif
- },
-
- base64ToTempFilePath(base64) {
- return new Promise((resolve, reject) => {
- try {
- // #ifdef H5
- // For H5, we load the base64 into an Image to ensure it's valid,
- // but resolve with the base64 string to avoid Uniapp's internal errors
- // when its functions expect a string path instead of an Image object.
- const image = new Image()
- // Resolve CORS issue for QR code from different origin
- image.crossOrigin = 'Anonymous'
- image.src = base64
- image.onload = () => {
- // Resolve with the string, not the object.
- resolve(base64)
- }
- image.onerror = err => {
- console.error('Failed to load image for canvas on H5', err)
- reject(new Error('H5图片加载失败'))
- }
- // #endif
-
- // #ifndef H5
- // For App and Mini Programs, write to a temp file and return the path.
- if (!base64 || typeof base64 !== 'string') {
- reject(new Error('无效的base64数据'))
- return
- }
-
- const formattedBase64 = base64.replace(/^data:image\/\w+;base64,/, '')
- if (!formattedBase64) {
- reject(new Error('base64数据格式错误'))
- return
- }
-
- // Use a standard path for user data directory.
- const filePath = `${uni.env.USER_DATA_PATH}/share_${Date.now()}.png`
- const fileManager = uni.getFileSystemManager()
-
- fileManager.writeFile({
- filePath,
- data: formattedBase64,
- encoding: 'base64',
- success: () => {
- resolve(filePath)
- },
- fail: err => {
- console.error('Failed to write temp file', err)
- reject(new Error('临时文件写入失败'))
- },
- })
- // #endif
- } catch (error) {
- console.error('base64ToTempFilePath error:', error)
- reject(new Error('图片处理失败'))
- }
- })
},
},
}
@@ -493,9 +326,8 @@ export default {
diff --git a/static/images/share-bg.jpg b/static/images/share-bg.jpg
index 48c1e1f..962d4ea 100644
Binary files a/static/images/share-bg.jpg and b/static/images/share-bg.jpg differ
diff --git a/static/images/share-logo.png b/static/images/share-logo.png
new file mode 100644
index 0000000..426b58f
Binary files /dev/null and b/static/images/share-logo.png differ