feat(share): align social sharing runtime
This commit is contained in:
1 parent
26ac8167f3
commit
cf6c11852e
33 files changed
+802
-1919
No files matched your search
@@ -82,6 +82,12 @@
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</div>
|
||||
<AksSorterField
|
||||
v-else-if="field.type === 'custom' && field.renderer === 'sorter'"
|
||||
:model-value="getFieldValue(field.key) || {}"
|
||||
:options="field.options || []"
|
||||
@update:model-value="setFieldValue(field.key, $event)"
|
||||
/>
|
||||
<slot
|
||||
v-else-if="field.type === 'custom'"
|
||||
:name="`field-${field.key}`"
|
||||
@@ -93,7 +99,7 @@
|
||||
:form-data="formData"
|
||||
:error-message="errors?.[field.key]"
|
||||
@update:model-value="setFieldValue(field.key, $event)"
|
||||
@action="emit('field-action', $event)"
|
||||
@action="emit('field-action', $event)"
|
||||
/>
|
||||
</slot>
|
||||
<AksField
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div class="aksrt-sorter">
|
||||
<div class="aksrt-sorter__column">
|
||||
<div class="aksrt-sorter__title">
|
||||
<span>已启用</span>
|
||||
<n-tag size="small" type="success" :bordered="false">{{ columns.enabled.length }}</n-tag>
|
||||
</div>
|
||||
<draggable
|
||||
v-model="columns.enabled"
|
||||
item-key="value"
|
||||
group="aksrt-sorter"
|
||||
handle=".aksrt-sorter__handle"
|
||||
ghost-class="aksrt-sorter__ghost"
|
||||
animation="180"
|
||||
class="aksrt-sorter__list"
|
||||
@change="commit"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<div class="aksrt-sorter__item">
|
||||
<i class="fa fas fa-grip-vertical aksrt-sorter__handle" aria-hidden="true"></i>
|
||||
<i v-if="element.icon" :class="element.icon" aria-hidden="true"></i>
|
||||
<span>{{ element.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<n-empty v-if="columns.enabled.length === 0" size="small" description="暂无启用项" />
|
||||
</div>
|
||||
|
||||
<div class="aksrt-sorter__column aksrt-sorter__column--disabled">
|
||||
<div class="aksrt-sorter__title">
|
||||
<span>未启用</span>
|
||||
<n-tag size="small" :bordered="false">{{ columns.disabled.length }}</n-tag>
|
||||
</div>
|
||||
<draggable
|
||||
v-model="columns.disabled"
|
||||
item-key="value"
|
||||
group="aksrt-sorter"
|
||||
handle=".aksrt-sorter__handle"
|
||||
ghost-class="aksrt-sorter__ghost"
|
||||
animation="180"
|
||||
class="aksrt-sorter__list"
|
||||
@change="commit"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<div class="aksrt-sorter__item">
|
||||
<i class="fa fas fa-grip-vertical aksrt-sorter__handle" aria-hidden="true"></i>
|
||||
<i v-if="element.icon" :class="element.icon" aria-hidden="true"></i>
|
||||
<span>{{ element.label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</draggable>
|
||||
<n-empty v-if="columns.disabled.length === 0" size="small" description="暂无未启用项" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, watch } from 'vue'
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Object, default: () => ({}) },
|
||||
options: { type: Array, default: () => [] },
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const columns = reactive({ enabled: [], disabled: [] })
|
||||
let syncing = false
|
||||
|
||||
function keysOf(value) {
|
||||
if (Array.isArray(value)) return value.map(String)
|
||||
return value && typeof value === 'object' ? Object.keys(value) : []
|
||||
}
|
||||
|
||||
function syncColumns() {
|
||||
syncing = true
|
||||
const byKey = new Map(props.options.map(option => [String(option.value), option]))
|
||||
const used = new Set()
|
||||
const normalize = keys => keys.filter(key => byKey.has(key) && !used.has(key)).map(key => {
|
||||
used.add(key)
|
||||
return byKey.get(key)
|
||||
})
|
||||
columns.enabled = normalize(keysOf(props.modelValue?.enabled))
|
||||
columns.disabled = normalize(keysOf(props.modelValue?.disabled))
|
||||
for (const option of props.options) {
|
||||
if (!used.has(String(option.value))) columns.disabled.push(option)
|
||||
}
|
||||
syncing = false
|
||||
}
|
||||
|
||||
function commit() {
|
||||
if (syncing) return
|
||||
const toMap = items => Object.fromEntries(items.map(item => [String(item.value), String(item.label)]))
|
||||
emit('update:modelValue', {
|
||||
enabled: toMap(columns.enabled),
|
||||
disabled: toMap(columns.disabled),
|
||||
})
|
||||
}
|
||||
|
||||
watch(() => [props.modelValue, props.options], syncColumns, { immediate: true, deep: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-sorter { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:14px; }
|
||||
.aksrt-sorter__column { min-height:210px; padding:12px; border:1px solid var(--aksrt-color-border); border-radius:6px; background:var(--aksrt-color-surface); }
|
||||
.aksrt-sorter__column--disabled { background:var(--aksrt-color-canvas); }
|
||||
.aksrt-sorter__title { display:flex; align-items:center; justify-content:space-between; margin-bottom:10px; font-weight:600; }
|
||||
.aksrt-sorter__list { display:grid; gap:7px; min-height:44px; }
|
||||
.aksrt-sorter__item { display:flex; align-items:center; gap:9px; min-height:38px; padding:7px 10px; border:1px solid var(--aksrt-color-border); border-radius:4px; background:var(--aksrt-color-surface); }
|
||||
.aksrt-sorter__handle { color:var(--aksrt-color-text-tertiary); cursor:grab; }
|
||||
.aksrt-sorter__ghost { opacity:.45; border-color:var(--aksrt-color-primary); }
|
||||
@media (max-width:720px) { .aksrt-sorter { grid-template-columns:1fr; } }
|
||||
</style>
|
||||
@@ -84,6 +84,16 @@ export const globalSection = {
|
||||
canonicalDomain: 'global',
|
||||
section: 'i18n',
|
||||
}),
|
||||
schemaPage({
|
||||
key: 'global-share',
|
||||
name: 'GlobalShare',
|
||||
label: '社交分享',
|
||||
route: '/global/share',
|
||||
title: '社交分享',
|
||||
desc: '配置分享平台、微信 JSAPI 与海报分享。',
|
||||
canonicalDomain: 'global',
|
||||
section: 'share',
|
||||
}),
|
||||
schemaPage({
|
||||
key: 'global-email',
|
||||
name: 'GlobalEmail',
|
||||
|
||||
@@ -57,16 +57,6 @@ export const postListSection = {
|
||||
canonicalDomain: 'post_list',
|
||||
section: 'feature',
|
||||
}),
|
||||
schemaPage({
|
||||
key: 'post-list-share',
|
||||
name: 'PostListShare',
|
||||
label: '分享设置',
|
||||
route: '/post-list/share',
|
||||
title: '分享设置',
|
||||
desc: '配置微信分享凭据、海报分享和社交分享选项。',
|
||||
canonicalDomain: 'post_list',
|
||||
section: 'share',
|
||||
}),
|
||||
schemaPage({
|
||||
key: 'post-list-comment',
|
||||
name: 'PostListComment',
|
||||
|
||||
@@ -14,6 +14,7 @@ import { customCodeSchema } from './custom-code.js'
|
||||
import { seoSchema } from './seo.js'
|
||||
import { codeHighlightSchema } from './code-highlight.js'
|
||||
import { systemNoticeSchema } from './system-notice.js'
|
||||
import { shareSchema } from './share.js'
|
||||
|
||||
export const globalSchemas = {
|
||||
logo: logoSchema,
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
const themeRoot = typeof window !== 'undefined' && window.aksrtAdminData?.themeUri
|
||||
? String(window.aksrtAdminData.themeUri).replace(/\/$/, '')
|
||||
: ''
|
||||
|
||||
const shareOptions = [
|
||||
{ label: 'QQ空间', value: 'qzone', icon: 'fa fab fa-qq' },
|
||||
{ label: '微博', value: 'weibo', icon: 'fa fab fa-weibo' },
|
||||
{ label: 'QQ好友', value: 'qq', icon: 'fa fab fa-qq' },
|
||||
{ label: 'Facebook', value: 'facebook', icon: 'fa fab fa-facebook-f' },
|
||||
{ label: 'X', value: 'twitter', icon: 'fa fab fa-twitter' },
|
||||
{ label: 'Telegram', value: 'telegram', icon: 'fa fab fa-telegram-plane' },
|
||||
{ label: 'WhatsApp', value: 'whatsapp', icon: 'fa fab fa-whatsapp' },
|
||||
{ label: 'LinkedIn', value: 'linkedin', icon: 'fa fab fa-linkedin-in' },
|
||||
{ label: 'Reddit', value: 'reddit', icon: 'fa fab fa-reddit-alien' },
|
||||
{ label: 'LINE', value: 'line', icon: 'fa fab fa-line' },
|
||||
{ label: 'VK', value: 'vk', icon: 'fa fab fa-vk' },
|
||||
{ label: '邮件', value: 'email', icon: 'fa fas fa-envelope' },
|
||||
{ label: '海报分享', value: 'poster', icon: 'fa fas fa-image' },
|
||||
{ label: '复制链接', value: 'copy', icon: 'fa fas fa-link' },
|
||||
]
|
||||
|
||||
const defaultShareItems = {
|
||||
enabled: { qzone: 'QQ空间', weibo: '微博', qq: 'QQ好友', poster: '海报分享', copy: '复制链接' },
|
||||
disabled: { facebook: 'Facebook', twitter: 'X', telegram: 'Telegram', whatsapp: 'WhatsApp', linkedin: 'LinkedIn', reddit: 'Reddit', line: 'LINE', vk: 'VK', email: '邮件' },
|
||||
}
|
||||
|
||||
export const shareSchema = {
|
||||
key: 'global.share',
|
||||
title: '社交分享',
|
||||
icon: 'fa fas fa-share-alt',
|
||||
description: '配置文章分享平台、微信 JSAPI 分享和海报分享。',
|
||||
defaults: {
|
||||
share_s: true,
|
||||
share_items: defaultShareItems,
|
||||
wechat_share_s: false,
|
||||
wechat_share_option: { appid: '', app_secret: '', only_logo: false },
|
||||
share_img: true,
|
||||
share_img_compatible_s: false,
|
||||
share_img_byimg: themeRoot ? `${themeRoot}/assets/img/slider-bg.jpg` : '',
|
||||
share_logo: themeRoot ? `${themeRoot}/assets/img/logo.png` : '',
|
||||
share_desc: '扫一扫 立即查看',
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
key: 'share',
|
||||
title: '社交分享',
|
||||
icon: 'fa fas fa-share-alt',
|
||||
fields: [
|
||||
{ key: 'share_s', label: '文章分享功能', type: 'switcher', default: true, help: '关闭后,在文章页面将不显示分享按钮。' },
|
||||
{
|
||||
key: 'share_items',
|
||||
label: '分享平台',
|
||||
type: 'custom',
|
||||
renderer: 'sorter',
|
||||
sanitize_type: 'array',
|
||||
default: defaultShareItems,
|
||||
options: shareOptions,
|
||||
description: '左侧启用并拖拽排序,右侧为未启用项(同时启用的数量不建议超过 6 个)。若开启海外平台,用户网络必须能正常访问对应服务。',
|
||||
},
|
||||
{ key: 'wechat_share_s', label: '微信分享有图', type: 'switcher', default: false, help: '使用微信 JSAPI 在微信 App 内分享。' },
|
||||
{
|
||||
key: 'wechat_share_hint',
|
||||
label: '',
|
||||
type: 'content',
|
||||
ui_only: true,
|
||||
dependsOn: { key: 'wechat_share_s', value: true },
|
||||
content: '<p><strong>微信分享有图配置</strong></p><p>此功能用于用户从公众号进入页面后调用微信默认分享能力,并不会额外显示分享按钮。请在公众号后台将当前站点域名配置为 JS 接口安全域名。</p><p><a href="https://mp.weixin.qq.com/" target="_blank" rel="noopener noreferrer">前往微信公众平台</a></p>',
|
||||
},
|
||||
{
|
||||
key: 'wechat_share_option',
|
||||
label: '微信分享有图配置',
|
||||
type: 'fieldset',
|
||||
default: { appid: '', app_secret: '', only_logo: false },
|
||||
dependsOn: { key: 'wechat_share_s', value: true },
|
||||
fields: [
|
||||
{ key: 'appid', label: 'AppID', type: 'input', default: '' },
|
||||
{ key: 'app_secret', label: 'AppSecret', type: 'input', default: '' },
|
||||
{ key: 'only_logo', label: '全部使用网站图标', type: 'switcher', default: false, help: '默认自动使用页面封面图;开启后所有页面均使用网站图标。图片启用防盗链时建议开启。' },
|
||||
],
|
||||
},
|
||||
{ key: 'share_img', label: '生成海报分享', type: 'switcher', default: true, help: '网站图片使用 OSS 等云存储时,请先配置允许本站 Canvas 读取图片的跨域规则。' },
|
||||
{
|
||||
key: 'share_img_warning',
|
||||
label: '',
|
||||
type: 'notice',
|
||||
ui_only: true,
|
||||
alertType: 'warning',
|
||||
content: '海报图片加载失败时,请检查图片 CDN/OSS 的跨域响应头。',
|
||||
dependsOn: { key: 'share_img', value: true },
|
||||
},
|
||||
{ key: 'share_img_compatible_s', label: '海报分享兼容模式', type: 'switcher', default: false, dependsOn: { key: 'share_img', value: true }, help: '通过服务端代理读取海报图片,改善跨域兼容性;会增加服务器图片处理开销。' },
|
||||
{ key: 'share_img_byimg', label: '海报分享默认图片', type: 'media', default: themeRoot ? `${themeRoot}/assets/img/slider-bg.jpg` : '', dependsOn: { key: 'share_img', value: true }, help: '文章没有图片时使用,建议尺寸 800×500。' },
|
||||
{ key: 'share_logo', label: '海报分享 LOGO', type: 'media', default: themeRoot ? `${themeRoot}/assets/img/logo.png` : '', dependsOn: { key: 'share_img', value: true }, help: '显示在海报底部,建议尺寸 300×100、大小 50KB 以内。' },
|
||||
{ key: 'share_desc', label: '海报分享底部文案', type: 'input', default: '扫一扫 立即查看', dependsOn: { key: 'share_img', value: true } },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import { pageSchema } from './page.js'
|
||||
import { filterSchema } from './filter.js'
|
||||
import { featureSchema } from './feature.js'
|
||||
import { paySchema } from './pay.js'
|
||||
import { shareSchema } from './share.js'
|
||||
import { commentSchema } from './comment.js'
|
||||
import { submitSchema } from './submit.js'
|
||||
|
||||
@@ -19,7 +18,6 @@ export const postListSchemas = {
|
||||
filter: filterSchema,
|
||||
feature: featureSchema,
|
||||
pay: paySchema,
|
||||
share: shareSchema,
|
||||
comment: commentSchema,
|
||||
submit: submitSchema,
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
export const shareSchema = {
|
||||
key: 'post_list.share',
|
||||
title: '分享设置',
|
||||
icon: 'fa fas fa-share-alt',
|
||||
description: '配置微信分享凭据、海报分享和社交分享选项。',
|
||||
defaults: {
|
||||
share_s: true,
|
||||
share_wechat_s: false,
|
||||
share_wechat_appid: '',
|
||||
share_wechat_app_secret: '',
|
||||
share_only_logo: false,
|
||||
share_img_compatible_s: false,
|
||||
share_img_byimg: '',
|
||||
share_logo: '',
|
||||
share_img: '',
|
||||
share_desc: '扫一扫 立即查看',
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
key: 'basic',
|
||||
title: '分享按钮',
|
||||
icon: 'fa fas fa-share-alt',
|
||||
fields: [
|
||||
{ key: 'share_s', label: '分享按钮', type: 'switch', default: true, help: '关闭后,在文章页面将不显示分享按钮,论坛及商城不受影响' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'wechat',
|
||||
title: '微信分享',
|
||||
icon: 'fa fab fa-weixin',
|
||||
fields: [
|
||||
{ key: 'share_wechat_s', label: '启用微信分享', type: 'switch', default: false, help: '启用后文章页将支持微信 JSAPI 分享' },
|
||||
{ key: 'share_wechat_appid', label: 'AppID', type: 'input', default: '', dependsOn: { key: 'share_wechat_s', value: true }, help: '微信公众号 AppID' },
|
||||
{ key: 'share_wechat_app_secret', label: 'AppSecret', type: 'input', default: '', dependsOn: { key: 'share_wechat_s', value: true }, help: '微信公众号 AppSecret(请确保 JS 安全域名已配置)' },
|
||||
{ key: 'share_only_logo', label: '仅显示 Logo', type: 'switch', default: false, help: '分享时仅显示站点 Logo' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'poster',
|
||||
title: '海报分享',
|
||||
icon: 'fa fas fa-image',
|
||||
fields: [
|
||||
{ key: 'share_img_compatible_s', label: '兼容模式', type: 'switch', default: false, help: '启用后使用兼容模式生成分享海报' },
|
||||
{ key: 'share_img_byimg', label: '海报默认图', type: 'media', default: '', help: '海报分享使用的默认背景图' },
|
||||
{ key: 'share_logo', label: '海报 LOGO', type: 'media', default: '', help: '海报上叠加的站点 LOGO' },
|
||||
{ key: 'share_img', label: '分享图片', type: 'media', default: '', help: '社交平台分享预览图' },
|
||||
{ key: 'share_desc', label: '分享描述', type: 'textarea', default: '扫一扫 立即查看', help: '海报或分享卡片的描述文案' },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -837,185 +837,6 @@ article.article.box-body,
|
||||
|
||||
.action-btn i { font-size: 1.2em; }
|
||||
|
||||
/* ===== 分享下拉面板 ===== */
|
||||
|
||||
/* 确保父容器作为定位参考 */
|
||||
.share-dropdown {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: calc(100% + 8px);
|
||||
transform: translateX(-50%);
|
||||
z-index: 100;
|
||||
/* 默认隐藏 — 最高优先级确保不被覆盖 */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.share-dropdown[aria-hidden="false"] {
|
||||
display: block !important;
|
||||
animation: shareDropdownIn 0.2s ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes shareDropdownIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translateY(8px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.share-dropdown__grid {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 16px;
|
||||
background: var(--surface-page);
|
||||
border: 1px solid var(--color-line);
|
||||
border-radius: var(--radius-lg, 8px);
|
||||
box-shadow: var(--shadow-md, 0 4px 16px rgba(0,0,0,0.1));
|
||||
}
|
||||
|
||||
.share-item {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 8px 12px;
|
||||
border: none;
|
||||
border-radius: var(--radius-btn, 6px);
|
||||
background: transparent;
|
||||
color: var(--color-ink-2, var(--color-ink-3));
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
transition: background 0.15s, color 0.15s, transform 0.15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.share-item:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.share-item i {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.share-item[data-platform="qq"]:hover { background: #e8f4fd; color: #12b7f5; }
|
||||
.share-item[data-platform="weibo"]:hover { background: #fceae9; color: #ff6a00; }
|
||||
.share-item[data-platform="twitter"]:hover { background: #f0f0f0; color: #000; }
|
||||
.share-item[data-platform="wechat"]:hover { background: #e6f7ec; color: #07c160; }
|
||||
.share-item[data-platform="copy"]:hover { background: #f0f2f5; color: #555; }
|
||||
.share-item[data-platform="poster"]:hover { background: #fff4e8; color: #f59e0b; }
|
||||
|
||||
/* 微信二维码浮层 */
|
||||
#share-qrcode-box {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 10px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 14px;
|
||||
background: var(--surface-page);
|
||||
border: 1px solid var(--color-line);
|
||||
border-radius: var(--radius-lg, 8px);
|
||||
box-shadow: var(--shadow-md, 0 4px 16px rgba(0,0,0,0.12));
|
||||
text-align: center;
|
||||
z-index: 101;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
#share-qrcode-box.is-visible {
|
||||
pointer-events: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#share-qrcode-image {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 暗色模式 */
|
||||
.theme-dark .share-dropdown__grid,
|
||||
html.dark .share-dropdown__grid {
|
||||
background: var(--surface-1);
|
||||
border-color: var(--color-line);
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.35);
|
||||
}
|
||||
|
||||
.theme-dark #share-qrcode-box,
|
||||
html.dark #share-qrcode-box {
|
||||
background: var(--surface-1);
|
||||
border-color: var(--color-line);
|
||||
}
|
||||
|
||||
.theme-dark .share-item,
|
||||
html.dark .share-item {
|
||||
color: var(--color-ink-2, #aaa);
|
||||
}
|
||||
|
||||
.theme-dark .share-item[data-platform="qq"]:hover { background: rgba(18,183,245,0.12); color: #12b7f5; }
|
||||
.theme-dark .share-item[data-platform="weibo"]:hover { background: rgba(255,106,0,0.12); color: #ff6a00; }
|
||||
.theme-dark .share-item[data-platform="twitter"]:hover { background: rgba(255,255,255,0.08); color: #fff; }
|
||||
.theme-dark .share-item[data-platform="wechat"]:hover { background: rgba(7,193,96,0.12); color: #07c160; }
|
||||
.theme-dark .share-item[data-platform="copy"]:hover { background: rgba(255,255,255,0.06); color: #ccc; }
|
||||
.theme-dark .share-item[data-platform="poster"]:hover { background: rgba(245,158,11,0.12); color: #f59e0b; }
|
||||
|
||||
/* Narrow screens: bottom sheet so dropdown never clips off-screen */
|
||||
@media (max-width: 767px) {
|
||||
.share-dropdown {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
transform: none;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
z-index: 1200;
|
||||
padding: 0 0 calc(12px + env(safe-area-inset-bottom, 0px));
|
||||
background: transparent;
|
||||
}
|
||||
.share-dropdown[aria-hidden="false"] {
|
||||
animation: shareSheetIn 0.22s ease-out forwards;
|
||||
}
|
||||
@keyframes shareSheetIn {
|
||||
from { opacity: 0; transform: translateY(16px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.share-dropdown__grid {
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin: 0 10px;
|
||||
padding: 14px 12px 16px;
|
||||
border-radius: 14px 14px 10px 10px;
|
||||
box-shadow: 0 -6px 28px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
.share-item {
|
||||
min-width: 64px;
|
||||
flex: 1 1 28%;
|
||||
max-width: 33%;
|
||||
}
|
||||
#share-qrcode-box {
|
||||
position: static;
|
||||
margin: 10px auto 0;
|
||||
transform: none;
|
||||
}
|
||||
body.aksrt-share-sheet-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
body.aksrt-share-sheet-open::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
z-index: 1190;
|
||||
}
|
||||
}
|
||||
|
||||
.theme-dark .post-drop-meta__menu,
|
||||
html.dark .post-drop-meta__menu {
|
||||
background: var(--surface-1, #323335);
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
.relative{position:relative}.flex{display:flex}.flex.ac,.ac{align-items:center}.flex.jc,.jc{justify-content:center}.flex.jsb,.jsb{justify-content:space-between}.flex.at,.at{align-items:flex-start}.flex.ae,.ae{align-items:flex-end}.flex0{flex:0 0 auto}.flex1{flex:1 1 auto;min-width:0}.flex.column{flex-direction:column}.flex.wrap{flex-wrap:wrap}.flex.flex-row,.flex-row{flex-direction:row}.flex.jse,.jse{justify-content:space-evenly}.flex.jsa,.jsa{justify-content:space-around}.flex>.flex1,.flex .flex1{flex:1;overflow:hidden;min-width:0}.relative-h{position:relative;height:100%}.padding-10{padding:10px}.font-bold{font-weight:700}.mt6{margin-top:6px}.gutters-5{margin:-5px}.gutters-5>*{padding:5px}@media(max-width:767px){.flex.flex-row.flex-col-sm-2{flex-wrap:wrap}.flex.flex-row.flex-col-sm-2>*{flex-basis:50%}}.clearfix:before,.clearfix:after{content:"";display:table}.clearfix:after{clear:both}.abs-right{position:absolute;right:0;top:0}.abs-center{position:absolute;left:0;width:100%;top:50%;right:.7em;transform:translateY(-50%);z-index:1}.abs-center.left-top,.abs-center.right-top{transform:unset;top:0}.abs-center.right-top{left:auto;width:auto;text-align:right}.abs-center.left-top{text-align:left}.abs-center.conter-bottom,.abs-center.conter-conter{text-align:center}.abs-center.right-top,.abs-center.right-bottom,.abs-center.right-conter{text-align:right}.abs-center.conter-bottom,.abs-center.right-bottom,.abs-center.left-bottom{top:auto;transform:unset;bottom:0}.abs-center.left-bottom{left:0;right:auto;text-align:left}.abs-center.right-bottom,.abs-center.right-conter{left:auto;right:0;text-align:right}.graphic,.page-cover{text-shadow:0 0 5px rgba(0,0,0,.2);--main-color: #fff;color:#fff;position:relative;overflow:hidden;box-shadow:0 0 10px var(--main-shadow, rgba(116, 116, 116, .08));padding:0 0 70%;border-radius:var(--main-radius, var(--radius, 8px))}.graphic>.fit-cover,.graphic>img.fit-cover{position:absolute;width:100%;height:100%;object-fit:cover;inset:0}.fit-cover{object-fit:cover;max-width:100%}.title-h-left{position:relative;padding-bottom:8px}.title-h-left:before{transition:.4s;transform-origin:left;position:absolute;content:"";width:40px;height:3px;background:var(--theme-color, var(--focus-color, #f04494));left:0;bottom:3px;border-radius:5px;box-shadow:1px 1px 3px -1px var(--theme-color, var(--focus-color, #f04494))}.line-form-line,.line-form-line:before{position:absolute;bottom:0;left:0;height:1px;width:100%;transition:.8s;background:var(--main-border-color, rgba(50, 50, 50, .06))}.line-form-line:before{content:"";width:0;background:var(--focus-color, #f04494)}.avatar-img{position:relative;display:inline-block;flex-shrink:0;--this-size: 38px;width:var(--this-size);height:var(--this-size)}.avatar-img .avatar,.avatar-img img{width:100%;height:100%;border-radius:50%;object-fit:cover}.avatar-lg{--this-size: 80px}.avatar-md{--this-size: 55px}.avatar-mini{--this-size: 20px}.shrink0{flex-shrink:0}.opacity8{opacity:.8}.muted-color{color:var(--muted-color, var(--color-ink-3))}.muted-2-color{color:var(--muted-2-color, var(--color-ink-4))}.muted-3-color{color:var(--muted-3-color, #b1b1b1)}.muted-4-color{color:var(--muted-4-color, #d2d2d2)}.text-center{text-align:center}.em09{font-size:.9em}.em12{font-size:1.2em}.px12-sm{font-size:12px}.ml3{margin-left:3px}.ml6{margin-left:6px}.ml10{margin-left:10px}.mr3{margin-right:3px}.mr6{margin-right:6px}.mt10{margin-top:10px}.mt20{margin-top:20px}.mb10{margin-bottom:10px}.mb20{margin-bottom:20px}.text-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.text-ellipsis-2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;word-break:break-word}.main-bg{background-color:var(--main-bg-color, var(--surface-1))}.separator{position:relative;letter-spacing:.08em}.icon-circle+.icon-circle:before{content:"·";display:inline-block;margin:0 .45em;opacity:.55}.article-avatar name,.article-avatar .name,.user-name{display:inline-flex;align-items:center;gap:4px;min-width:0;max-width:100%}.pull-right{float:right}.pull-left{float:left}body.single main.container .content-layout{display:block;min-width:0}body.single main.container .content-layout>*{min-width:0;max-width:100%}body.single main.container .content-layout>.breadcrumb,body.single main.container .content-layout>ul.breadcrumb,body.single main.container .content-layout>.breadcrumb-nav,body.single main.container .content-layout>.breadcrumbs-wrap{position:relative;z-index:1;margin-top:0;margin-bottom:12px;padding-top:2px}body.single .sidebar .aksrt-panel,body.single .sidebar .widget{margin-bottom:15px}body.single main.container{box-sizing:border-box}.article,article.article.box-body,.article.main-bg.box-body{padding:0 30px;overflow:hidden}@media(max-width:767px){.article,article.article.box-body,.article.main-bg.box-body{padding:0 15px}.article-header .article-title{font-size:18px}}.entry-header,.article-header{margin-bottom:10px;padding-bottom:0;border-bottom:none;background:tranLine truncated
|
||||
.relative{position:relative}.flex{display:flex}.flex.ac,.ac{align-items:center}.flex.jc,.jc{justify-content:center}.flex.jsb,.jsb{justify-content:space-between}.flex.at,.at{align-items:flex-start}.flex.ae,.ae{align-items:flex-end}.flex0{flex:0 0 auto}.flex1{flex:1 1 auto;min-width:0}.flex.column{flex-direction:column}.flex.wrap{flex-wrap:wrap}.flex.flex-row,.flex-row{flex-direction:row}.flex.jse,.jse{justify-content:space-evenly}.flex.jsa,.jsa{justify-content:space-around}.flex>.flex1,.flex .flex1{flex:1;overflow:hidden;min-width:0}.relative-h{position:relative;height:100%}.padding-10{padding:10px}.font-bold{font-weight:700}.mt6{margin-top:6px}.gutters-5{margin:-5px}.gutters-5>*{padding:5px}@media(max-width:767px){.flex.flex-row.flex-col-sm-2{flex-wrap:wrap}.flex.flex-row.flex-col-sm-2>*{flex-basis:50%}}.clearfix:before,.clearfix:after{content:"";display:table}.clearfix:after{clear:both}.abs-right{position:absolute;right:0;top:0}.abs-center{position:absolute;left:0;width:100%;top:50%;right:.7em;transform:translateY(-50%);z-index:1}.abs-center.left-top,.abs-center.right-top{transform:unset;top:0}.abs-center.right-top{left:auto;width:auto;text-align:right}.abs-center.left-top{text-align:left}.abs-center.conter-bottom,.abs-center.conter-conter{text-align:center}.abs-center.right-top,.abs-center.right-bottom,.abs-center.right-conter{text-align:right}.abs-center.conter-bottom,.abs-center.right-bottom,.abs-center.left-bottom{top:auto;transform:unset;bottom:0}.abs-center.left-bottom{left:0;right:auto;text-align:left}.abs-center.right-bottom,.abs-center.right-conter{left:auto;right:0;text-align:right}.graphic,.page-cover{text-shadow:0 0 5px rgba(0,0,0,.2);--main-color: #fff;color:#fff;position:relative;overflow:hidden;box-shadow:0 0 10px var(--main-shadow, rgba(116, 116, 116, .08));padding:0 0 70%;border-radius:var(--main-radius, var(--radius, 8px))}.graphic>.fit-cover,.graphic>img.fit-cover{position:absolute;width:100%;height:100%;object-fit:cover;inset:0}.fit-cover{object-fit:cover;max-width:100%}.title-h-left{position:relative;padding-bottom:8px}.title-h-left:before{transition:.4s;transform-origin:left;position:absolute;content:"";width:40px;height:3px;background:var(--theme-color, var(--focus-color, #f04494));left:0;bottom:3px;border-radius:5px;box-shadow:1px 1px 3px -1px var(--theme-color, var(--focus-color, #f04494))}.line-form-line,.line-form-line:before{position:absolute;bottom:0;left:0;height:1px;width:100%;transition:.8s;background:var(--main-border-color, rgba(50, 50, 50, .06))}.line-form-line:before{content:"";width:0;background:var(--focus-color, #f04494)}.avatar-img{position:relative;display:inline-block;flex-shrink:0;--this-size: 38px;width:var(--this-size);height:var(--this-size)}.avatar-img .avatar,.avatar-img img{width:100%;height:100%;border-radius:50%;object-fit:cover}.avatar-lg{--this-size: 80px}.avatar-md{--this-size: 55px}.avatar-mini{--this-size: 20px}.shrink0{flex-shrink:0}.opacity8{opacity:.8}.muted-color{color:var(--muted-color, var(--color-ink-3))}.muted-2-color{color:var(--muted-2-color, var(--color-ink-4))}.muted-3-color{color:var(--muted-3-color, #b1b1b1)}.muted-4-color{color:var(--muted-4-color, #d2d2d2)}.text-center{text-align:center}.em09{font-size:.9em}.em12{font-size:1.2em}.px12-sm{font-size:12px}.ml3{margin-left:3px}.ml6{margin-left:6px}.ml10{margin-left:10px}.mr3{margin-right:3px}.mr6{margin-right:6px}.mt10{margin-top:10px}.mt20{margin-top:20px}.mb10{margin-bottom:10px}.mb20{margin-bottom:20px}.text-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.text-ellipsis-2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;word-break:break-word}.main-bg{background-color:var(--main-bg-color, var(--surface-1))}.separator{position:relative;letter-spacing:.08em}.icon-circle+.icon-circle:before{content:"·";display:inline-block;margin:0 .45em;opacity:.55}.article-avatar name,.article-avatar .name,.user-name{display:inline-flex;align-items:center;gap:4px;min-width:0;max-width:100%}.pull-right{float:right}.pull-left{float:left}body.single main.container .content-layout{display:block;min-width:0}body.single main.container .content-layout>*{min-width:0;max-width:100%}body.single main.container .content-layout>.breadcrumb,body.single main.container .content-layout>ul.breadcrumb,body.single main.container .content-layout>.breadcrumb-nav,body.single main.container .content-layout>.breadcrumbs-wrap{position:relative;z-index:1;margin-top:0;margin-bottom:12px;padding-top:2px}body.single .sidebar .aksrt-panel,body.single .sidebar .widget{margin-bottom:15px}body.single main.container{box-sizing:border-box}.article,article.article.box-body,.article.main-bg.box-body{padding:0 30px;overflow:hidden}@media(max-width:767px){.article,article.article.box-body,.article.main-bg.box-body{padding:0 15px}.article-header .article-title{font-size:18px}}.entry-header,.article-header{margin-bottom:10px;padding-bottom:0;border-bottom:none;background:tranLine truncated
|
||||
@@ -157,185 +157,6 @@
|
||||
|
||||
.action-btn i { font-size: 1.2em; }
|
||||
|
||||
/* ===== 分享下拉面板 ===== */
|
||||
|
||||
/* 确保父容器作为定位参考 */
|
||||
.share-dropdown {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: calc(100% + 8px);
|
||||
transform: translateX(-50%);
|
||||
z-index: 100;
|
||||
/* 默认隐藏 — 最高优先级确保不被覆盖 */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.share-dropdown[aria-hidden="false"] {
|
||||
display: block !important;
|
||||
animation: shareDropdownIn 0.2s ease-out forwards;
|
||||
}
|
||||
|
||||
@keyframes shareDropdownIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-50%) translateY(8px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.share-dropdown__grid {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 16px;
|
||||
background: var(--surface-page);
|
||||
border: 1px solid var(--color-line);
|
||||
border-radius: var(--radius-lg, 8px);
|
||||
box-shadow: var(--shadow-md, 0 4px 16px rgba(0,0,0,0.1));
|
||||
}
|
||||
|
||||
.share-item {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 8px 12px;
|
||||
border: none;
|
||||
border-radius: var(--radius-btn, 6px);
|
||||
background: transparent;
|
||||
color: var(--color-ink-2, var(--color-ink-3));
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
transition: background 0.15s, color 0.15s, transform 0.15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.share-item:hover {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.share-item i {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.share-item[data-platform="qq"]:hover { background: #e8f4fd; color: #12b7f5; }
|
||||
.share-item[data-platform="weibo"]:hover { background: #fceae9; color: #ff6a00; }
|
||||
.share-item[data-platform="twitter"]:hover { background: #f0f0f0; color: #000; }
|
||||
.share-item[data-platform="wechat"]:hover { background: #e6f7ec; color: #07c160; }
|
||||
.share-item[data-platform="copy"]:hover { background: #f0f2f5; color: #555; }
|
||||
.share-item[data-platform="poster"]:hover { background: #fff4e8; color: #f59e0b; }
|
||||
|
||||
/* 微信二维码浮层 */
|
||||
#share-qrcode-box {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 10px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: 14px;
|
||||
background: var(--surface-page);
|
||||
border: 1px solid var(--color-line);
|
||||
border-radius: var(--radius-lg, 8px);
|
||||
box-shadow: var(--shadow-md, 0 4px 16px rgba(0,0,0,0.12));
|
||||
text-align: center;
|
||||
z-index: 101;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
#share-qrcode-box.is-visible {
|
||||
pointer-events: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#share-qrcode-image {
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 暗色模式 */
|
||||
.theme-dark .share-dropdown__grid,
|
||||
html.dark .share-dropdown__grid {
|
||||
background: var(--surface-1);
|
||||
border-color: var(--color-line);
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.35);
|
||||
}
|
||||
|
||||
.theme-dark #share-qrcode-box,
|
||||
html.dark #share-qrcode-box {
|
||||
background: var(--surface-1);
|
||||
border-color: var(--color-line);
|
||||
}
|
||||
|
||||
.theme-dark .share-item,
|
||||
html.dark .share-item {
|
||||
color: var(--color-ink-2, #aaa);
|
||||
}
|
||||
|
||||
.theme-dark .share-item[data-platform="qq"]:hover { background: rgba(18,183,245,0.12); color: #12b7f5; }
|
||||
.theme-dark .share-item[data-platform="weibo"]:hover { background: rgba(255,106,0,0.12); color: #ff6a00; }
|
||||
.theme-dark .share-item[data-platform="twitter"]:hover { background: rgba(255,255,255,0.08); color: #fff; }
|
||||
.theme-dark .share-item[data-platform="wechat"]:hover { background: rgba(7,193,96,0.12); color: #07c160; }
|
||||
.theme-dark .share-item[data-platform="copy"]:hover { background: rgba(255,255,255,0.06); color: #ccc; }
|
||||
.theme-dark .share-item[data-platform="poster"]:hover { background: rgba(245,158,11,0.12); color: #f59e0b; }
|
||||
|
||||
/* Narrow screens: bottom sheet so dropdown never clips off-screen */
|
||||
@media (max-width: 767px) {
|
||||
.share-dropdown {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
transform: none;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
z-index: 1200;
|
||||
padding: 0 0 calc(12px + env(safe-area-inset-bottom, 0px));
|
||||
background: transparent;
|
||||
}
|
||||
.share-dropdown[aria-hidden="false"] {
|
||||
animation: shareSheetIn 0.22s ease-out forwards;
|
||||
}
|
||||
@keyframes shareSheetIn {
|
||||
from { opacity: 0; transform: translateY(16px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
.share-dropdown__grid {
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
margin: 0 10px;
|
||||
padding: 14px 12px 16px;
|
||||
border-radius: 14px 14px 10px 10px;
|
||||
box-shadow: 0 -6px 28px rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
.share-item {
|
||||
min-width: 64px;
|
||||
flex: 1 1 28%;
|
||||
max-width: 33%;
|
||||
}
|
||||
#share-qrcode-box {
|
||||
position: static;
|
||||
margin: 10px auto 0;
|
||||
transform: none;
|
||||
}
|
||||
body.aksrt-share-sheet-open {
|
||||
overflow: hidden;
|
||||
}
|
||||
body.aksrt-share-sheet-open::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
z-index: 1190;
|
||||
}
|
||||
}
|
||||
|
||||
.theme-dark .post-drop-meta__menu,
|
||||
html.dark .post-drop-meta__menu {
|
||||
background: var(--surface-1, #323335);
|
||||
|
||||
@@ -8887,6 +8887,26 @@ img.alignleft {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.share-btn icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: inline-flex;
|
||||
border-radius: 100%;
|
||||
background: var(--main-border-color);
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 22px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.share-btn icon .icon {
|
||||
margin: auto !important;
|
||||
}
|
||||
|
||||
.share-button .share-btn icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.share-button .share-btn .icon {
|
||||
width: 1em;
|
||||
font-size: inherit;
|
||||
@@ -8907,6 +8927,14 @@ img.alignleft {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.horizontal .share-btn icon {
|
||||
display: flex;
|
||||
margin-bottom: 6px;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.drop-newadd {
|
||||
border-radius: var(--main-radius);
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
body{--mian-max-width: 1200px;--posts-card-scale: 70%;--posts-list-scale: 70%;--theme-color: #f04494;--focus-color: var(--theme-color);--focus-shadow-color: rgba(253, 83, 161, .4);--key-color: #333;--main-color: #4e5358;--main-shadow: rgba(116, 116, 116, .08);--muted-color: #777;--muted-2-color: #999;--muted-3-color: #b1b1b1;--muted-4-color: #d2d2d2;--body-bg-color: #f5f6f7;--main-bg-color: #fff;--muted-bg-color: #eee;--muted-bg-2-color: #f6f7f8;--main-border-color: rgba(50, 50, 50, .06);--muted-border-color: rgba(0, 0, 0, .03);--main-radius: 8px;--mini-radius: calc(var(--main-radius) / 1.4);--blur-bg: rgba(255, 255, 255, .8);--float-btn-bg: rgba(200, 200, 200, .4);--header-bg: var(--blur-bg);--header-color: var(--main-color);--footer-bg: var(--main-bg-color);--footer-color: var(--muted-2-color)}.dark-theme{--key-color: #f8fafc;--main-color: #e5eef7;--main-shadow: rgba(24, 24, 24, .1);--muted-color: #b4b6bb;--muted-2-color: #888a8f;--muted-3-color: #636469;--muted-4-color: #43454a;--body-bg-color: #292a2d;--main-bg-color: #323335;--muted-bg-color: #2d2e31;--muted-bg-2-color: #37383a;--main-border-color: rgba(114, 114, 114, .1);--muted-border-color: rgba(184, 184, 184, .02);--blur-bg: rgba(50, 51, 53, .8);--float-btn-bg: rgba(70, 70, 70, .4);--header-bg: var(--blur-bg);--header-color: var(--main-color);--footer-bg: var(--main-bg-color);--footer-color: var(--muted-2-color)}::view-transition-old(root),::view-transition-new(root){animation:none;mix-blend-mode:normal}.dark::view-transition-old(root){z-index:1}.dark::view-transition-new(root){z-index:2147483646}::view-transition-old(root){z-index:2147483646}::view-transition-new(root){z-index:1}@supports not ((-webkit-backdrop-filter: blur(20px)) or (backdrop-filter: blur(20px))){body{--blur-bg: #ffffff}body.dark-theme{--blur-bg: #37383a}}body:has(.modal.in),body.modal-open{--blur-bg: #ffffff}body.dark-theme:has(.modal.in),body.dark-theme.modal-open{--blur-bg: #37383a}body.fps-accelerat{--blur-bg: #ffffff}body.fps-accelerat.dark-theme{--blur-bg: #37383a}body.fps-accelerat *{-webkit-backdrop-filter:unset!important;backdrop-filter:unset!important}a[href],.relates-thumb li a>.post-info,.more-posts a>span{transition:color .2s,background .3s,opacity .3s,box-shadow .3s,transform .3s}.main-shadow{transition:box-shadow .3s}.but:focus,.but:hover,.progress,.navbar-nav>li:before{transition:.3s}.navbar-top .sub-menu,.theme-popover,.hover-show .hover-show-con{opacity:0;transform:translateY(6px);transition:.4s}.navbar-top li:hover>.sub-menu,.hover-show:hover .hover-show-con,.hover-show:hover~.hover-show-con,.hover-show:hover~.sub-menu{opacity:1;transform:translateY(0)}.hover-show{position:relative;cursor:pointer;z-index:10}.hover-show .hover-show-con{position:absolute;visibility:hidden}.hover-show:hover .hover-show-con,.hover-show:hover~.hover-show-con,.hover-show:hover~.sub-menu{visibility:unset}.match-ok,.navbar-top .sub-menu li>a,.ic-close{transition:.3s}.ic-close:hover{transform:rotate(270deg);color:inherit}.social_loginbar a,.item-thumbnail img,.dosc-nav .fa{transition:.2s ease-out}.hover-zoom:hover,.hover-zoom-img:hover img,.social_loginbar .xh-social-item:hover,.social_loginbar .social-login-item:hover{transform:scale(1.05)}.hover-zoom-sm:hover,.hover-zoom-img-sm:hover img,.posts-mini:hover img,.posts-item:hover .item-thumbnail img,.posts-item.mult-thumb .thumb-items>span>img:hover{transform:scale(1.02)}.main-min-height{min-height:calc(100vh - 280px)}.main-shadow{box-shadow:0 0 10px var(--main-shadow)}.key-color{color:var(--key-color)}.focus-color{--this-color: var(--focus-color);color:var(--focus-color)}.muted-color{color:var(--muted-color)}.muted-2-color{color:var(--muted-2-color)}.muted-3-color{color:var(--muted-3-color)}.main-bg{background:var(--main-bg-color)}.placeholder{background:linear-gradient(118deg,#7979791a 25%,#79797933 37%,#7979791a 63%);opacity:1;border-radius:4px;-webkit-animation:placeholder 1.5s ease infinite!important;animation:placeholder 1.5s ease infinite!important;background-size:400% 100%!important}.placeholder.img{height:119px}.placeholder.t1{height:24px;width:80%}.placeholder.k1{height:20px;width:60%}.placeholder.k2{height:20px}.placeholder.k3{height:15px}.placeholder.s1{width:70px;height:15px;display:inline-block}@-webkit-keyframes placeholder{0%{background-position:100% 50%}to{background-position:0 50%}}@keyframes placeholder{0%{background-position:100% 50%}to{background-position:0 50%}}@-webkit-keyframes fade{0%{opacity:0}to{opacity:1}}@keyframes fade{0%{opacity:0}to{opacity:1}}.ani.shake{-webkit-animation:shake .3s ease-in!important;animation:shake .3s ease-in!important}@-webkit-keyframes shake{20%{transform:translate(2px)}40%{transform:translate(-4px)}60%{transform:translate(5px)}80%{transform:translate(3px)}to{transform:translate(0)}}@keyframes shake{20%{transform:translate(2px)}40%{transform:translate(-4px)}60%{transform:translate(5px)}80%{transform:translate(3px)}to{transform:translate(0)}}.obs-animate{opacity:0;transition:opacity .6sLine truncated
|
||||
body{--mian-max-width: 1200px;--posts-card-scale: 70%;--posts-list-scale: 70%;--theme-color: #f04494;--focus-color: var(--theme-color);--focus-shadow-color: rgba(253, 83, 161, .4);--key-color: #333;--main-color: #4e5358;--main-shadow: rgba(116, 116, 116, .08);--muted-color: #777;--muted-2-color: #999;--muted-3-color: #b1b1b1;--muted-4-color: #d2d2d2;--body-bg-color: #f5f6f7;--main-bg-color: #fff;--muted-bg-color: #eee;--muted-bg-2-color: #f6f7f8;--main-border-color: rgba(50, 50, 50, .06);--muted-border-color: rgba(0, 0, 0, .03);--main-radius: 8px;--mini-radius: calc(var(--main-radius) / 1.4);--blur-bg: rgba(255, 255, 255, .8);--float-btn-bg: rgba(200, 200, 200, .4);--header-bg: var(--blur-bg);--header-color: var(--main-color);--footer-bg: var(--main-bg-color);--footer-color: var(--muted-2-color)}.dark-theme{--key-color: #f8fafc;--main-color: #e5eef7;--main-shadow: rgba(24, 24, 24, .1);--muted-color: #b4b6bb;--muted-2-color: #888a8f;--muted-3-color: #636469;--muted-4-color: #43454a;--body-bg-color: #292a2d;--main-bg-color: #323335;--muted-bg-color: #2d2e31;--muted-bg-2-color: #37383a;--main-border-color: rgba(114, 114, 114, .1);--muted-border-color: rgba(184, 184, 184, .02);--blur-bg: rgba(50, 51, 53, .8);--float-btn-bg: rgba(70, 70, 70, .4);--header-bg: var(--blur-bg);--header-color: var(--main-color);--footer-bg: var(--main-bg-color);--footer-color: var(--muted-2-color)}::view-transition-old(root),::view-transition-new(root){animation:none;mix-blend-mode:normal}.dark::view-transition-old(root){z-index:1}.dark::view-transition-new(root){z-index:2147483646}::view-transition-old(root){z-index:2147483646}::view-transition-new(root){z-index:1}@supports not ((-webkit-backdrop-filter: blur(20px)) or (backdrop-filter: blur(20px))){body{--blur-bg: #ffffff}body.dark-theme{--blur-bg: #37383a}}body:has(.modal.in),body.modal-open{--blur-bg: #ffffff}body.dark-theme:has(.modal.in),body.dark-theme.modal-open{--blur-bg: #37383a}body.fps-accelerat{--blur-bg: #ffffff}body.fps-accelerat.dark-theme{--blur-bg: #37383a}body.fps-accelerat *{-webkit-backdrop-filter:unset!important;backdrop-filter:unset!important}a[href],.relates-thumb li a>.post-info,.more-posts a>span{transition:color .2s,background .3s,opacity .3s,box-shadow .3s,transform .3s}.main-shadow{transition:box-shadow .3s}.but:focus,.but:hover,.progress,.navbar-nav>li:before{transition:.3s}.navbar-top .sub-menu,.theme-popover,.hover-show .hover-show-con{opacity:0;transform:translateY(6px);transition:.4s}.navbar-top li:hover>.sub-menu,.hover-show:hover .hover-show-con,.hover-show:hover~.hover-show-con,.hover-show:hover~.sub-menu{opacity:1;transform:translateY(0)}.hover-show{position:relative;cursor:pointer;z-index:10}.hover-show .hover-show-con{position:absolute;visibility:hidden}.hover-show:hover .hover-show-con,.hover-show:hover~.hover-show-con,.hover-show:hover~.sub-menu{visibility:unset}.match-ok,.navbar-top .sub-menu li>a,.ic-close{transition:.3s}.ic-close:hover{transform:rotate(270deg);color:inherit}.social_loginbar a,.item-thumbnail img,.dosc-nav .fa{transition:.2s ease-out}.hover-zoom:hover,.hover-zoom-img:hover img,.social_loginbar .xh-social-item:hover,.social_loginbar .social-login-item:hover{transform:scale(1.05)}.hover-zoom-sm:hover,.hover-zoom-img-sm:hover img,.posts-mini:hover img,.posts-item:hover .item-thumbnail img,.posts-item.mult-thumb .thumb-items>span>img:hover{transform:scale(1.02)}.main-min-height{min-height:calc(100vh - 280px)}.main-shadow{box-shadow:0 0 10px var(--main-shadow)}.key-color{color:var(--key-color)}.focus-color{--this-color: var(--focus-color);color:var(--focus-color)}.muted-color{color:var(--muted-color)}.muted-2-color{color:var(--muted-2-color)}.muted-3-color{color:var(--muted-3-color)}.main-bg{background:var(--main-bg-color)}.placeholder{background:linear-gradient(118deg,#7979791a 25%,#79797933 37%,#7979791a 63%);opacity:1;border-radius:4px;-webkit-animation:placeholder 1.5s ease infinite!important;animation:placeholder 1.5s ease infinite!important;background-size:400% 100%!important}.placeholder.img{height:119px}.placeholder.t1{height:24px;width:80%}.placeholder.k1{height:20px;width:60%}.placeholder.k2{height:20px}.placeholder.k3{height:15px}.placeholder.s1{width:70px;height:15px;display:inline-block}@-webkit-keyframes placeholder{0%{background-position:100% 50%}to{background-position:0 50%}}@keyframes placeholder{0%{background-position:100% 50%}to{background-position:0 50%}}@-webkit-keyframes fade{0%{opacity:0}to{opacity:1}}@keyframes fade{0%{opacity:0}to{opacity:1}}.ani.shake{-webkit-animation:shake .3s ease-in!important;animation:shake .3s ease-in!important}@-webkit-keyframes shake{20%{transform:translate(2px)}40%{transform:translate(-4px)}60%{transform:translate(5px)}80%{transform:translate(3px)}to{transform:translate(0)}}@keyframes shake{20%{transform:translate(2px)}40%{transform:translate(-4px)}60%{transform:translate(5px)}80%{transform:translate(3px)}to{transform:translate(0)}}.obs-animate{opacity:0;transition:opacity .6sLine truncated
|
||||
@@ -1,305 +0,0 @@
|
||||
/**
|
||||
* AKSRT Post Share
|
||||
*
|
||||
* Handles share dropdowns, social share targets, copy link,
|
||||
* and WeChat bridge handoff with QR fallback.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function getMetaContent(selectors) {
|
||||
for (var i = 0; i < selectors.length; i += 1) {
|
||||
var node = document.querySelector(selectors[i]);
|
||||
var content = node ? node.getAttribute('content') : '';
|
||||
if (content) return content;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function getPlatform(node) {
|
||||
if (!node) return '';
|
||||
return node.getAttribute('data-share-platform') || node.getAttribute('data-platform') || '';
|
||||
}
|
||||
|
||||
function resolvePayload(node) {
|
||||
// Unified payload via the shared builder; fall back to local resolution
|
||||
// only if the builder script is unavailable.
|
||||
if (window.AksrtShareData && typeof window.AksrtShareData.resolve === 'function') {
|
||||
return window.AksrtShareData.resolve(node);
|
||||
}
|
||||
|
||||
var dropdown = document.getElementById('share-dropdown');
|
||||
var source = node && typeof node.closest === 'function'
|
||||
? node.closest('[data-share-url], [data-share-title], [data-share-desc], [data-share-image]')
|
||||
: null;
|
||||
var context = source || dropdown;
|
||||
|
||||
function readAttr(name) {
|
||||
return (node && node.getAttribute(name)) || (context && context.getAttribute(name)) || '';
|
||||
}
|
||||
|
||||
return {
|
||||
title: readAttr('data-share-title') || document.title,
|
||||
url: readAttr('data-share-url') || window.location.href,
|
||||
desc: readAttr('data-share-desc') || getMetaContent(['meta[property="og:description"]', 'meta[name="description"]']),
|
||||
text: readAttr('data-share-text') || '',
|
||||
image: readAttr('data-share-image') || getMetaContent(['meta[property="og:image"]']),
|
||||
qrcode: readAttr('data-share-qrcode') || ''
|
||||
};
|
||||
}
|
||||
|
||||
function openWindow(url) {
|
||||
if (!url) return;
|
||||
window.open(url, '_blank', 'width=640,height=560,scrollbars=yes,resizable=yes');
|
||||
}
|
||||
|
||||
function buildShareUrl(platform, payload) {
|
||||
switch (platform) {
|
||||
case 'weibo':
|
||||
return 'https://service.weibo.com/share/share.php?url=' + encodeURIComponent(payload.url) + '&title=' + encodeURIComponent(payload.title + (payload.text ? ' ' + payload.text : ''));
|
||||
case 'qq':
|
||||
return 'https://connect.qq.com/widget/shareqq/index.html?url=' + encodeURIComponent(payload.url) + '&title=' + encodeURIComponent(payload.title) + '&desc=' + encodeURIComponent(payload.desc || payload.text || '');
|
||||
case 'twitter':
|
||||
return 'https://x.com/intent/tweet?url=' + encodeURIComponent(payload.url) + '&text=' + encodeURIComponent(payload.title);
|
||||
case 'telegram':
|
||||
return 'https://t.me/share/url?url=' + encodeURIComponent(payload.url) + '&text=' + encodeURIComponent(payload.title);
|
||||
case 'linkedin':
|
||||
return 'https://www.linkedin.com/sharing/share-offsite/?url=' + encodeURIComponent(payload.url);
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function fallbackCopy(text) {
|
||||
var textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.style.cssText = 'position:fixed;left:-9999px;top:-9999px;opacity:0;';
|
||||
textarea.setAttribute('readonly', '');
|
||||
document.body.appendChild(textarea);
|
||||
try {
|
||||
textarea.select();
|
||||
textarea.setSelectionRange(0, textarea.value.length);
|
||||
if (!document.execCommand('copy')) {
|
||||
throw new Error('copy command failed');
|
||||
}
|
||||
} finally {
|
||||
document.body.removeChild(textarea);
|
||||
}
|
||||
}
|
||||
|
||||
function copyLink(text) {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
return navigator.clipboard.writeText(text).catch(function () {
|
||||
fallbackCopy(text);
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
fallbackCopy(text);
|
||||
return Promise.resolve();
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
|
||||
function initShareDropdown() {
|
||||
var dropdown = document.getElementById('share-dropdown');
|
||||
var triggers = Array.prototype.slice.call(document.querySelectorAll('#action-share-trigger, .action-share[data-type="share"], .footer-tabbar .action-share')).filter(function (el, idx, arr) { return arr.indexOf(el) === idx; });
|
||||
var trigger = triggers[0] || null;
|
||||
if (!trigger || !dropdown || dropdown.dataset.aksrtShareBound === '1') return;
|
||||
|
||||
dropdown.dataset.aksrtShareBound = '1';
|
||||
|
||||
var qrBox = document.getElementById('share-qrcode-box');
|
||||
var qrImage = document.getElementById('share-qrcode-image');
|
||||
|
||||
function closeDropdown() {
|
||||
dropdown.setAttribute('aria-hidden', 'true');
|
||||
triggers.forEach(function (t) { t.setAttribute('aria-expanded', 'false'); });
|
||||
document.body.classList.remove('aksrt-share-sheet-open');
|
||||
if (window.AksrtShare && typeof window.AksrtShare.hideQrFallback === 'function') {
|
||||
window.AksrtShare.hideQrFallback(qrBox);
|
||||
} else if (qrBox) {
|
||||
qrBox.classList.remove('is-visible');
|
||||
qrBox.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
function toggleDropdown() {
|
||||
var isOpen = dropdown.getAttribute('aria-hidden') === 'false';
|
||||
if (isOpen) {
|
||||
closeDropdown();
|
||||
return;
|
||||
}
|
||||
|
||||
dropdown.setAttribute('aria-hidden', 'false');
|
||||
triggers.forEach(function (t) { t.setAttribute('aria-expanded', 'true'); });
|
||||
if (window.matchMedia && window.matchMedia('(max-width: 767px)').matches) {
|
||||
document.body.classList.add('aksrt-share-sheet-open');
|
||||
}
|
||||
}
|
||||
|
||||
trigger.addEventListener('click', function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
toggleDropdown();
|
||||
});
|
||||
|
||||
triggers.slice(1).forEach(function (extraTrigger) {
|
||||
extraTrigger.addEventListener('click', function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
// Reuse primary trigger click semantics by synthetic toggle
|
||||
trigger.click();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
document.addEventListener('click', function (event) {
|
||||
if (!trigger.contains(event.target) && !dropdown.contains(event.target)) {
|
||||
closeDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Escape') {
|
||||
closeDropdown();
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.addEventListener('click', function (event) {
|
||||
var item = event.target.closest('.share-item');
|
||||
if (!item) return;
|
||||
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
handleShareAction(item, {
|
||||
qrBox: qrBox,
|
||||
qrImage: qrImage,
|
||||
closeDropdown: closeDropdown,
|
||||
withinDropdown: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleWeixinShare(node, payload, options) {
|
||||
options = options || {};
|
||||
|
||||
var share = window.AksrtShare;
|
||||
if (!share || typeof share.openWeixinShare !== 'function') {
|
||||
notyf('微信分享模块未加载', 'danger');
|
||||
return Promise.resolve({ mode: 'error' });
|
||||
}
|
||||
|
||||
if (
|
||||
options.qrBox &&
|
||||
options.qrBox.classList.contains('is-visible') &&
|
||||
(!share.isWeixinEnv || !share.isWeixinEnv())
|
||||
) {
|
||||
share.hideQrFallback(options.qrBox);
|
||||
return Promise.resolve({ mode: 'closed' });
|
||||
}
|
||||
|
||||
return share.openWeixinShare({
|
||||
title: payload.title,
|
||||
url: payload.url,
|
||||
desc: payload.desc || payload.text || '',
|
||||
image: payload.image,
|
||||
qrBox: options.qrBox || null,
|
||||
qrImage: options.qrImage || null
|
||||
}).then(function (result) {
|
||||
if (result && result.message) {
|
||||
notyf(result.message, result.mode === 'error' ? 'danger' : (result.mode === 'bridge' ? 'success' : 'info'));
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
function handleShareAction(node, options) {
|
||||
var platform = getPlatform(node);
|
||||
if (!platform) return Promise.resolve({ mode: 'noop' });
|
||||
|
||||
var payload = resolvePayload(node);
|
||||
if (!payload.url) return Promise.resolve({ mode: 'noop' });
|
||||
|
||||
if (platform === 'copy') {
|
||||
return copyLink(payload.url).then(function () {
|
||||
notyf('链接已复制', 'success');
|
||||
if (options && typeof options.closeDropdown === 'function') {
|
||||
options.closeDropdown();
|
||||
}
|
||||
return { mode: 'copy' };
|
||||
}).catch(function () {
|
||||
notyf('复制失败,请手动复制链接', 'danger');
|
||||
return { mode: 'error' };
|
||||
});
|
||||
}
|
||||
|
||||
if (platform === 'wechat') {
|
||||
return handleWeixinShare(node, payload, options).then(function (result) {
|
||||
if (result && result.mode !== 'qr' && result.mode !== 'error' && options && typeof options.closeDropdown === 'function') {
|
||||
options.closeDropdown();
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
if (platform === 'poster') {
|
||||
if (window.AksrtPosterShare && typeof window.AksrtPosterShare.open === 'function') {
|
||||
window.AksrtPosterShare.open(payload);
|
||||
if (options && typeof options.closeDropdown === 'function') options.closeDropdown();
|
||||
return Promise.resolve({ mode: 'poster' });
|
||||
}
|
||||
notyf('海报模块未加载', 'danger');
|
||||
return Promise.resolve({ mode: 'error' });
|
||||
}
|
||||
|
||||
var shareUrl = buildShareUrl(platform, payload);
|
||||
if (!shareUrl) {
|
||||
return Promise.resolve({ mode: 'noop' });
|
||||
}
|
||||
|
||||
openWindow(shareUrl);
|
||||
if (options && typeof options.closeDropdown === 'function') {
|
||||
options.closeDropdown();
|
||||
}
|
||||
|
||||
return Promise.resolve({ mode: 'window' });
|
||||
}
|
||||
|
||||
function bindGenericShareButtons() {
|
||||
document.addEventListener('click', function (event) {
|
||||
var node = event.target.closest('[data-share-platform]');
|
||||
if (!node || node.closest('#share-dropdown')) return;
|
||||
|
||||
event.preventDefault();
|
||||
handleShareAction(node, {});
|
||||
});
|
||||
|
||||
document.addEventListener('click', function (event) {
|
||||
var node = event.target.closest('[data-share-copy]');
|
||||
if (!node) return;
|
||||
|
||||
event.preventDefault();
|
||||
var url = node.getAttribute('data-share-url') || window.location.href;
|
||||
copyLink(url).then(function () {
|
||||
notyf('链接已复制', 'success');
|
||||
}).catch(function () {
|
||||
notyf('复制失败,请手动复制链接', 'danger');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (document.documentElement.dataset.aksrtPostShareInitialized === '1') return;
|
||||
document.documentElement.dataset.aksrtPostShareInitialized = '1';
|
||||
initShareDropdown();
|
||||
bindGenericShareButtons();
|
||||
}
|
||||
|
||||
jQuery(document).off('auto_fun.aksrt-post-share').on('auto_fun.aksrt-post-share', function () { init(document); });
|
||||
})();
|
||||
+180
-387
@@ -1,406 +1,199 @@
|
||||
/**
|
||||
* AKSRT Poster Share — 海报分享
|
||||
*
|
||||
* 生成文章分享海报图片,支持下载和分享。
|
||||
* 使用 Canvas API 绘制,无需外部依赖。
|
||||
* Reference-theme poster sharing runtime.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
(function () {
|
||||
(function (window, document, $) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* 初始化海报分享
|
||||
*
|
||||
* @param {Object} options 配置项
|
||||
*/
|
||||
function PosterShare(options) {
|
||||
this.options = Object.assign({
|
||||
triggerSelector: '[data-aksrt-poster]',
|
||||
title: '',
|
||||
excerpt: '',
|
||||
author: '',
|
||||
date: '',
|
||||
siteName: '',
|
||||
qrCodeUrl: '',
|
||||
width: 750,
|
||||
height: 1334,
|
||||
backgroundColor: '#ffffff',
|
||||
textColor: '#333333',
|
||||
accentColor: '#1890ff',
|
||||
}, options || {});
|
||||
var WIDTH = 768;
|
||||
var HEIGHT = 1168;
|
||||
var FONT = '-apple-system,BlinkMacSystemFont,"Segoe UI","Microsoft YaHei",Arial,sans-serif';
|
||||
|
||||
this.init();
|
||||
function notice(message, type) {
|
||||
if (typeof window.notyf === 'function') window.notyf(message, type || '');
|
||||
}
|
||||
|
||||
PosterShare.prototype.init = function () {
|
||||
var self = this;
|
||||
function ajaxUrl() {
|
||||
return (window.aksrtData && window.aksrtData.ajaxUrl) || (window._win && window._win.ajax_url) || '';
|
||||
}
|
||||
|
||||
document.querySelectorAll(this.options.triggerSelector).forEach(function (btn) {
|
||||
btn.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
function nonce() {
|
||||
return (window.aksrtData && window.aksrtData.nonce) || '';
|
||||
}
|
||||
|
||||
// Unified payload first (title/excerpt/author/date/qr), then allow an
|
||||
// explicit data-aksrt-poster JSON blob to override individual fields.
|
||||
var resolved = (window.AksrtShareData && typeof window.AksrtShareData.resolve === 'function')
|
||||
? window.AksrtShareData.resolve(btn)
|
||||
: {};
|
||||
function loadImage(sources) {
|
||||
sources = sources.filter(Boolean);
|
||||
return new Promise(function (resolve, reject) {
|
||||
var index = 0;
|
||||
function next() {
|
||||
if (index >= sources.length) { reject(new Error('image unavailable')); return; }
|
||||
var image = new Image();
|
||||
image.crossOrigin = 'anonymous';
|
||||
image.onload = function () { resolve(image); };
|
||||
image.onerror = function () { index += 1; next(); };
|
||||
image.src = sources[index];
|
||||
}
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
var config = {};
|
||||
function qrCodeDataUrl(text) {
|
||||
return new Promise(function (resolve) {
|
||||
if (!text || typeof window.tbquire !== 'function') { resolve(''); return; }
|
||||
window.tbquire(['qrcode'], function () {
|
||||
var host = $('<div>').css({ position: 'fixed', left: '-9999px', top: '-9999px' }).appendTo('body');
|
||||
try {
|
||||
config = JSON.parse(btn.dataset.aksrtPoster || '{}');
|
||||
} catch (err) {}
|
||||
|
||||
var merged = Object.assign({}, self.options, {
|
||||
title: resolved.title || self.options.title,
|
||||
excerpt: resolved.desc || self.options.excerpt,
|
||||
author: resolved.author || self.options.author,
|
||||
date: resolved.date || self.options.date,
|
||||
siteName: resolved.siteName || self.options.siteName,
|
||||
qrCodeUrl: resolved.qrcode || self.options.qrCodeUrl
|
||||
}, config);
|
||||
self.generate(merged);
|
||||
host.qrcode({ width: 160, height: 160, correctLevel: 0, text: text, background: '#fff', foreground: '#333' });
|
||||
var canvas = host.find('canvas').get(0);
|
||||
resolve(canvas ? canvas.toDataURL('image/png') : '');
|
||||
} catch (error) {
|
||||
resolve('');
|
||||
} finally {
|
||||
host.remove();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var WEEKDAYS = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
|
||||
var FONT_FAMILY = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';
|
||||
|
||||
PosterShare.prototype.generate = function (config) {
|
||||
var self = this;
|
||||
config.width = config.width || 768;
|
||||
config.height = config.height || 1168;
|
||||
|
||||
var overlay = this.createOverlay();
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = config.width;
|
||||
canvas.height = config.height;
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
// Background
|
||||
ctx.fillStyle = config.backgroundColor;
|
||||
ctx.fillRect(0, 0, config.width, config.height);
|
||||
|
||||
var coverSources = [config.coverImg, config.banner, config.banner_default, config.banner_spare].filter(Boolean);
|
||||
|
||||
if (coverSources.length) {
|
||||
self.loadImageWithRetry(coverSources, 0, function (coverImg) {
|
||||
self.drawPosterContent(ctx, canvas, config, overlay, coverImg);
|
||||
}, function () {
|
||||
self.drawPosterContent(ctx, canvas, config, overlay, null);
|
||||
});
|
||||
} else {
|
||||
self.drawPosterContent(ctx, canvas, config, overlay, null);
|
||||
}
|
||||
};
|
||||
|
||||
PosterShare.prototype.loadImageWithRetry = function (sources, idx, onLoad, onFail) {
|
||||
if (idx >= sources.length) { onFail(); return; }
|
||||
var self = this;
|
||||
var retries = 0;
|
||||
var src = sources[idx];
|
||||
|
||||
function tryLoad() {
|
||||
var img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.onload = function () { onLoad(img); };
|
||||
img.onerror = function () {
|
||||
retries++;
|
||||
if (retries < 3) { tryLoad(); }
|
||||
else { self.loadImageWithRetry(sources, idx + 1, onLoad, onFail); }
|
||||
};
|
||||
img.src = src;
|
||||
}
|
||||
tryLoad();
|
||||
};
|
||||
|
||||
PosterShare.prototype.drawPosterContent = function (ctx, canvas, config, overlay, coverImg) {
|
||||
var self = this;
|
||||
var W = config.width;
|
||||
var isProduct = config.isProduct;
|
||||
var y = 0;
|
||||
|
||||
// Cover image area (top)
|
||||
var coverH = isProduct ? W : Math.round(W * 0.52);
|
||||
if (coverImg) {
|
||||
var imgRatio = coverImg.width / coverImg.height;
|
||||
var drawW, drawH, drawX, drawY;
|
||||
if (imgRatio > W / coverH) {
|
||||
drawH = coverH; drawW = coverH * imgRatio;
|
||||
drawX = -(drawW - W) / 2; drawY = 0;
|
||||
} else {
|
||||
drawW = W; drawH = W / imgRatio;
|
||||
drawX = 0; drawY = -(drawH - coverH) / 2;
|
||||
}
|
||||
ctx.drawImage(coverImg, drawX, drawY, drawW, drawH);
|
||||
} else {
|
||||
ctx.fillStyle = config.accentColor;
|
||||
ctx.fillRect(0, 0, W, coverH);
|
||||
}
|
||||
|
||||
// Date/weekday badge (top-left)
|
||||
if (config.date) {
|
||||
var d = new Date(config.date);
|
||||
if (!isNaN(d.getTime())) {
|
||||
var weekday = WEEKDAYS[d.getDay()];
|
||||
var dateStr = (d.getMonth() + 1) + '/' + d.getDate();
|
||||
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.55)';
|
||||
ctx.beginPath();
|
||||
ctx.roundRect ? ctx.roundRect(20, 20, 80, 65, 8) : ctx.rect(20, 20, 80, 65);
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.font = 'bold 20px ' + FONT_FAMILY;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(weekday, 60, 47);
|
||||
ctx.font = '16px ' + FONT_FAMILY;
|
||||
ctx.fillText(dateStr, 60, 72);
|
||||
ctx.textAlign = 'left';
|
||||
}
|
||||
}
|
||||
|
||||
y = coverH + 36;
|
||||
|
||||
// Title with vertical accent line
|
||||
ctx.fillStyle = config.accentColor;
|
||||
ctx.fillRect(50, y - 6, 4, 44);
|
||||
|
||||
ctx.fillStyle = config.textColor;
|
||||
ctx.font = 'bold 32px ' + FONT_FAMILY;
|
||||
var titleLines = this.wrapText(ctx, config.title, W - 140);
|
||||
titleLines.slice(0, 3).forEach(function (line) {
|
||||
ctx.fillText(line, 66, y + 28);
|
||||
y += 44;
|
||||
});
|
||||
|
||||
y += 16;
|
||||
|
||||
// Product price section
|
||||
if (isProduct && config.price !== undefined) {
|
||||
ctx.font = 'bold 36px ' + FONT_FAMILY;
|
||||
ctx.fillStyle = '#e74c3c';
|
||||
var priceLabel = config.priceUnit === 'points' ? (config.price + ' 积分') : ('¥' + config.price);
|
||||
ctx.fillText(priceLabel, 60, y + 10);
|
||||
|
||||
if (config.originalPrice && config.originalPrice > config.price) {
|
||||
var priceW = ctx.measureText(priceLabel).width;
|
||||
ctx.font = '22px ' + FONT_FAMILY;
|
||||
ctx.fillStyle = '#999';
|
||||
var origText = '¥' + config.originalPrice;
|
||||
ctx.fillText(origText, 60 + priceW + 16, y + 10);
|
||||
var origW = ctx.measureText(origText).width;
|
||||
ctx.strokeStyle = '#999';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(60 + priceW + 16, y + 5);
|
||||
ctx.lineTo(60 + priceW + 16 + origW, y + 5);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
if (config.priceTag) {
|
||||
ctx.font = '18px ' + FONT_FAMILY;
|
||||
ctx.fillStyle = '#fff';
|
||||
var tagW = ctx.measureText(config.priceTag).width + 16;
|
||||
ctx.fillStyle = config.accentColor;
|
||||
ctx.beginPath();
|
||||
ctx.roundRect ? ctx.roundRect(W - 60 - tagW, y - 10, tagW, 30, 4) : ctx.rect(W - 60 - tagW, y - 10, tagW, 30);
|
||||
ctx.fill();
|
||||
ctx.fillStyle = '#fff';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText(config.priceTag, W - 60 - tagW / 2, y + 10);
|
||||
ctx.textAlign = 'left';
|
||||
}
|
||||
|
||||
y += 48;
|
||||
}
|
||||
|
||||
// Excerpt
|
||||
if (config.excerpt) {
|
||||
ctx.fillStyle = '#666';
|
||||
ctx.font = '22px ' + FONT_FAMILY;
|
||||
var excerptLines = this.wrapText(ctx, config.excerpt, W - 120);
|
||||
excerptLines.slice(0, 5).forEach(function (line) {
|
||||
ctx.fillText(line, 60, y + 4);
|
||||
y += 34;
|
||||
});
|
||||
if (excerptLines.length > 5) {
|
||||
ctx.fillText('...', 60, y + 4);
|
||||
y += 34;
|
||||
}
|
||||
}
|
||||
|
||||
y += 20;
|
||||
|
||||
// Author & date
|
||||
ctx.fillStyle = '#999';
|
||||
ctx.font = '18px ' + FONT_FAMILY;
|
||||
if (config.author) { ctx.fillText(config.author, 60, y); y += 26; }
|
||||
|
||||
// Bottom: site name + QR code
|
||||
var bottomY = config.height - 110;
|
||||
|
||||
ctx.strokeStyle = '#eee';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(50, bottomY);
|
||||
ctx.lineTo(W - 50, bottomY);
|
||||
ctx.stroke();
|
||||
|
||||
if (config.siteName) {
|
||||
ctx.fillStyle = '#999';
|
||||
ctx.font = '18px ' + FONT_FAMILY;
|
||||
ctx.fillText(config.siteName, 60, bottomY + 36);
|
||||
}
|
||||
|
||||
if (config.qrCodeUrl) {
|
||||
var qrImg = new Image();
|
||||
qrImg.crossOrigin = 'anonymous';
|
||||
qrImg.onload = function () {
|
||||
var qrSize = 90;
|
||||
var qrX = W - 50 - qrSize;
|
||||
var qrY = bottomY + 6;
|
||||
ctx.drawImage(qrImg, qrX, qrY, qrSize, qrSize);
|
||||
|
||||
ctx.fillStyle = '#999';
|
||||
ctx.font = '13px ' + FONT_FAMILY;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('扫码阅读', qrX + qrSize / 2, qrY + qrSize + 16);
|
||||
ctx.textAlign = 'left';
|
||||
|
||||
self.showPoster(canvas, overlay);
|
||||
};
|
||||
qrImg.onerror = function () { self.showPoster(canvas, overlay); };
|
||||
qrImg.src = config.qrCodeUrl;
|
||||
} else {
|
||||
self.showPoster(canvas, overlay);
|
||||
}
|
||||
};
|
||||
|
||||
PosterShare.prototype.showPoster = function (canvas, overlay) {
|
||||
// 创建海报容器
|
||||
var posterWrap = document.createElement('div');
|
||||
posterWrap.className = 'aksrt-poster-share__wrap';
|
||||
|
||||
var img = document.createElement('img');
|
||||
img.src = canvas.toDataURL('image/png');
|
||||
img.className = 'aksrt-poster-share__image';
|
||||
img.alt = '分享海报';
|
||||
posterWrap.appendChild(img);
|
||||
|
||||
// 操作按钮
|
||||
var actions = document.createElement('div');
|
||||
actions.className = 'aksrt-poster-share__actions';
|
||||
|
||||
var downloadBtn = document.createElement('button');
|
||||
downloadBtn.type = 'button';
|
||||
downloadBtn.className = 'aksrt-poster-share__btn';
|
||||
downloadBtn.innerHTML = '<i class="fa fas fa-download"></i> 保存图片';
|
||||
downloadBtn.addEventListener('click', function () {
|
||||
var link = document.createElement('a');
|
||||
var postId = (window.aksrtData && aksrtData.postId) || Date.now();
|
||||
link.download = 'poster_' + postId + '.png';
|
||||
link.href = canvas.toDataURL('image/png');
|
||||
link.click();
|
||||
});
|
||||
actions.appendChild(downloadBtn);
|
||||
|
||||
var closeBtn = document.createElement('button');
|
||||
closeBtn.type = 'button';
|
||||
closeBtn.className = 'aksrt-poster-share__btn aksrt-poster-share__btn--secondary';
|
||||
closeBtn.textContent = '关闭';
|
||||
closeBtn.addEventListener('click', function () {
|
||||
overlay.remove();
|
||||
});
|
||||
actions.appendChild(closeBtn);
|
||||
|
||||
posterWrap.appendChild(actions);
|
||||
|
||||
// 替换加载状态
|
||||
overlay.innerHTML = '';
|
||||
overlay.appendChild(posterWrap);
|
||||
};
|
||||
|
||||
PosterShare.prototype.createOverlay = function () {
|
||||
var overlay = document.createElement('div');
|
||||
overlay.className = 'aksrt-poster-share__overlay';
|
||||
overlay.innerHTML = '<div class="aksrt-poster-share__loading"><i class="fa fas fa-spinner fa-spin"></i> 生成海报中...</div>';
|
||||
overlay.addEventListener('click', function (e) {
|
||||
if (e.target === overlay) overlay.remove();
|
||||
});
|
||||
return overlay;
|
||||
};
|
||||
|
||||
PosterShare.prototype.wrapText = function (ctx, text, maxWidth) {
|
||||
var lines = [];
|
||||
var currentLine = '';
|
||||
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
var char = text[i];
|
||||
var testLine = currentLine + char;
|
||||
var metrics = ctx.measureText(testLine);
|
||||
|
||||
if (metrics.width > maxWidth && currentLine !== '') {
|
||||
lines.push(currentLine);
|
||||
currentLine = char;
|
||||
} else {
|
||||
currentLine = testLine;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLine) {
|
||||
lines.push(currentLine);
|
||||
}
|
||||
|
||||
return lines;
|
||||
};
|
||||
|
||||
// 自动初始化
|
||||
function autoInit() {
|
||||
document.querySelectorAll('[data-aksrt-poster]').forEach(function (el) {
|
||||
if (el.dataset.posterInit) return;
|
||||
el.dataset.posterInit = '1';
|
||||
|
||||
var config = {};
|
||||
try {
|
||||
config = JSON.parse(el.dataset.aksrtPoster || '{}');
|
||||
} catch (e) {}
|
||||
|
||||
new PosterShare({ triggerSelector: '[data-aksrt-poster]' });
|
||||
});
|
||||
}
|
||||
|
||||
jQuery(document).off('auto_fun.aksrt-poster-share').on('auto_fun.aksrt-poster-share', autoInit);
|
||||
function coverRect(boxWidth, boxHeight, sourceWidth, sourceHeight) {
|
||||
var sx = 0, sy = 0, sw = sourceWidth, sh = sourceHeight;
|
||||
if (sourceWidth / sourceHeight > boxWidth / boxHeight) {
|
||||
sw = boxWidth * sourceHeight / boxHeight;
|
||||
sx = (sourceWidth - sw) / 2;
|
||||
} else {
|
||||
sh = boxHeight * sourceWidth / boxWidth;
|
||||
sy = (sourceHeight - sh) / 2;
|
||||
}
|
||||
return { sx: sx, sy: sy, sw: sw, sh: sh };
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a poster directly from a unified share payload, without binding
|
||||
* to DOM triggers. Used by post-share.js for the "生成海报" share item.
|
||||
*
|
||||
* @param {Object} payload Canonical share payload (AksrtShareData shape).
|
||||
*/
|
||||
PosterShare.open = function (payload) {
|
||||
payload = payload || {};
|
||||
var inst = Object.create(PosterShare.prototype);
|
||||
inst.options = {
|
||||
width: 750,
|
||||
height: 1334,
|
||||
backgroundColor: '#ffffff',
|
||||
textColor: '#333333',
|
||||
accentColor: '#1890ff'
|
||||
};
|
||||
inst.generate(Object.assign({}, inst.options, {
|
||||
title: payload.title || document.title,
|
||||
excerpt: payload.excerpt || payload.desc || '',
|
||||
author: payload.author || '',
|
||||
date: payload.date || '',
|
||||
siteName: payload.siteName || '',
|
||||
qrCodeUrl: payload.qrCodeUrl || payload.qrcode || ''
|
||||
}));
|
||||
};
|
||||
function containRect(x, y, boxWidth, boxHeight, sourceWidth, sourceHeight) {
|
||||
var ratio = Math.min(boxWidth / sourceWidth, boxHeight / sourceHeight);
|
||||
var width = sourceWidth * ratio;
|
||||
var height = sourceHeight * ratio;
|
||||
return { x: x + (boxWidth - width) / 2, y: y + (boxHeight - height) / 2, width: width, height: height };
|
||||
}
|
||||
|
||||
window.AksrtPosterShare = PosterShare;
|
||||
})();
|
||||
function drawLines(ctx, text, maxWidth, maxRows, x, y, lineHeight) {
|
||||
var chars = String(text || '').replace(/[\r\n]+/g, ' ').split('');
|
||||
var rows = [], line = '';
|
||||
chars.forEach(function (char) {
|
||||
var next = line + char;
|
||||
if (line && ctx.measureText(next).width > maxWidth) { rows.push(line); line = char; }
|
||||
else line = next;
|
||||
});
|
||||
if (line) rows.push(line);
|
||||
if (rows.length > maxRows) {
|
||||
rows = rows.slice(0, maxRows);
|
||||
while (rows[maxRows - 1] && ctx.measureText(rows[maxRows - 1] + '...').width > maxWidth) {
|
||||
rows[maxRows - 1] = rows[maxRows - 1].slice(0, -1);
|
||||
}
|
||||
rows[maxRows - 1] += '...';
|
||||
}
|
||||
rows.forEach(function (row, index) { ctx.fillText(row, x, y + index * lineHeight); });
|
||||
}
|
||||
|
||||
function renderPoster(data) {
|
||||
return Promise.all([
|
||||
loadImage([data.banner, data.banner_default, data.banner_spare]),
|
||||
data.logo ? loadImage([data.logo]).catch(function () { return null; }) : Promise.resolve(null),
|
||||
qrCodeDataUrl(data.url).then(function (src) { return src ? loadImage([src]).catch(function () { return null; }) : null; })
|
||||
]).then(function (assets) {
|
||||
var banner = assets[0], logo = assets[1], qr = assets[2];
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = WIDTH; canvas.height = HEIGHT;
|
||||
var ctx = canvas.getContext('2d');
|
||||
var imageHeight = HEIGHT / 2;
|
||||
|
||||
ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, WIDTH, HEIGHT);
|
||||
var crop = coverRect(WIDTH, imageHeight, banner.width, banner.height);
|
||||
ctx.drawImage(banner, crop.sx, crop.sy, crop.sw, crop.sh, 0, 0, WIDTH, imageHeight);
|
||||
|
||||
var now = new Date();
|
||||
ctx.fillStyle = '#fff'; ctx.font = '35px ' + FONT; ctx.fillText('周' + '日一二三四五六'.charAt(now.getDay()), 30, 70);
|
||||
ctx.font = '28px ' + FONT; ctx.fillText((now.getMonth() + 1) + ' / ' + now.getDate(), 30, 115);
|
||||
|
||||
ctx.strokeStyle = '#00a1ff'; ctx.lineWidth = 7; ctx.lineCap = 'round'; ctx.beginPath();
|
||||
ctx.moveTo(40, imageHeight + 38); ctx.lineTo(40, imageHeight + 74); ctx.stroke();
|
||||
|
||||
ctx.fillStyle = '#424242'; ctx.font = 'bold 35px ' + FONT;
|
||||
drawLines(ctx, data.title, WIDTH - 120, 2, 58, imageHeight + 68, 52);
|
||||
ctx.fillStyle = '#fc4e1f'; ctx.font = '24px ' + FONT;
|
||||
drawLines(ctx, data.tags, WIDTH - 80, 1, 40, imageHeight + 172, 36);
|
||||
ctx.fillStyle = '#585858'; ctx.font = '25px ' + FONT;
|
||||
drawLines(ctx, data.content, WIDTH - 80, 4, 40, imageHeight + 232, 39);
|
||||
|
||||
ctx.strokeStyle = 'rgba(122,122,122,.2)'; ctx.lineWidth = 2; ctx.strokeRect(30, HEIGHT - 230, WIDTH - 60, 200);
|
||||
if (logo) {
|
||||
var logoRect = containRect(80, HEIGHT - 190, 300, 100, logo.width, logo.height);
|
||||
ctx.drawImage(logo, logoRect.x, logoRect.y, logoRect.width, logoRect.height);
|
||||
}
|
||||
if (qr) ctx.drawImage(qr, WIDTH - 200, HEIGHT - 200, 120, 120);
|
||||
ctx.fillStyle = '#b4b4b4'; ctx.font = '22px ' + FONT; ctx.textAlign = 'center';
|
||||
ctx.fillText(data.description || '扫一扫 立即查看', WIDTH / 2, HEIGHT - 52);
|
||||
return canvas.toDataURL('image/png');
|
||||
});
|
||||
}
|
||||
|
||||
function modalId(postId) { return 'modal_poster_' + postId; }
|
||||
|
||||
function createModal(postId) {
|
||||
var id = modalId(postId);
|
||||
var html = '<div class="modal fade flex jc" id="' + id + '" tabindex="-1" role="dialog" aria-hidden="true">' +
|
||||
'<div class="modal-dialog poster-share hover-show" role="document"><div class="modal-content" style="height:220px;overflow:hidden">' +
|
||||
'<div class="poster-imgbox hover-show"></div><div class="flex jc loading-mask absolute main-bg radius8">' +
|
||||
'<div class="loading zts fa-2x"></div><div class="muted-2-color box-body">正在生成图片,请稍候...</div></div></div>' +
|
||||
'<div class="padding-6 abs-center hover-show-con text-center poster-share-actions" style="top:auto">' +
|
||||
'<a href="#" class="but cir jb-blue poster-download hide"><i class="fa fas fa-download" aria-hidden="true"></i></a>' +
|
||||
'<button type="button" data-dismiss="modal" class="but cir jb-yellow ml10"><svg aria-hidden="true" class="icon em12"><use xlink:href="#icon-close"></use></svg></button>' +
|
||||
'</div></div></div>';
|
||||
$('body').append(html);
|
||||
return $('#' + id);
|
||||
}
|
||||
|
||||
function showPoster($modal, postId, src) {
|
||||
var $box = $modal.find('.poster-imgbox').empty().append($('<img>', { src: src, alt: '分享海报', class: 'loaded-img' })).addClass('loaded');
|
||||
$modal.find('.poster-download').attr({ href: src, download: 'poster_' + postId + '.png' }).removeClass('hide');
|
||||
$modal.find('.loading-mask').fadeOut(160);
|
||||
$modal.find('.modal-content').css({ height: $box.outerHeight(), transition: '.2s' });
|
||||
window.setTimeout(function () { $modal.find('.modal-content').css({ height: '', overflow: '', transition: '' }); }, 220);
|
||||
}
|
||||
|
||||
function requestPoster($trigger, postId, $modal) {
|
||||
$.ajax({
|
||||
type: 'POST', url: ajaxUrl(), dataType: 'json',
|
||||
data: { action: 'aksrt_poster_share_data', id: postId, nonce: nonce() }
|
||||
}).done(function (response) {
|
||||
if (!response || !response.success || !response.data) {
|
||||
notice((response && response.data && response.data.message) || '海报数据加载失败', 'danger');
|
||||
$modal.modal('hide');
|
||||
$modal.remove();
|
||||
return;
|
||||
}
|
||||
renderPoster(response.data).then(function (src) { showPoster($modal, postId, src); }).catch(function () {
|
||||
notice('海报加载失败,请检查图片跨域设置', 'danger');
|
||||
$modal.modal('hide');
|
||||
$modal.remove();
|
||||
});
|
||||
}).fail(function (xhr) {
|
||||
var message = xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message;
|
||||
notice(message || '海报数据加载失败', 'danger');
|
||||
$modal.modal('hide');
|
||||
}).always(function () { $trigger.removeAttr('disabled'); });
|
||||
}
|
||||
|
||||
$('body').off('click.aksrtPosterShare', '[poster-share]').on('click.aksrtPosterShare', '[poster-share]', function (event) {
|
||||
event.preventDefault();
|
||||
var $trigger = $(this);
|
||||
var postId = parseInt($trigger.attr('poster-share'), 10) || 0;
|
||||
if (!postId || $trigger.attr('disabled')) return;
|
||||
var $modal = $('#' + modalId(postId));
|
||||
if ($modal.length) { $modal.modal('show'); return; }
|
||||
$trigger.attr('disabled', 'disabled');
|
||||
$('.modal').modal('hide');
|
||||
$modal = createModal(postId);
|
||||
$modal.modal('show');
|
||||
requestPoster($trigger, postId, $modal);
|
||||
});
|
||||
})(window, document, window.jQuery);
|
||||
@@ -1,108 +0,0 @@
|
||||
/**
|
||||
* AKSRT Share Data Builder
|
||||
*
|
||||
* Single source of truth for share payloads. Every share surface
|
||||
* (dropdown links, copy, WeChat bridge, poster) resolves its data through
|
||||
* window.AksrtShareData so no script assembles title/url/cover/qrcode on its
|
||||
* own.
|
||||
*
|
||||
* Canonical payload shape:
|
||||
* { title, url, desc, text, image, qrcode, author, date, siteName }
|
||||
*
|
||||
* Data is read from the nearest [data-share-*] context (falling back to
|
||||
* #share-dropdown), then to OpenGraph/meta tags and document defaults.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function metaContent(selectors) {
|
||||
for (var i = 0; i < selectors.length; i += 1) {
|
||||
var node = document.querySelector(selectors[i]);
|
||||
var content = node ? node.getAttribute('content') : '';
|
||||
if (content) return content;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function siteName() {
|
||||
return (
|
||||
metaContent(['meta[property="og:site_name"]']) ||
|
||||
(document.querySelector('.site-title, .logo-text, .navbar-logo') || {}).textContent ||
|
||||
document.title ||
|
||||
''
|
||||
).trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the element that carries the share data attributes for a node.
|
||||
*/
|
||||
function context(node) {
|
||||
var source = node && typeof node.closest === 'function'
|
||||
? node.closest('[data-share-url], [data-share-title], [data-share-desc], [data-share-image], [data-aksrt-poster]')
|
||||
: null;
|
||||
return source || document.getElementById('share-dropdown');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a QR data URL for a link, reusing the WeChat share encoder
|
||||
* when available. Returns '' if no encoder is loaded.
|
||||
*/
|
||||
function qrcode(url) {
|
||||
if (window.AksrtShare && typeof window.AksrtShare.buildQrDataUrl === 'function' && url) {
|
||||
return window.AksrtShare.buildQrDataUrl(url, 200) || '';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a canonical share payload for a triggering node.
|
||||
*
|
||||
* @param {Element} node Triggering element (button/link).
|
||||
* @param {Object} [overrides] Optional explicit overrides.
|
||||
* @returns {Object}
|
||||
*/
|
||||
function resolve(node, overrides) {
|
||||
var ctx = context(node);
|
||||
|
||||
function attr(name) {
|
||||
return (node && node.getAttribute && node.getAttribute(name)) ||
|
||||
(ctx && ctx.getAttribute && ctx.getAttribute(name)) || '';
|
||||
}
|
||||
|
||||
var url = attr('data-share-url') || window.location.href;
|
||||
var payload = {
|
||||
title: attr('data-share-title') || document.title,
|
||||
url: url,
|
||||
desc: attr('data-share-desc') || metaContent(['meta[property="og:description"]', 'meta[name="description"]']),
|
||||
text: attr('data-share-text') || '',
|
||||
image: attr('data-share-image') || metaContent(['meta[property="og:image"]']),
|
||||
qrcode: attr('data-share-qrcode') || '',
|
||||
author: attr('data-share-author') || '',
|
||||
date: attr('data-share-date') || '',
|
||||
siteName: attr('data-share-site') || siteName()
|
||||
};
|
||||
|
||||
if (!payload.qrcode) {
|
||||
payload.qrcode = qrcode(payload.url);
|
||||
}
|
||||
|
||||
if (overrides && typeof overrides === 'object') {
|
||||
Object.keys(overrides).forEach(function (key) {
|
||||
if (overrides[key] !== undefined && overrides[key] !== null && overrides[key] !== '') {
|
||||
payload[key] = overrides[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
window.AksrtShareData = {
|
||||
resolve: resolve,
|
||||
qrcode: qrcode,
|
||||
siteName: siteName
|
||||
};
|
||||
})();
|
||||
@@ -1,481 +0,0 @@
|
||||
/**
|
||||
* AKSRT Weixin Share
|
||||
*
|
||||
* Bridge-first WeChat share helper with QR fallback.
|
||||
*
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Local QR code data URL generator — no third-party services.
|
||||
* Uses canvas rendering with a minimal QR matrix encoder.
|
||||
*/
|
||||
function buildQRCodeDataUrl(text, size) {
|
||||
size = size || 160;
|
||||
try {
|
||||
var matrix = generateQRMatrix(text || ' ');
|
||||
if (!matrix) return '';
|
||||
var canvas = document.createElement('canvas');
|
||||
var moduleCount = matrix.length;
|
||||
var scale = Math.floor(size / (moduleCount + 8));
|
||||
var margin = Math.floor((size - scale * moduleCount) / 2);
|
||||
canvas.width = size;
|
||||
canvas.height = size;
|
||||
var ctx = canvas.getContext('2d');
|
||||
ctx.fillStyle = '#ffffff';
|
||||
ctx.fillRect(0, 0, size, size);
|
||||
ctx.fillStyle = '#000000';
|
||||
for (var r = 0; r < moduleCount; r++) {
|
||||
for (var c = 0; c < moduleCount; c++) {
|
||||
if (matrix[r][c]) {
|
||||
ctx.fillRect(margin + c * scale, margin + r * scale, scale, scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
return canvas.toDataURL('image/png');
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimal QR Code matrix generator (Version 1-6, Byte mode, Error Correction L).
|
||||
* Returns a 2D boolean array or null on failure.
|
||||
*/
|
||||
function generateQRMatrix(text) {
|
||||
var data = encodeUTF8(text);
|
||||
// Choose version based on data length (EC level L, Byte mode)
|
||||
var version = 1;
|
||||
var capacities = [0, 17, 32, 53, 78, 106, 134];
|
||||
for (var v = 1; v <= 6; v++) {
|
||||
if (data.length <= capacities[v]) { version = v; break; }
|
||||
if (v === 6) return null; // data too long for small versions
|
||||
}
|
||||
var moduleCount = version * 4 + 17;
|
||||
var matrix = createMatrix(moduleCount);
|
||||
var reserved = createMatrix(moduleCount);
|
||||
|
||||
// Place finder patterns
|
||||
placeFinder(matrix, reserved, 0, 0);
|
||||
placeFinder(matrix, reserved, moduleCount - 7, 0);
|
||||
placeFinder(matrix, reserved, 0, moduleCount - 7);
|
||||
|
||||
// Place alignment patterns (version >= 2)
|
||||
if (version >= 2) {
|
||||
var alignPos = getAlignmentPositions(version);
|
||||
for (var i = 0; i < alignPos.length; i++) {
|
||||
for (var j = 0; j < alignPos.length; j++) {
|
||||
if (isInFinder(alignPos[i], alignPos[j], moduleCount)) continue;
|
||||
placeAlignment(matrix, reserved, alignPos[i], alignPos[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Place timing patterns
|
||||
for (var i = 8; i < moduleCount - 8; i++) {
|
||||
if (!reserved[6][i]) { matrix[6][i] = (i % 2 === 0); reserved[6][i] = true; }
|
||||
if (!reserved[i][6]) { matrix[i][6] = (i % 2 === 0); reserved[i][6] = true; }
|
||||
}
|
||||
|
||||
// Reserve format info areas
|
||||
for (var i = 0; i < 8; i++) {
|
||||
reserved[8][i] = true; reserved[i][8] = true;
|
||||
reserved[8][moduleCount - 1 - i] = true; reserved[moduleCount - 1 - i][8] = true;
|
||||
}
|
||||
reserved[8][8] = true;
|
||||
if (version >= 2) {
|
||||
for (var i = moduleCount - 11; i < moduleCount - 8; i++) {
|
||||
for (var j = 0; j < 6; j++) { reserved[j][i] = true; reserved[i][j] = true; }
|
||||
}
|
||||
}
|
||||
|
||||
// Dark module
|
||||
matrix[moduleCount - 8][8] = true;
|
||||
reserved[moduleCount - 8][8] = true;
|
||||
|
||||
// Encode data
|
||||
var dataBits = encodeData(data, version);
|
||||
placeData(matrix, reserved, dataBits, moduleCount);
|
||||
|
||||
// Apply best mask
|
||||
var bestMask = 0;
|
||||
var bestPenalty = Infinity;
|
||||
for (var m = 0; m < 8; m++) {
|
||||
var masked = applyMask(matrix, reserved, m, moduleCount);
|
||||
var penalty = calcPenalty(masked, moduleCount);
|
||||
if (penalty < bestPenalty) { bestPenalty = penalty; bestMask = m; }
|
||||
}
|
||||
matrix = applyMask(matrix, reserved, bestMask, moduleCount);
|
||||
|
||||
// Place format info
|
||||
placeFormatInfo(matrix, bestMask, moduleCount);
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
function createMatrix(n) {
|
||||
var m = [];
|
||||
for (var i = 0; i < n; i++) { m[i] = []; for (var j = 0; j < n; j++) m[i][j] = false; }
|
||||
return m;
|
||||
}
|
||||
|
||||
function encodeUTF8(str) {
|
||||
var bytes = [];
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var c = str.charCodeAt(i);
|
||||
if (c < 0x80) bytes.push(c);
|
||||
else if (c < 0x800) { bytes.push(0xc0 | (c >> 6)); bytes.push(0x80 | (c & 0x3f)); }
|
||||
else { bytes.push(0xe0 | (c >> 12)); bytes.push(0x80 | ((c >> 6) & 0x3f)); bytes.push(0x80 | (c & 0x3f)); }
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function placeFinder(m, r, row, col) {
|
||||
for (var dr = -1; dr <= 7; dr++) {
|
||||
for (var dc = -1; dc <= 7; dc++) {
|
||||
var rr = row + dr, cc = col + dc;
|
||||
if (rr < 0 || rr >= m.length || cc < 0 || cc >= m.length) continue;
|
||||
var val = (dr >= 0 && dr <= 6 && (dc === 0 || dc === 6)) || (dc >= 0 && dc <= 6 && (dr === 0 || dr === 6)) || (dr >= 2 && dr <= 4 && dc >= 2 && dc <= 4);
|
||||
m[rr][cc] = val;
|
||||
r[rr][cc] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function placeAlignment(m, r, row, col) {
|
||||
for (var dr = -2; dr <= 2; dr++) {
|
||||
for (var dc = -2; dc <= 2; dc++) {
|
||||
var val = Math.abs(dr) === 2 || Math.abs(dc) === 2 || (dr === 0 && dc === 0);
|
||||
m[row + dr][col + dc] = val;
|
||||
r[row + dr][col + dc] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getAlignmentPositions(v) {
|
||||
if (v <= 1) return [];
|
||||
if (v === 2) return [6, 18];
|
||||
if (v === 3) return [6, 22];
|
||||
if (v === 4) return [6, 26];
|
||||
if (v === 5) return [6, 30];
|
||||
return [6, 34];
|
||||
}
|
||||
|
||||
function isInFinder(row, col, n) {
|
||||
return (row < 9 && col < 9) || (row < 9 && col >= n - 8) || (row >= n - 8 && col < 9);
|
||||
}
|
||||
|
||||
function encodeData(data, version) {
|
||||
var bits = [];
|
||||
// Mode indicator: Byte = 0100
|
||||
bits.push(0, 1, 0, 0);
|
||||
// Character count
|
||||
var ccBits = version <= 9 ? 8 : 16;
|
||||
for (var i = ccBits - 1; i >= 0; i--) bits.push((data.length >> i) & 1);
|
||||
// Data
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
for (var j = 7; j >= 0; j--) bits.push((data[i] >> j) & 1);
|
||||
}
|
||||
// Terminator
|
||||
var capacities = [0, 152, 272, 440, 640, 864, 1088];
|
||||
var cap = capacities[version] || 152;
|
||||
for (var i = 0; i < 4 && bits.length < cap; i++) bits.push(0);
|
||||
// Pad to byte boundary
|
||||
while (bits.length % 8 !== 0) bits.push(0);
|
||||
// Pad bytes
|
||||
var padBytes = [0xEC, 0x11];
|
||||
var pi = 0;
|
||||
while (bits.length < cap) {
|
||||
var pb = padBytes[pi % 2];
|
||||
for (var j = 7; j >= 0; j--) bits.push((pb >> j) & 1);
|
||||
pi++;
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
function placeData(matrix, reserved, bits, n) {
|
||||
var bitIndex = 0;
|
||||
for (var right = n - 1; right >= 1; right -= 2) {
|
||||
if (right === 6) right = 5;
|
||||
for (var vert = 0; vert < n; vert++) {
|
||||
for (var j = 0; j < 2; j++) {
|
||||
var col = right - j;
|
||||
var upward = ((right + 1) & 2) === 0;
|
||||
var row = upward ? n - 1 - vert : vert;
|
||||
if (!reserved[row][col] && bitIndex < bits.length) {
|
||||
matrix[row][col] = bits[bitIndex] === 1;
|
||||
bitIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function applyMask(matrix, reserved, maskNum, n) {
|
||||
var result = createMatrix(n);
|
||||
for (var r = 0; r < n; r++) {
|
||||
for (var c = 0; c < n; c++) {
|
||||
result[r][c] = matrix[r][c];
|
||||
if (!reserved[r][c]) {
|
||||
var invert = false;
|
||||
switch (maskNum) {
|
||||
case 0: invert = (r + c) % 2 === 0; break;
|
||||
case 1: invert = r % 2 === 0; break;
|
||||
case 2: invert = c % 3 === 0; break;
|
||||
case 3: invert = (r + c) % 3 === 0; break;
|
||||
case 4: invert = (Math.floor(r / 2) + Math.floor(c / 3)) % 2 === 0; break;
|
||||
case 5: invert = (r * c) % 2 + (r * c) % 3 === 0; break;
|
||||
case 6: invert = ((r * c) % 2 + (r * c) % 3) % 2 === 0; break;
|
||||
case 7: invert = ((r + c) % 2 + (r * c) % 3) % 2 === 0; break;
|
||||
}
|
||||
if (invert) result[r][c] = !result[r][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function calcPenalty(matrix, n) {
|
||||
var penalty = 0;
|
||||
// Rule 1: consecutive same-color modules in row/column
|
||||
for (var r = 0; r < n; r++) {
|
||||
var run = 1;
|
||||
for (var c = 1; c < n; c++) {
|
||||
if (matrix[r][c] === matrix[r][c - 1]) { run++; } else { run = 1; }
|
||||
if (run === 5) penalty += 3;
|
||||
else if (run > 5) penalty += 1;
|
||||
}
|
||||
}
|
||||
for (var c = 0; c < n; c++) {
|
||||
var run = 1;
|
||||
for (var r = 1; r < n; r++) {
|
||||
if (matrix[r][c] === matrix[r - 1][c]) { run++; } else { run = 1; }
|
||||
if (run === 5) penalty += 3;
|
||||
else if (run > 5) penalty += 1;
|
||||
}
|
||||
}
|
||||
return penalty;
|
||||
}
|
||||
|
||||
function placeFormatInfo(matrix, maskNum, n) {
|
||||
var formatInfo = getFormatInfo(maskNum);
|
||||
// Place around top-left finder
|
||||
var positions = [
|
||||
[8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [8, 5], [8, 7], [8, 8],
|
||||
[7, 8], [5, 8], [4, 8], [3, 8], [2, 8], [1, 8], [0, 8]
|
||||
];
|
||||
for (var i = 0; i < 15; i++) {
|
||||
var r = positions[i][0], c = positions[i][1];
|
||||
matrix[r][c] = formatInfo[i] === 1;
|
||||
}
|
||||
// Place around bottom-left and top-right finders
|
||||
var positions2 = [
|
||||
[n - 1, 8], [n - 2, 8], [n - 3, 8], [n - 4, 8], [n - 5, 8], [n - 6, 8], [n - 7, 8],
|
||||
[8, n - 8], [8, n - 7], [8, n - 6], [8, n - 5], [8, n - 4], [8, n - 3], [8, n - 2], [8, n - 1]
|
||||
];
|
||||
for (var i = 0; i < 15; i++) {
|
||||
var r = positions2[i][0], c = positions2[i][1];
|
||||
matrix[r][c] = formatInfo[i] === 1;
|
||||
}
|
||||
}
|
||||
|
||||
function getFormatInfo(maskNum) {
|
||||
// EC level L = 01, mask number = maskNum
|
||||
var data = (0x01 << 3) | maskNum; // 5 bits
|
||||
var bits = data << 10;
|
||||
// BCH(15,5) error correction
|
||||
var gen = 0x537; // generator polynomial
|
||||
for (var i = 14; i >= 10; i--) {
|
||||
if (bits & (1 << i)) bits ^= gen << (i - 10);
|
||||
}
|
||||
var formatBits = (data << 10) | bits;
|
||||
// XOR with mask pattern
|
||||
formatBits ^= 0x5412;
|
||||
var result = [];
|
||||
for (var i = 14; i >= 0; i--) result.push((formatBits >> i) & 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
function isWeixinEnv() {
|
||||
return /micromessenger/i.test(window.navigator.userAgent || '') || !!window.WeixinJSBridge;
|
||||
}
|
||||
|
||||
function normalizePayload(payload) {
|
||||
payload = payload || {};
|
||||
return {
|
||||
title: payload.title || document.title,
|
||||
url: payload.url || window.location.href,
|
||||
desc: payload.desc || '',
|
||||
image: payload.image || ''
|
||||
};
|
||||
}
|
||||
|
||||
function hideQrFallback(qrBox) {
|
||||
if (!qrBox) return;
|
||||
qrBox.classList.remove('is-visible');
|
||||
qrBox.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
|
||||
function showQrFallback(payload) {
|
||||
var qrBox = payload.qrBox;
|
||||
var qrImage = payload.qrImage;
|
||||
if (!qrBox || !qrImage || !payload.url) {
|
||||
return Promise.resolve({
|
||||
mode: 'error',
|
||||
message: '当前页面缺少微信二维码容器'
|
||||
});
|
||||
}
|
||||
|
||||
if (qrImage.dataset.qrValue !== payload.url || !qrImage.getAttribute('src')) {
|
||||
qrImage.dataset.qrValue = payload.url;
|
||||
var dataUrl = buildQRCodeDataUrl(payload.url, 160);
|
||||
if (dataUrl) {
|
||||
qrImage.src = dataUrl;
|
||||
} else {
|
||||
qrImage.alt = '二维码生成失败,请直接复制链接分享';
|
||||
}
|
||||
}
|
||||
|
||||
qrBox.classList.add('is-visible');
|
||||
qrBox.setAttribute('aria-hidden', 'false');
|
||||
|
||||
return Promise.resolve({
|
||||
mode: 'qr',
|
||||
message: '请使用微信扫一扫分享'
|
||||
});
|
||||
}
|
||||
|
||||
function bridgeWithWxSdk(payload) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (!window.wx || typeof window.wx.ready !== 'function') {
|
||||
reject(new Error('wx sdk unavailable'));
|
||||
return;
|
||||
}
|
||||
|
||||
var done = false;
|
||||
var timer = window.setTimeout(function () {
|
||||
if (done) return;
|
||||
done = true;
|
||||
reject(new Error('微信分享桥接未就绪'));
|
||||
}, 1200);
|
||||
|
||||
function finishSuccess() {
|
||||
if (done) return;
|
||||
done = true;
|
||||
window.clearTimeout(timer);
|
||||
resolve({
|
||||
mode: 'bridge',
|
||||
message: '已同步微信分享信息,请使用右上角菜单继续分享'
|
||||
});
|
||||
}
|
||||
|
||||
function finishError(error) {
|
||||
if (done) return;
|
||||
done = true;
|
||||
window.clearTimeout(timer);
|
||||
reject(error instanceof Error ? error : new Error('微信分享桥接失败'));
|
||||
}
|
||||
|
||||
try {
|
||||
if (typeof window.wx.error === 'function') {
|
||||
window.wx.error(function (error) {
|
||||
finishError(new Error((error && error.errMsg) || '微信签名校验失败'));
|
||||
});
|
||||
}
|
||||
|
||||
window.wx.ready(function () {
|
||||
try {
|
||||
if (typeof window.wx.updateAppMessageShareData === 'function') {
|
||||
window.wx.updateAppMessageShareData({
|
||||
title: payload.title,
|
||||
desc: payload.desc,
|
||||
link: payload.url,
|
||||
imgUrl: payload.image
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof window.wx.updateTimelineShareData === 'function') {
|
||||
window.wx.updateTimelineShareData({
|
||||
title: payload.title,
|
||||
link: payload.url,
|
||||
imgUrl: payload.image
|
||||
});
|
||||
}
|
||||
|
||||
finishSuccess();
|
||||
} catch (error) {
|
||||
finishError(error);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
finishError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function bridgeWithWeixinJsBridge(payload) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var bridge = window.WeixinJSBridge;
|
||||
if (!bridge || typeof bridge.invoke !== 'function') {
|
||||
reject(new Error('WeixinJSBridge unavailable'));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
bridge.invoke('sendAppMessage', {
|
||||
title: payload.title,
|
||||
desc: payload.desc,
|
||||
link: payload.url,
|
||||
img_url: payload.image
|
||||
}, function (response) {
|
||||
var errMsg = response && response.err_msg ? response.err_msg : '';
|
||||
if (!errMsg || /:ok$/i.test(errMsg)) {
|
||||
resolve({
|
||||
mode: 'bridge',
|
||||
message: '已调起微信分享面板'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
reject(new Error(errMsg));
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function openWeixinShare(payload) {
|
||||
var data = normalizePayload(payload);
|
||||
data.qrBox = payload && payload.qrBox ? payload.qrBox : null;
|
||||
data.qrImage = payload && payload.qrImage ? payload.qrImage : null;
|
||||
|
||||
if (!isWeixinEnv()) {
|
||||
return showQrFallback(data);
|
||||
}
|
||||
|
||||
return bridgeWithWxSdk(data)
|
||||
.catch(function () {
|
||||
return bridgeWithWeixinJsBridge(data);
|
||||
})
|
||||
.catch(function (error) {
|
||||
return showQrFallback(data).then(function (result) {
|
||||
result.message = (error && error.message ? error.message + ',' : '') + '已切换为二维码分享';
|
||||
return result;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
window.AksrtShare = Object.assign({}, window.AksrtShare || {}, {
|
||||
isWeixinEnv: isWeixinEnv,
|
||||
hideQrFallback: hideQrFallback,
|
||||
showQrFallback: showQrFallback,
|
||||
openWeixinShare: openWeixinShare,
|
||||
// Exposed so the unified share-data-builder can render poster QR codes
|
||||
// without a second encoder.
|
||||
buildQrDataUrl: buildQRCodeDataUrl
|
||||
});
|
||||
})();
|
||||
Reference in new issue
Block a user