界面样式调整
This commit is contained in:
parent
d70b962ef5
commit
cdf5f81601
78
README.md
78
README.md
@ -1,62 +1,62 @@
|
|||||||
# OBS Overlay Widget
|
# OBS 悬浮小组件
|
||||||
|
|
||||||
A collection of highly customizable widgets for OBS Studio streaming and recording, built with Vue 3, TypeScript, and Vite.
|
一个为 OBS Studio 直播和录制场景开发的高度可定制化小组件集合,基于 Vue 3、TypeScript 和 Vite 构建。
|
||||||
|
|
||||||
## Features
|
## 功能特点
|
||||||
|
|
||||||
- **Time and Date Display**: Customizable formats for showing current time and date
|
- **时间和日期显示**:可自定义格式的时间和日期显示
|
||||||
- **Text Display**: Show fixed text or API-returned content with custom styling
|
- **文本显示**:展示固定文字或 API 返回内容,支持自定义样式
|
||||||
- **Image Display**: Display local or remote images with customization options
|
- **图片显示**:展示本地或远程图片,支持自定义设置
|
||||||
- **Split View Interface**: Configuration panel on the left, real-time preview on the right
|
- **分屏界面**:左侧为配置面板,右侧为实时预览
|
||||||
- **Transparent Background**: All widgets have transparent backgrounds suitable for OBS overlay
|
- **透明背景**:所有小组件均具有适合 OBS 悬浮的透明背景
|
||||||
- **URL Generation**: Automatically generates sharable URLs with encoded configuration
|
- **URL 生成**:自动生成包含编码配置的可分享 URL
|
||||||
- **Pure Preview Mode**: Open generated URLs to display only the widget with transparent background
|
- **纯预览模式**:打开生成的 URL 仅显示小组件内容,无配置界面,背景透明
|
||||||
|
|
||||||
## Widget Types
|
## 小组件类型
|
||||||
|
|
||||||
1. **Clock Widget**: Display current time with customizable format, style, and effects
|
1. **时钟小组件**:显示当前时间,可自定义格式、样式和特效
|
||||||
2. **Date Widget**: Show current date with customizable format, style, and effects
|
2. **日期小组件**:显示当前日期,可自定义格式、样式和特效
|
||||||
3. **Text Widget**: Display text with customizable styles including gradients, shadows, and fonts
|
3. **文本小组件**:显示文本,支持渐变、阴影、字体等自定义样式
|
||||||
4. **Image Widget**: Show images with customizable size, effects, and positioning
|
4. **图片小组件**:显示图片,可自定义大小、特效和位置
|
||||||
|
|
||||||
## Usage
|
## 使用方法
|
||||||
|
|
||||||
1. Select a widget type from the dropdown
|
1. 从下拉菜单中选择小组件类型
|
||||||
2. Configure the widget using the control panel on the left
|
2. 使用左侧控制面板配置小组件
|
||||||
3. See real-time preview on the right
|
3. 在右侧实时查看预览效果
|
||||||
4. Copy the generated URL to use in OBS Studio as a Browser Source
|
4. 复制生成的 URL,在 OBS Studio 中作为浏览器源使用
|
||||||
|
|
||||||
## Development
|
## 开发
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Install dependencies
|
# 安装依赖
|
||||||
npm install
|
npm install
|
||||||
|
|
||||||
# Start development server
|
# 启动开发服务器
|
||||||
npm run dev
|
npm run dev
|
||||||
|
|
||||||
# Build for production
|
# 构建生产版本
|
||||||
npm run build
|
npm run build
|
||||||
|
|
||||||
# Preview production build
|
# 预览生产构建
|
||||||
npm run preview
|
npm run preview
|
||||||
```
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## 故障排除
|
||||||
|
|
||||||
If you encounter TypeScript errors related to undefined properties, make sure that:
|
如果遇到与未定义属性相关的 TypeScript 错误,请确保:
|
||||||
|
|
||||||
1. All widget components handle possible undefined configuration properties
|
1. 所有小组件组件都能处理可能未定义的配置属性
|
||||||
2. Default values are provided for all configuration options
|
2. 为所有配置选项提供默认值
|
||||||
3. Use proper null checking (e.g., `props.config.property || defaultValue`)
|
3. 使用适当的空值检查(例如:`props.config.property || defaultValue`)
|
||||||
|
|
||||||
## Integration with OBS Studio
|
## 与 OBS Studio 集成
|
||||||
|
|
||||||
1. Run this application on a web server or locally
|
1. 在 Web 服务器或本地运行此应用
|
||||||
2. Configure your widget using the configuration interface
|
2. 使用配置界面设置您的小组件
|
||||||
3. Copy the generated URL
|
3. 复制生成的 URL
|
||||||
4. In OBS Studio:
|
4. 在 OBS Studio 中:
|
||||||
- Add a "Browser Source" to your scene
|
- 向您的场景添加"浏览器源"
|
||||||
- Paste the URL into the Browser Source URL field
|
- 将 URL 粘贴到浏览器源 URL 字段
|
||||||
- Set width and height according to your needs
|
- 根据需要设置宽度和高度
|
||||||
- Check "Shutdown source when not visible" for better performance
|
- 勾选"不可见时关闭源"以获得更好的性能
|
||||||
|
@ -1,28 +1,47 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="clock-config">
|
<div class="clock-config">
|
||||||
<h2>Clock Widget Settings</h2>
|
<h2>时钟小组件设置</h2>
|
||||||
|
|
||||||
<el-form label-position="top">
|
<el-form label-position="top">
|
||||||
<el-form-item label="Time Format">
|
<el-form-item label="时间格式">
|
||||||
<el-select v-model="localConfig.format" placeholder="Select format">
|
<el-select v-model="localConfig.format" placeholder="选择格式">
|
||||||
<el-option label="HH:mm:ss (24-hour)" value="HH:mm:ss" />
|
<el-option label="HH:mm:ss (24小时制)" value="HH:mm:ss" />
|
||||||
<el-option label="HH:mm (24-hour)" value="HH:mm" />
|
<el-option label="HH:mm (24小时制)" value="HH:mm" />
|
||||||
<el-option label="hh:mm:ss A (12-hour)" value="hh:mm:ss A" />
|
<el-option label="hh:mm:ss A (12小时制)" value="hh:mm:ss A" />
|
||||||
<el-option label="hh:mm A (12-hour)" value="hh:mm A" />
|
<el-option label="hh:mm A (12小时制)" value="hh:mm A" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Show Seconds">
|
<el-form-item>
|
||||||
<el-switch v-model="localConfig.showSeconds" />
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<div>
|
||||||
|
<span>显示秒</span>
|
||||||
|
<el-switch v-model="localConfig.showSeconds" style="margin-left: 10px;" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>显示日期</span>
|
||||||
|
<el-switch v-model="localConfig.showDate" style="margin-left: 10px;" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-divider>Text Style</el-divider>
|
<el-form-item v-if="localConfig.showDate" label="日期格式">
|
||||||
|
<el-select v-model="localConfig.dateFormat" placeholder="选择格式">
|
||||||
|
<el-option label="YYYY-MM-DD" value="YYYY-MM-DD" />
|
||||||
|
<el-option label="MM/DD/YYYY" value="MM/DD/YYYY" />
|
||||||
|
<el-option label="DD/MM/YYYY" value="DD/MM/YYYY" />
|
||||||
|
<el-option label="MMMM D, YYYY" value="MMMM D, YYYY" />
|
||||||
|
<el-option label="D MMMM YYYY" value="D MMMM YYYY" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Font Size">
|
<el-divider>文本样式</el-divider>
|
||||||
|
|
||||||
|
<el-form-item label="字体大小">
|
||||||
<el-slider v-model="localConfig.fontSize" :min="12" :max="120" show-input />
|
<el-slider v-model="localConfig.fontSize" :min="12" :max="120" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Font Family">
|
<el-form-item label="字体">
|
||||||
<el-select v-model="localConfig.fontFamily">
|
<el-select v-model="localConfig.fontFamily">
|
||||||
<el-option label="Arial" value="Arial" />
|
<el-option label="Arial" value="Arial" />
|
||||||
<el-option label="Helvetica" value="Helvetica" />
|
<el-option label="Helvetica" value="Helvetica" />
|
||||||
@ -34,58 +53,58 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Font Weight">
|
<el-form-item label="字重">
|
||||||
<el-select v-model="localConfig.fontWeight">
|
<el-select v-model="localConfig.fontWeight">
|
||||||
<el-option label="Normal" value="normal" />
|
<el-option label="普通" value="normal" />
|
||||||
<el-option label="Bold" value="bold" />
|
<el-option label="粗体" value="bold" />
|
||||||
<el-option label="Light" value="lighter" />
|
<el-option label="细体" value="lighter" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-divider>Color Settings</el-divider>
|
<el-divider>颜色设置</el-divider>
|
||||||
|
|
||||||
<el-form-item label="Use Gradient Colors">
|
<el-form-item label="使用渐变色">
|
||||||
<el-switch v-model="localConfig.useGradient" />
|
<el-switch v-model="localConfig.useGradient" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<template v-if="!localConfig.useGradient">
|
<template v-if="!localConfig.useGradient">
|
||||||
<el-form-item label="Text Color">
|
<el-form-item label="文本颜色">
|
||||||
<el-color-picker v-model="localConfig.color" show-alpha />
|
<el-color-picker v-model="localConfig.color" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-form-item label="Gradient Start Color">
|
<el-form-item label="渐变起始颜色">
|
||||||
<el-color-picker v-model="localConfig.gradientColors[0]" show-alpha />
|
<el-color-picker v-model="localConfig.gradientColors[0]" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Gradient End Color">
|
<el-form-item label="渐变结束颜色">
|
||||||
<el-color-picker v-model="localConfig.gradientColors[1]" show-alpha />
|
<el-color-picker v-model="localConfig.gradientColors[1]" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-divider>Effects</el-divider>
|
<el-divider>特效</el-divider>
|
||||||
|
|
||||||
<el-form-item label="Text Shadow">
|
<el-form-item label="文字阴影">
|
||||||
<el-switch v-model="localConfig.textShadow" />
|
<el-switch v-model="localConfig.textShadow" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<template v-if="localConfig.textShadow">
|
<template v-if="localConfig.textShadow">
|
||||||
<el-form-item label="Shadow Color">
|
<el-form-item label="阴影颜色">
|
||||||
<el-color-picker v-model="localConfig.shadowColor" show-alpha />
|
<el-color-picker v-model="localConfig.shadowColor" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Shadow Blur">
|
<el-form-item label="阴影模糊度">
|
||||||
<el-slider v-model="localConfig.shadowBlur" :min="0" :max="20" show-input />
|
<el-slider v-model="localConfig.shadowBlur" :min="0" :max="20" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button-group>
|
<el-button-group>
|
||||||
<el-button type="primary" @click="applyPreset('modern')">Modern</el-button>
|
<el-button type="primary" @click="applyPreset('modern')">现代风格</el-button>
|
||||||
<el-button type="success" @click="applyPreset('neon')">Neon</el-button>
|
<el-button type="success" @click="applyPreset('neon')">霓虹风格</el-button>
|
||||||
<el-button type="warning" @click="applyPreset('elegant')">Elegant</el-button>
|
<el-button type="warning" @click="applyPreset('elegant')">优雅风格</el-button>
|
||||||
<el-button type="danger" @click="applyPreset('minimal')">Minimal</el-button>
|
<el-button type="danger" @click="applyPreset('minimal')">简约风格</el-button>
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@ -95,7 +114,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch, onMounted } from 'vue';
|
import { ref, watch, onMounted } from 'vue';
|
||||||
|
|
||||||
// Define props interface for config
|
// 为配置定义 props 接口
|
||||||
interface ClockConfig {
|
interface ClockConfig {
|
||||||
format: string;
|
format: string;
|
||||||
color: string;
|
color: string;
|
||||||
@ -108,6 +127,8 @@ interface ClockConfig {
|
|||||||
useGradient: boolean;
|
useGradient: boolean;
|
||||||
gradientColors: string[];
|
gradientColors: string[];
|
||||||
showSeconds: boolean;
|
showSeconds: boolean;
|
||||||
|
showDate: boolean;
|
||||||
|
dateFormat: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define props with default values
|
// Define props with default values
|
||||||
@ -125,7 +146,9 @@ const props = withDefaults(defineProps<{
|
|||||||
shadowBlur: 4,
|
shadowBlur: 4,
|
||||||
useGradient: false,
|
useGradient: false,
|
||||||
gradientColors: ['#ff0000', '#0000ff'],
|
gradientColors: ['#ff0000', '#0000ff'],
|
||||||
showSeconds: true
|
showSeconds: true,
|
||||||
|
showDate: false,
|
||||||
|
dateFormat: 'YYYY-MM-DD'
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -146,7 +169,9 @@ const localConfig = ref<ClockConfig>({
|
|||||||
shadowBlur: 4,
|
shadowBlur: 4,
|
||||||
useGradient: false,
|
useGradient: false,
|
||||||
gradientColors: ['#ff0000', '#0000ff'],
|
gradientColors: ['#ff0000', '#0000ff'],
|
||||||
showSeconds: true
|
showSeconds: true,
|
||||||
|
showDate: false,
|
||||||
|
dateFormat: 'YYYY-MM-DD'
|
||||||
});
|
});
|
||||||
|
|
||||||
// Sync with parent config on mount
|
// Sync with parent config on mount
|
||||||
@ -167,7 +192,9 @@ const presets = {
|
|||||||
textShadow: true,
|
textShadow: true,
|
||||||
shadowColor: 'rgba(0, 0, 0, 0.3)',
|
shadowColor: 'rgba(0, 0, 0, 0.3)',
|
||||||
shadowBlur: 10,
|
shadowBlur: 10,
|
||||||
showSeconds: false
|
showSeconds: false,
|
||||||
|
showDate: true,
|
||||||
|
dateFormat: 'YYYY-MM-DD'
|
||||||
},
|
},
|
||||||
neon: {
|
neon: {
|
||||||
format: 'HH:mm:ss',
|
format: 'HH:mm:ss',
|
||||||
@ -179,7 +206,8 @@ const presets = {
|
|||||||
textShadow: true,
|
textShadow: true,
|
||||||
shadowColor: 'rgba(57, 255, 20, 0.8)',
|
shadowColor: 'rgba(57, 255, 20, 0.8)',
|
||||||
shadowBlur: 15,
|
shadowBlur: 15,
|
||||||
showSeconds: true
|
showSeconds: true,
|
||||||
|
showDate: false
|
||||||
},
|
},
|
||||||
elegant: {
|
elegant: {
|
||||||
format: 'hh:mm A',
|
format: 'hh:mm A',
|
||||||
@ -191,7 +219,9 @@ const presets = {
|
|||||||
textShadow: true,
|
textShadow: true,
|
||||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
shadowBlur: 5,
|
shadowBlur: 5,
|
||||||
showSeconds: false
|
showSeconds: false,
|
||||||
|
showDate: true,
|
||||||
|
dateFormat: 'MMMM D, YYYY'
|
||||||
},
|
},
|
||||||
minimal: {
|
minimal: {
|
||||||
format: 'HH:mm',
|
format: 'HH:mm',
|
||||||
@ -201,7 +231,8 @@ const presets = {
|
|||||||
color: '#ffffff',
|
color: '#ffffff',
|
||||||
useGradient: false,
|
useGradient: false,
|
||||||
textShadow: false,
|
textShadow: false,
|
||||||
showSeconds: false
|
showSeconds: false,
|
||||||
|
showDate: false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="date-config">
|
<div class="date-config">
|
||||||
<h2>Date Widget Settings</h2>
|
<h2>日期小组件设置</h2>
|
||||||
|
|
||||||
<el-form label-position="top">
|
<el-form label-position="top">
|
||||||
<el-form-item label="Date Format">
|
<el-form-item label="日期格式">
|
||||||
<el-select v-model="localConfig.format" placeholder="Select format">
|
<el-select v-model="localConfig.format" placeholder="选择格式">
|
||||||
<el-option label="YYYY-MM-DD" value="YYYY-MM-DD" />
|
<el-option label="YYYY-MM-DD" value="YYYY-MM-DD" />
|
||||||
<el-option label="MM/DD/YYYY" value="MM/DD/YYYY" />
|
<el-option label="MM/DD/YYYY" value="MM/DD/YYYY" />
|
||||||
<el-option label="DD/MM/YYYY" value="DD/MM/YYYY" />
|
<el-option label="DD/MM/YYYY" value="DD/MM/YYYY" />
|
||||||
@ -13,17 +13,17 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Show Weekday">
|
<el-form-item label="显示星期">
|
||||||
<el-switch v-model="localConfig.showWeekday" />
|
<el-switch v-model="localConfig.showWeekday" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-divider>Text Style</el-divider>
|
<el-divider>文本样式</el-divider>
|
||||||
|
|
||||||
<el-form-item label="Font Size">
|
<el-form-item label="字体大小">
|
||||||
<el-slider v-model="localConfig.fontSize" :min="12" :max="80" show-input />
|
<el-slider v-model="localConfig.fontSize" :min="12" :max="80" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Font Family">
|
<el-form-item label="字体">
|
||||||
<el-select v-model="localConfig.fontFamily">
|
<el-select v-model="localConfig.fontFamily">
|
||||||
<el-option label="Arial" value="Arial" />
|
<el-option label="Arial" value="Arial" />
|
||||||
<el-option label="Helvetica" value="Helvetica" />
|
<el-option label="Helvetica" value="Helvetica" />
|
||||||
@ -35,58 +35,58 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Font Weight">
|
<el-form-item label="字重">
|
||||||
<el-select v-model="localConfig.fontWeight">
|
<el-select v-model="localConfig.fontWeight">
|
||||||
<el-option label="Normal" value="normal" />
|
<el-option label="普通" value="normal" />
|
||||||
<el-option label="Bold" value="bold" />
|
<el-option label="粗体" value="bold" />
|
||||||
<el-option label="Light" value="lighter" />
|
<el-option label="细体" value="lighter" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-divider>Color Settings</el-divider>
|
<el-divider>颜色设置</el-divider>
|
||||||
|
|
||||||
<el-form-item label="Use Gradient Colors">
|
<el-form-item label="使用渐变色">
|
||||||
<el-switch v-model="localConfig.useGradient" />
|
<el-switch v-model="localConfig.useGradient" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<template v-if="!localConfig.useGradient">
|
<template v-if="!localConfig.useGradient">
|
||||||
<el-form-item label="Text Color">
|
<el-form-item label="文本颜色">
|
||||||
<el-color-picker v-model="localConfig.color" show-alpha />
|
<el-color-picker v-model="localConfig.color" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-form-item label="Gradient Start Color">
|
<el-form-item label="渐变起始颜色">
|
||||||
<el-color-picker v-model="localConfig.gradientColors[0]" show-alpha />
|
<el-color-picker v-model="localConfig.gradientColors[0]" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Gradient End Color">
|
<el-form-item label="渐变结束颜色">
|
||||||
<el-color-picker v-model="localConfig.gradientColors[1]" show-alpha />
|
<el-color-picker v-model="localConfig.gradientColors[1]" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-divider>Effects</el-divider>
|
<el-divider>特效</el-divider>
|
||||||
|
|
||||||
<el-form-item label="Text Shadow">
|
<el-form-item label="文字阴影">
|
||||||
<el-switch v-model="localConfig.textShadow" />
|
<el-switch v-model="localConfig.textShadow" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<template v-if="localConfig.textShadow">
|
<template v-if="localConfig.textShadow">
|
||||||
<el-form-item label="Shadow Color">
|
<el-form-item label="阴影颜色">
|
||||||
<el-color-picker v-model="localConfig.shadowColor" show-alpha />
|
<el-color-picker v-model="localConfig.shadowColor" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Shadow Blur">
|
<el-form-item label="阴影模糊度">
|
||||||
<el-slider v-model="localConfig.shadowBlur" :min="0" :max="20" show-input />
|
<el-slider v-model="localConfig.shadowBlur" :min="0" :max="20" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button-group>
|
<el-button-group>
|
||||||
<el-button type="primary" @click="applyPreset('modern')">Modern</el-button>
|
<el-button type="primary" @click="applyPreset('modern')">现代风格</el-button>
|
||||||
<el-button type="success" @click="applyPreset('elegant')">Elegant</el-button>
|
<el-button type="success" @click="applyPreset('elegant')">优雅风格</el-button>
|
||||||
<el-button type="warning" @click="applyPreset('casual')">Casual</el-button>
|
<el-button type="warning" @click="applyPreset('casual')">休闲风格</el-button>
|
||||||
<el-button type="danger" @click="applyPreset('minimal')">Minimal</el-button>
|
<el-button type="danger" @click="applyPreset('minimal')">简约风格</el-button>
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
@ -1,56 +1,56 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="image-config">
|
<div class="image-config">
|
||||||
<h2>Image Widget Settings</h2>
|
<h2>图片小组件设置</h2>
|
||||||
|
|
||||||
<el-form label-position="top">
|
<el-form label-position="top">
|
||||||
<el-form-item label="Image URL">
|
<el-form-item label="图片URL">
|
||||||
<el-input v-model="localConfig.imageUrl" placeholder="Enter image URL" />
|
<el-input v-model="localConfig.imageUrl" placeholder="输入图片URL" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<div class="preview-image" v-if="localConfig.imageUrl">
|
<div class="preview-image" v-if="localConfig.imageUrl">
|
||||||
<img :src="localConfig.imageUrl" alt="Preview" style="max-width: 100%; max-height: 150px;" />
|
<img :src="localConfig.imageUrl" alt="预览" style="max-width: 100%; max-height: 150px;" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-divider>Size & Appearance</el-divider>
|
<el-divider>尺寸与外观</el-divider>
|
||||||
|
|
||||||
<el-form-item label="Width (px)">
|
<el-form-item label="宽度 (像素)">
|
||||||
<el-slider v-model="localConfig.width" :min="50" :max="800" show-input />
|
<el-slider v-model="localConfig.width" :min="50" :max="800" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Height (px)">
|
<el-form-item label="高度 (像素)">
|
||||||
<el-slider v-model="localConfig.height" :min="50" :max="800" show-input />
|
<el-slider v-model="localConfig.height" :min="50" :max="800" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Opacity">
|
<el-form-item label="透明度">
|
||||||
<el-slider v-model="localConfig.opacity" :min="0" :max="1" :step="0.01" show-input />
|
<el-slider v-model="localConfig.opacity" :min="0" :max="1" :step="0.01" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Border Radius (px)">
|
<el-form-item label="圆角半径 (像素)">
|
||||||
<el-slider v-model="localConfig.borderRadius" :min="0" :max="100" show-input />
|
<el-slider v-model="localConfig.borderRadius" :min="0" :max="100" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-divider>Effects</el-divider>
|
<el-divider>特效</el-divider>
|
||||||
|
|
||||||
<el-form-item label="Shadow">
|
<el-form-item label="阴影">
|
||||||
<el-switch v-model="localConfig.shadow" />
|
<el-switch v-model="localConfig.shadow" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<template v-if="localConfig.shadow">
|
<template v-if="localConfig.shadow">
|
||||||
<el-form-item label="Shadow Color">
|
<el-form-item label="阴影颜色">
|
||||||
<el-color-picker v-model="localConfig.shadowColor" show-alpha />
|
<el-color-picker v-model="localConfig.shadowColor" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Shadow Blur">
|
<el-form-item label="阴影模糊度">
|
||||||
<el-slider v-model="localConfig.shadowBlur" :min="0" :max="50" show-input />
|
<el-slider v-model="localConfig.shadowBlur" :min="0" :max="50" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button-group>
|
<el-button-group>
|
||||||
<el-button type="primary" @click="applyPreset('normal')">Normal</el-button>
|
<el-button type="primary" @click="applyPreset('normal')">正常</el-button>
|
||||||
<el-button type="success" @click="applyPreset('rounded')">Rounded</el-button>
|
<el-button type="success" @click="applyPreset('rounded')">圆角</el-button>
|
||||||
<el-button type="warning" @click="applyPreset('shadow')">Shadow</el-button>
|
<el-button type="warning" @click="applyPreset('shadow')">阴影</el-button>
|
||||||
<el-button type="danger" @click="applyPreset('circular')">Circular</el-button>
|
<el-button type="danger" @click="applyPreset('circular')">圆形</el-button>
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="text-config">
|
<div class="text-config">
|
||||||
<h2>Text Widget Settings</h2>
|
<h2>文本小组件设置</h2>
|
||||||
|
|
||||||
<el-form label-position="top">
|
<el-form label-position="top">
|
||||||
<el-form-item label="Text Content">
|
<el-form-item label="文本内容">
|
||||||
<el-input v-model="localConfig.text" type="textarea" :rows="3" placeholder="Enter text to display" />
|
<el-input v-model="localConfig.text" type="textarea" :rows="3" placeholder="输入要显示的文本" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-divider>Text Style</el-divider>
|
<el-divider>文本样式</el-divider>
|
||||||
|
|
||||||
<el-form-item label="Font Size">
|
<el-form-item label="字体大小">
|
||||||
<el-slider v-model="localConfig.fontSize" :min="12" :max="100" show-input />
|
<el-slider v-model="localConfig.fontSize" :min="12" :max="100" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Font Family">
|
<el-form-item label="字体">
|
||||||
<el-select v-model="localConfig.fontFamily">
|
<el-select v-model="localConfig.fontFamily">
|
||||||
<el-option label="Arial" value="Arial" />
|
<el-option label="Arial" value="Arial" />
|
||||||
<el-option label="Helvetica" value="Helvetica" />
|
<el-option label="Helvetica" value="Helvetica" />
|
||||||
@ -25,58 +25,58 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Font Weight">
|
<el-form-item label="字重">
|
||||||
<el-select v-model="localConfig.fontWeight">
|
<el-select v-model="localConfig.fontWeight">
|
||||||
<el-option label="Normal" value="normal" />
|
<el-option label="普通" value="normal" />
|
||||||
<el-option label="Bold" value="bold" />
|
<el-option label="粗体" value="bold" />
|
||||||
<el-option label="Light" value="lighter" />
|
<el-option label="细体" value="lighter" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-divider>Color Settings</el-divider>
|
<el-divider>颜色设置</el-divider>
|
||||||
|
|
||||||
<el-form-item label="Use Gradient Colors">
|
<el-form-item label="使用渐变色">
|
||||||
<el-switch v-model="localConfig.useGradient" />
|
<el-switch v-model="localConfig.useGradient" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<template v-if="!localConfig.useGradient">
|
<template v-if="!localConfig.useGradient">
|
||||||
<el-form-item label="Text Color">
|
<el-form-item label="文本颜色">
|
||||||
<el-color-picker v-model="localConfig.color" show-alpha />
|
<el-color-picker v-model="localConfig.color" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-form-item label="Gradient Start Color">
|
<el-form-item label="渐变起始颜色">
|
||||||
<el-color-picker v-model="localConfig.gradientColors[0]" show-alpha />
|
<el-color-picker v-model="localConfig.gradientColors[0]" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Gradient End Color">
|
<el-form-item label="渐变结束颜色">
|
||||||
<el-color-picker v-model="localConfig.gradientColors[1]" show-alpha />
|
<el-color-picker v-model="localConfig.gradientColors[1]" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-divider>Effects</el-divider>
|
<el-divider>特效</el-divider>
|
||||||
|
|
||||||
<el-form-item label="Text Shadow">
|
<el-form-item label="文字阴影">
|
||||||
<el-switch v-model="localConfig.textShadow" />
|
<el-switch v-model="localConfig.textShadow" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<template v-if="localConfig.textShadow">
|
<template v-if="localConfig.textShadow">
|
||||||
<el-form-item label="Shadow Color">
|
<el-form-item label="阴影颜色">
|
||||||
<el-color-picker v-model="localConfig.shadowColor" show-alpha />
|
<el-color-picker v-model="localConfig.shadowColor" show-alpha />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="Shadow Blur">
|
<el-form-item label="阴影模糊度">
|
||||||
<el-slider v-model="localConfig.shadowBlur" :min="0" :max="20" show-input />
|
<el-slider v-model="localConfig.shadowBlur" :min="0" :max="20" show-input />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button-group>
|
<el-button-group>
|
||||||
<el-button type="primary" @click="applyPreset('modern')">Modern</el-button>
|
<el-button type="primary" @click="applyPreset('modern')">现代风格</el-button>
|
||||||
<el-button type="success" @click="applyPreset('neon')">Neon</el-button>
|
<el-button type="success" @click="applyPreset('neon')">霓虹风格</el-button>
|
||||||
<el-button type="warning" @click="applyPreset('retro')">Retro</el-button>
|
<el-button type="warning" @click="applyPreset('retro')">复古风格</el-button>
|
||||||
<el-button type="danger" @click="applyPreset('minimal')">Minimal</el-button>
|
<el-button type="danger" @click="applyPreset('minimal')">简约风格</el-button>
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="config-view">
|
<div class="config-view">
|
||||||
<div class="left-panel">
|
<div class="left-panel">
|
||||||
<div class="widget-selector">
|
<div class="widget-selector">
|
||||||
<el-select v-model="selectedWidget" placeholder="Select Widget" @change="handleWidgetChange">
|
<el-select v-model="selectedWidget" placeholder="选择小组件" @change="handleWidgetChange">
|
||||||
<el-option v-for="widget in widgets" :key="widget.value" :label="widget.label" :value="widget.value" />
|
<el-option v-for="widget in widgets" :key="widget.value" :label="widget.label" :value="widget.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
@ -15,7 +15,7 @@
|
|||||||
<el-input v-model="generatedUrl" readonly>
|
<el-input v-model="generatedUrl" readonly>
|
||||||
<template #append>
|
<template #append>
|
||||||
<el-button @click="copyUrl">
|
<el-button @click="copyUrl">
|
||||||
<el-icon><CopyDocument /></el-icon> Copy
|
<el-icon><CopyDocument /></el-icon> 复制
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
@ -38,42 +38,42 @@ import { CopyDocument } from '@element-plus/icons-vue';
|
|||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
import { encodeConfig, decodeConfig } from '../utils/configUtils';
|
import { encodeConfig, decodeConfig } from '../utils/configUtils';
|
||||||
|
|
||||||
// Widget components and their configs
|
// 小组件组件及其配置
|
||||||
import ClockWidget from '../widgets/ClockWidget.vue';
|
import ClockWidget from '../widgets/ClockWidget.vue';
|
||||||
import DateWidget from '../widgets/DateWidget.vue';
|
import DateWidget from '../widgets/DateWidget.vue';
|
||||||
import TextWidget from '../widgets/TextWidget.vue';
|
import TextWidget from '../widgets/TextWidget.vue';
|
||||||
import ImageWidget from '../widgets/ImageWidget.vue';
|
import ImageWidget from '../widgets/ImageWidget.vue';
|
||||||
|
|
||||||
// Config components
|
// 配置组件
|
||||||
import ClockConfig from '../components/config/ClockConfig.vue';
|
import ClockConfig from '../components/config/ClockConfig.vue';
|
||||||
import DateConfig from '../components/config/DateConfig.vue';
|
import DateConfig from '../components/config/DateConfig.vue';
|
||||||
import TextConfig from '../components/config/TextConfig.vue';
|
import TextConfig from '../components/config/TextConfig.vue';
|
||||||
import ImageConfig from '../components/config/ImageConfig.vue';
|
import ImageConfig from '../components/config/ImageConfig.vue';
|
||||||
|
|
||||||
const widgets = [
|
const widgets = [
|
||||||
{ label: 'Clock Widget', value: 'clock', component: ClockWidget, configComponent: ClockConfig },
|
{ label: '时钟小组件', value: 'clock', component: ClockWidget, configComponent: ClockConfig },
|
||||||
{ label: 'Date Widget', value: 'date', component: DateWidget, configComponent: DateConfig },
|
{ label: '日期小组件', value: 'date', component: DateWidget, configComponent: DateConfig },
|
||||||
{ label: 'Text Widget', value: 'text', component: TextWidget, configComponent: TextConfig },
|
{ label: '文本小组件', value: 'text', component: TextWidget, configComponent: TextConfig },
|
||||||
{ label: 'Image Widget', value: 'image', component: ImageWidget, configComponent: ImageConfig },
|
{ label: '图片小组件', value: 'image', component: ImageWidget, configComponent: ImageConfig },
|
||||||
];
|
];
|
||||||
|
|
||||||
const selectedWidget = ref('clock');
|
const selectedWidget = ref('clock');
|
||||||
const currentWidgetConfig = ref({});
|
const currentWidgetConfig = ref({});
|
||||||
const generatedUrl = ref('');
|
const generatedUrl = ref('');
|
||||||
|
|
||||||
// Get widget component based on selection
|
// 根据选择获取小组件组件
|
||||||
const currentWidgetComponent = computed(() => {
|
const currentWidgetComponent = computed(() => {
|
||||||
const widget = widgets.find(w => w.value === selectedWidget.value);
|
const widget = widgets.find(w => w.value === selectedWidget.value);
|
||||||
return widget?.component;
|
return widget?.component;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get config component based on selection
|
// 根据选择获取配置组件
|
||||||
const currentConfigComponent = computed(() => {
|
const currentConfigComponent = computed(() => {
|
||||||
const widget = widgets.find(w => w.value === selectedWidget.value);
|
const widget = widgets.find(w => w.value === selectedWidget.value);
|
||||||
return widget?.configComponent;
|
return widget?.configComponent;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set default config for each widget type
|
// 为每种小组件类型设置默认配置
|
||||||
const getDefaultConfig = (widgetType: string) => {
|
const getDefaultConfig = (widgetType: string) => {
|
||||||
switch (widgetType) {
|
switch (widgetType) {
|
||||||
case 'clock':
|
case 'clock':
|
||||||
@ -139,13 +139,13 @@ const handleWidgetChange = () => {
|
|||||||
updateGeneratedUrl();
|
updateGeneratedUrl();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update widget configuration
|
// 更新小组件配置
|
||||||
const updateWidgetConfig = (newConfig: any) => {
|
const updateWidgetConfig = (newConfig: any) => {
|
||||||
currentWidgetConfig.value = newConfig;
|
currentWidgetConfig.value = newConfig;
|
||||||
updateGeneratedUrl();
|
updateGeneratedUrl();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate preview URL
|
// 生成预览 URL
|
||||||
const updateGeneratedUrl = () => {
|
const updateGeneratedUrl = () => {
|
||||||
const baseUrl = window.location.origin;
|
const baseUrl = window.location.origin;
|
||||||
const configStr = encodeConfig({
|
const configStr = encodeConfig({
|
||||||
@ -155,16 +155,16 @@ const updateGeneratedUrl = () => {
|
|||||||
generatedUrl.value = `${baseUrl}/preview?data=${configStr}`;
|
generatedUrl.value = `${baseUrl}/preview?data=${configStr}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Copy URL to clipboard
|
// 复制 URL 到剪贴板
|
||||||
const copyUrl = () => {
|
const copyUrl = () => {
|
||||||
navigator.clipboard.writeText(generatedUrl.value).then(() => {
|
navigator.clipboard.writeText(generatedUrl.value).then(() => {
|
||||||
ElMessage.success('URL copied to clipboard!');
|
ElMessage.success('URL 已复制到剪贴板!');
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
ElMessage.error('Failed to copy URL');
|
ElMessage.error('复制 URL 失败');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check for query params on load (for direct linking)
|
// 加载时检查查询参数(用于直接链接)
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const queryParams = new URLSearchParams(window.location.search);
|
const queryParams = new URLSearchParams(window.location.search);
|
||||||
const data = queryParams.get('data');
|
const data = queryParams.get('data');
|
||||||
@ -175,15 +175,15 @@ onMounted(() => {
|
|||||||
selectedWidget.value = decodedData.type;
|
selectedWidget.value = decodedData.type;
|
||||||
currentWidgetConfig.value = decodedData.config;
|
currentWidgetConfig.value = decodedData.config;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ElMessage.error('Invalid configuration in URL');
|
ElMessage.error('URL 中的配置无效');
|
||||||
handleWidgetChange(); // Load default config
|
handleWidgetChange(); // 加载默认配置
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handleWidgetChange(); // Load default config
|
handleWidgetChange(); // 加载默认配置
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update URL when configuration changes
|
// 配置变更时更新 URL
|
||||||
watch([selectedWidget, currentWidgetConfig], () => {
|
watch([selectedWidget, currentWidgetConfig], () => {
|
||||||
updateGeneratedUrl();
|
updateGeneratedUrl();
|
||||||
}, { deep: true });
|
}, { deep: true });
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
<div class="home-view">
|
<div class="home-view">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1>OBS Overlay Widget</h1>
|
<h1>OBS 悬浮小组件</h1>
|
||||||
<p>Create customizable widgets for OBS Studio streaming and recording</p>
|
<p>为 OBS Studio 直播和录制场景创建可定制化小组件</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="cards">
|
<div class="cards">
|
||||||
@ -11,9 +11,9 @@
|
|||||||
<div class="card-icon">
|
<div class="card-icon">
|
||||||
<el-icon><Setting /></el-icon>
|
<el-icon><Setting /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-title">Configure Widgets</div>
|
<div class="card-title">配置小组件</div>
|
||||||
<div class="card-description">
|
<div class="card-description">
|
||||||
Design and customize widgets for your OBS streams with an interactive interface
|
通过交互式界面设计和自定义 OBS 直播小组件
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -21,53 +21,53 @@
|
|||||||
<div class="card-icon">
|
<div class="card-icon">
|
||||||
<el-icon><Document /></el-icon>
|
<el-icon><Document /></el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-title">Documentation</div>
|
<div class="card-title">使用文档</div>
|
||||||
<div class="card-description">
|
<div class="card-description">
|
||||||
Learn how to use and integrate OBS Overlay Widgets into your streams
|
了解如何使用和集成 OBS 悬浮小组件到您的直播中
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="features">
|
<div class="features">
|
||||||
<h2>Available Widgets</h2>
|
<h2>可用小组件</h2>
|
||||||
|
|
||||||
<div class="widget-list">
|
<div class="widget-list">
|
||||||
<div class="widget-item">
|
<div class="widget-item">
|
||||||
<div class="widget-icon">⏰</div>
|
<div class="widget-icon">⏰</div>
|
||||||
<div class="widget-info">
|
<div class="widget-info">
|
||||||
<h3>Clock Widget</h3>
|
<h3>时钟小组件</h3>
|
||||||
<p>Display current time with customizable format, style, and effects</p>
|
<p>显示当前时间,可自定义格式、样式和特效</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="widget-item">
|
<div class="widget-item">
|
||||||
<div class="widget-icon">📅</div>
|
<div class="widget-icon">📅</div>
|
||||||
<div class="widget-info">
|
<div class="widget-info">
|
||||||
<h3>Date Widget</h3>
|
<h3>日期小组件</h3>
|
||||||
<p>Show current date with customizable format, style, and effects</p>
|
<p>显示当前日期,可自定义格式、样式和特效</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="widget-item">
|
<div class="widget-item">
|
||||||
<div class="widget-icon">📝</div>
|
<div class="widget-icon">📝</div>
|
||||||
<div class="widget-info">
|
<div class="widget-info">
|
||||||
<h3>Text Widget</h3>
|
<h3>文本小组件</h3>
|
||||||
<p>Display text with customizable styles including gradients, shadows, and fonts</p>
|
<p>显示文本,支持渐变、阴影、字体等自定义样式</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="widget-item">
|
<div class="widget-item">
|
||||||
<div class="widget-icon">🖼️</div>
|
<div class="widget-icon">🖼️</div>
|
||||||
<div class="widget-info">
|
<div class="widget-info">
|
||||||
<h3>Image Widget</h3>
|
<h3>图片小组件</h3>
|
||||||
<p>Show images with customizable size, effects, and positioning</p>
|
<p>显示图片,可自定义大小、特效和位置</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<p>OBS Overlay Widget © 2025</p>
|
<p>OBS 悬浮小组件 © 2025</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -84,7 +84,7 @@ const goToConfig = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const goToDoc = () => {
|
const goToDoc = () => {
|
||||||
// This would go to documentation in a real app
|
// 在实际应用中,这里会跳转到文档页面
|
||||||
window.open('https://github.com/yourusername/obs-overlay-widget', '_blank');
|
window.open('https://github.com/yourusername/obs-overlay-widget', '_blank');
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -12,13 +12,13 @@
|
|||||||
import { ref, onMounted, computed } from 'vue';
|
import { ref, onMounted, computed } from 'vue';
|
||||||
import { decodeConfig } from '../utils/configUtils';
|
import { decodeConfig } from '../utils/configUtils';
|
||||||
|
|
||||||
// Import widget components
|
// 导入小组件组件
|
||||||
import ClockWidget from '../widgets/ClockWidget.vue';
|
import ClockWidget from '../widgets/ClockWidget.vue';
|
||||||
import DateWidget from '../widgets/DateWidget.vue';
|
import DateWidget from '../widgets/DateWidget.vue';
|
||||||
import TextWidget from '../widgets/TextWidget.vue';
|
import TextWidget from '../widgets/TextWidget.vue';
|
||||||
import ImageWidget from '../widgets/ImageWidget.vue';
|
import ImageWidget from '../widgets/ImageWidget.vue';
|
||||||
|
|
||||||
// Widget registry
|
// 小组件注册表
|
||||||
const widgetRegistry = {
|
const widgetRegistry = {
|
||||||
'clock': ClockWidget,
|
'clock': ClockWidget,
|
||||||
'date': DateWidget,
|
'date': DateWidget,
|
||||||
@ -42,7 +42,7 @@ onMounted(() => {
|
|||||||
widgetType.value = decodedData.type;
|
widgetType.value = decodedData.type;
|
||||||
widgetConfig.value = decodedData.config;
|
widgetConfig.value = decodedData.config;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Invalid configuration in URL', e);
|
console.error('URL 中的配置无效', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="clock-widget" :style="clockStyle">
|
<div class="clock-widget" :style="clockStyle">
|
||||||
{{ currentTime }}
|
<div>{{ currentTime }}</div>
|
||||||
|
<div v-if="props.config.showDate" :style="clockStyle">{{ currentDate }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -21,6 +22,8 @@ interface ClockConfig {
|
|||||||
useGradient: boolean;
|
useGradient: boolean;
|
||||||
gradientColors: string[];
|
gradientColors: string[];
|
||||||
showSeconds: boolean;
|
showSeconds: boolean;
|
||||||
|
showDate: boolean;
|
||||||
|
dateFormat: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define props with default values
|
// Define props with default values
|
||||||
@ -38,18 +41,27 @@ const props = withDefaults(defineProps<{
|
|||||||
shadowBlur: 4,
|
shadowBlur: 4,
|
||||||
useGradient: false,
|
useGradient: false,
|
||||||
gradientColors: ['#ff0000', '#0000ff'],
|
gradientColors: ['#ff0000', '#0000ff'],
|
||||||
showSeconds: true
|
showSeconds: true,
|
||||||
|
showDate: false,
|
||||||
|
dateFormat: 'YYYY-MM-DD'
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
// State for current time
|
// State for current time and date
|
||||||
const currentTime = ref('');
|
const currentTime = ref('');
|
||||||
|
const currentDate = ref('');
|
||||||
|
|
||||||
// Update time string based on format
|
// Update time string based on format
|
||||||
const updateTime = () => {
|
const updateTime = () => {
|
||||||
const currentFormat = props.config.format || 'HH:mm:ss';
|
const currentFormat = props.config.format || 'HH:mm:ss';
|
||||||
const format = props.config.showSeconds ? currentFormat : currentFormat.replace(':ss', '');
|
const format = props.config.showSeconds ? currentFormat : currentFormat.replace(':ss', '');
|
||||||
currentTime.value = dayjs().format(format);
|
currentTime.value = dayjs().format(format);
|
||||||
|
|
||||||
|
// Update date if enabled
|
||||||
|
if (props.config.showDate) {
|
||||||
|
const dateFormat = props.config.dateFormat || 'YYYY-MM-DD';
|
||||||
|
currentDate.value = dayjs().format(dateFormat);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Interval for updating time
|
// Interval for updating time
|
||||||
@ -71,7 +83,7 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update interval if showSeconds changes
|
// Watch for showSeconds changes
|
||||||
watch(() => props.config.showSeconds, (newValue) => {
|
watch(() => props.config.showSeconds, (newValue) => {
|
||||||
if (timeInterval !== null) {
|
if (timeInterval !== null) {
|
||||||
window.clearInterval(timeInterval);
|
window.clearInterval(timeInterval);
|
||||||
@ -82,6 +94,11 @@ watch(() => props.config.showSeconds, (newValue) => {
|
|||||||
updateTime();
|
updateTime();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Watch for showDate or dateFormat changes
|
||||||
|
watch([() => props.config.showDate, () => props.config.dateFormat], () => {
|
||||||
|
updateTime();
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
// Computed styles for the clock
|
// Computed styles for the clock
|
||||||
const clockStyle = computed(() => {
|
const clockStyle = computed(() => {
|
||||||
const style: Record<string, string> = {
|
const style: Record<string, string> = {
|
||||||
@ -116,5 +133,6 @@ const clockStyle = computed(() => {
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user