@phill-component/icons 1.0.7 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,3 @@
1
- export { default as IconAttachment } from './Attachment.vue';
2
1
  export { default as IconBrush } from './Brush.vue';
3
2
  export { default as IconCalendar } from './Calendar.vue';
4
3
  export { default as IconCopy } from './Copy.vue';
@@ -12,7 +11,6 @@ export { default as IconHome } from './Home.vue';
12
11
  export { default as IconObliqueLine } from './ObliqueLine.vue';
13
12
  export { default as IconOriginalSize } from './OriginalSize.vue';
14
13
  export { default as IconSetting } from './Setting.vue';
15
- export { default as IconSort } from './Sort.vue';
16
14
  export { default as IconTask } from './Task.vue';
17
15
  export { default as IconToLandscape } from './ToLandscape.vue';
18
16
  export { default as IconZoomIn } from './ZoomIn.vue';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phill-component/icons",
3
- "version": "1.0.7",
3
+ "version": "1.10.1",
4
4
  "description": "Unified icons for phillUI mobile and pc libraries",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -14,7 +14,10 @@
14
14
  },
15
15
  "scripts": {
16
16
  "build": "node scripts/build.js",
17
- "release": "node scripts/publish.js"
17
+ "fetch": "node scripts/fetch.js",
18
+ "sync": "node scripts/sync.js",
19
+ "release": "node scripts/publish.js",
20
+ "jenkins": "node scripts/jenkins-server.js"
18
21
  },
19
22
  "keywords": [
20
23
  "icons",
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * fetch.js - 生成 icons manifest 并输出到 stdout
4
+ *
5
+ * 用途:B 服务器运行此脚本,生成当前 SVG 目录的 manifest
6
+ * A 服务器通过 HTTP 请求获取此 manifest,用于比较差异
7
+ *
8
+ * 输出格式:
9
+ * {
10
+ * "icons": {
11
+ * "home": "sha256:abc123...",
12
+ * "edit": "sha256:def456..."
13
+ * }
14
+ * }
15
+ */
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const crypto = require('crypto');
19
+
20
+ function getSvgHash(filePath) {
21
+ const content = fs.readFileSync(filePath);
22
+ return crypto.createHash('sha256').update(content).digest('hex');
23
+ }
24
+
25
+ function main() {
26
+ const pkgDir = process.cwd();
27
+ const svgDir = path.join(pkgDir, 'svg');
28
+
29
+ if (!fs.existsSync(svgDir)) {
30
+ console.error('[fetch-icons] 未找到 svg 目录。');
31
+ process.exit(1);
32
+ }
33
+
34
+ const files = fs.readdirSync(svgDir).filter(f => f.endsWith('.svg'));
35
+ const manifest = { icons: {} };
36
+
37
+ for (const file of files) {
38
+ const name = file.replace('.svg', '');
39
+ const hash = getSvgHash(path.join(svgDir, file));
40
+ manifest.icons[name] = `sha256:${hash}`;
41
+ }
42
+
43
+ // 输出 JSON 到 stdout
44
+ console.log(JSON.stringify(manifest, null, 2));
45
+ }
46
+
47
+ main();
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * jenkins-server.js - 模拟 Jenkins 服务器
4
+ *
5
+ * 用途:接收 A 服务器 (Icon Portal) 的请求,执行 sync 和 release 脚本
6
+ *
7
+ * 环境变量:
8
+ * - PORT - 服务器端口 (默认 3001)
9
+ */
10
+ const http = require('http');
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const cp = require('child_process');
14
+
15
+ const PORT = process.env.PORT || 3001;
16
+
17
+ // 临时目录用于存储接收到的数据
18
+ const tempDir = path.join(__dirname, '..', '.temp');
19
+ if (!fs.existsSync(tempDir)) {
20
+ fs.mkdirSync(tempDir, { recursive: true });
21
+ }
22
+
23
+ function parseBody(req) {
24
+ return new Promise((resolve, reject) => {
25
+ let body = '';
26
+ req.on('data', chunk => { body += chunk; });
27
+ req.on('end', () => {
28
+ try {
29
+ resolve(JSON.parse(body));
30
+ } catch {
31
+ reject(new Error('Invalid JSON'));
32
+ }
33
+ });
34
+ req.on('error', reject);
35
+ });
36
+ }
37
+
38
+ function execScript(script, args = [], env = {}) {
39
+ return new Promise((resolve, reject) => {
40
+ const pkgDir = path.join(__dirname, '..');
41
+ const child = cp.spawn('node', [path.join(__dirname, script), ...args], {
42
+ cwd: pkgDir,
43
+ stdio: ['pipe', 'pipe', 'pipe'],
44
+ env: { ...process.env, ...env }
45
+ });
46
+
47
+ let stdout = '';
48
+ let stderr = '';
49
+
50
+ child.stdout.on('data', data => { stdout += data; });
51
+ child.stderr.on('data', data => { stderr += data; });
52
+
53
+ child.on('close', code => {
54
+ if (code === 0) {
55
+ resolve({ stdout, stderr });
56
+ } else {
57
+ reject(new Error(`Script ${script} exited with code ${code}: ${stderr}`));
58
+ }
59
+ });
60
+
61
+ child.on('error', reject);
62
+ });
63
+ }
64
+
65
+ const server = http.createServer(async (req, res) => {
66
+ const url = new URL(req.url, `http://localhost:${PORT}`);
67
+
68
+ // CORS headers
69
+ res.setHeader('Access-Control-Allow-Origin', '*');
70
+ res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
71
+ res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
72
+
73
+ if (req.method === 'OPTIONS') {
74
+ res.writeHead(204);
75
+ res.end();
76
+ return;
77
+ }
78
+
79
+ try {
80
+ // GET /health - 健康检查
81
+ if (req.method === 'GET' && url.pathname === '/health') {
82
+ res.writeHead(200, { 'Content-Type': 'application/json' });
83
+ res.end(JSON.stringify({ status: 'ok' }));
84
+ return;
85
+ }
86
+
87
+ // GET /manifest - 获取当前 manifest (对应 fetch.js)
88
+ if (req.method === 'GET' && url.pathname === '/manifest') {
89
+ console.log('[Jenkins] Fetching current manifest...');
90
+ const result = await execScript('fetch.js');
91
+ res.writeHead(200, { 'Content-Type': 'application/json' });
92
+ res.end(result.stdout);
93
+ return;
94
+ }
95
+
96
+ // GET /svg/:name - 获取 SVG 文件内容
97
+ if (req.method === 'GET' && url.pathname.startsWith('/svg/')) {
98
+ const name = url.pathname.replace('/svg/', '').replace('.svg', '');
99
+ const svgPath = path.join(__dirname, '..', 'svg', `${name}.svg`);
100
+ if (fs.existsSync(svgPath)) {
101
+ res.writeHead(200, { 'Content-Type': 'image/svg+xml' });
102
+ res.end(fs.readFileSync(svgPath, 'utf-8'));
103
+ } else {
104
+ res.writeHead(404, { 'Content-Type': 'application/json' });
105
+ res.end(JSON.stringify({ error: 'SVG not found' }));
106
+ }
107
+ return;
108
+ }
109
+
110
+ // POST /sync - 接收 added/modified/deleted 数据并执行同步
111
+ if (req.method === 'POST' && url.pathname === '/sync') {
112
+ const body = await parseBody(req);
113
+ const { added, modified, deleted, version } = body;
114
+
115
+ // 保存数据到临时文件
116
+ const dataPath = path.join(tempDir, 'sync-data.json');
117
+ fs.writeFileSync(dataPath, JSON.stringify({ added, modified, deleted }, null, 2));
118
+
119
+ console.log(`[Jenkins] Received sync request:`);
120
+ console.log(` Added: ${Object.keys(added || {}).length} icons`);
121
+ console.log(` Modified: ${Object.keys(modified || {}).length} icons`);
122
+ console.log(` Deleted: ${(deleted || []).length} icons`);
123
+ console.log(` Version: ${version || 'not specified'}`);
124
+
125
+ // 执行 sync 脚本
126
+ const syncArgs = ['--data', dataPath];
127
+ if (version) {
128
+ syncArgs.push('--version', version);
129
+ }
130
+
131
+ console.log(`[Jenkins] Running sync.js ${syncArgs.join(' ')}`);
132
+ const syncResult = await execScript('sync.js', syncArgs);
133
+ console.log('[Jenkins] Sync output:', syncResult.stdout);
134
+
135
+ // 解析 sync 输出,查找 changed 字段
136
+ let syncOutput;
137
+ try {
138
+ // 查找 JSON 输出行
139
+ const lines = syncResult.stdout.trim().split('\n');
140
+ const jsonLine = lines.find(line => line.startsWith('{'));
141
+ if (jsonLine) {
142
+ syncOutput = JSON.parse(jsonLine);
143
+ }
144
+ } catch (e) {
145
+ console.log('[Jenkins] Failed to parse sync output:', e.message);
146
+ }
147
+
148
+ const hasChanges = syncOutput?.changed !== false;
149
+
150
+ if (!hasChanges) {
151
+ console.log('[Jenkins] No changes detected, skipping release.');
152
+ res.writeHead(200, { 'Content-Type': 'application/json' });
153
+ res.end(JSON.stringify({
154
+ success: true,
155
+ changed: false,
156
+ message: 'No changes detected'
157
+ }));
158
+ return;
159
+ }
160
+
161
+ console.log('[Jenkins] Changes detected, running release...');
162
+
163
+ // 如果指定了版本,执行 release
164
+ if (version) {
165
+ console.log(`[Jenkins] Running release for version ${version}`);
166
+ const releaseResult = await execScript('publish.js', [], { PHILLUI_PUBLISH: '1' });
167
+ console.log('[Jenkins] Release completed:', releaseResult.stdout);
168
+ }
169
+
170
+ res.writeHead(200, { 'Content-Type': 'application/json' });
171
+ res.end(JSON.stringify({
172
+ success: true,
173
+ changed: true,
174
+ version: version || null,
175
+ message: 'Sync and release completed',
176
+ syncOutput
177
+ }));
178
+ return;
179
+ }
180
+
181
+ // 404
182
+ res.writeHead(404, { 'Content-Type': 'application/json' });
183
+ res.end(JSON.stringify({ error: 'Not found' }));
184
+ } catch (err) {
185
+ console.error('[Jenkins] Error:', err.message);
186
+ res.writeHead(500, { 'Content-Type': 'application/json' });
187
+ res.end(JSON.stringify({ error: err.message }));
188
+ }
189
+ });
190
+
191
+ server.listen(PORT, () => {
192
+ console.log(`[Jenkins] Mock server running on http://localhost:${PORT}`);
193
+ console.log(`[Jenkins] Available endpoints:`);
194
+ console.log(` GET /health - Health check`);
195
+ console.log(` GET /manifest - Get current manifest (fetch.js)`);
196
+ console.log(` GET /svg/:name - Get SVG file content`);
197
+ console.log(` POST /sync - Sync icons and release (sync.js + publish.js)`);
198
+ });
@@ -128,6 +128,16 @@ function main() {
128
128
  console.log(`[publish-icons] 执行:npm publish --access public --userconfig ${userconfig}`);
129
129
  exec('npm', ['publish', '--access', 'public', '--userconfig', userconfig], { env });
130
130
  console.log(`[publish-icons] ${iconsPkg.name}@${iconsPkg.version} 发布成功!`);
131
+
132
+ // Push version bump and tag to git
133
+ console.log('[publish-icons] 推送版本到 Git...');
134
+ try {
135
+ exec('git', ['push', 'origin', 'HEAD']);
136
+ exec('git', ['push', '--tags']);
137
+ console.log('[publish-icons] Git 推送完成!');
138
+ } catch (e) {
139
+ console.warn('[publish-icons] Git 推送失败(不影响发布):', e.message);
140
+ }
131
141
  } catch (e) {
132
142
  console.error('[publish-icons] 发布失败:', e.message);
133
143
  if (e.stdout) console.error('STDOUT:', e.stdout.toString());
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * sync.js - 接收 added/modified/deleted 数据,执行 git 操作
4
+ *
5
+ * 用法:node scripts/sync.js --data <path-to-data.json> [--version <version>]
6
+ *
7
+ * 输入格式 (data.json):
8
+ * {
9
+ * "added": { "newIcon": { "hash": "sha256:xxx", "content": "<svg>...</svg>" } },
10
+ * "modified": { "changedIcon": { "hash": "sha256:yyy", "content": "<svg>...</svg>" } },
11
+ * "deleted": ["oldIcon"]
12
+ * }
13
+ *
14
+ * 输出: JSON 到 stdout
15
+ * { "changed": true/false, "added": [...], "modified": [...], "deleted": [...] }
16
+ */
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+ const cp = require('child_process');
20
+
21
+ function exec(command, args, options = {}) {
22
+ const res = cp.spawnSync(command, args, { encoding: 'utf8', ...options });
23
+ if (res.status !== 0) {
24
+ const err = new Error(res.stderr || res.stdout || `${command} failed`);
25
+ err.stdout = res.stdout;
26
+ err.stderr = res.stderr;
27
+ err.status = res.status;
28
+ throw err;
29
+ }
30
+ return res.stdout || '';
31
+ }
32
+
33
+ function parseArgs() {
34
+ const args = process.argv.slice(2);
35
+ const result = {};
36
+ for (let i = 0; i < args.length; i++) {
37
+ if (args[i] === '--data' && args[i + 1]) {
38
+ result.data = args[i + 1];
39
+ i++;
40
+ } else if (args[i] === '--version' && args[i + 1]) {
41
+ result.version = args[i + 1];
42
+ i++;
43
+ }
44
+ }
45
+ return result;
46
+ }
47
+
48
+ function main() {
49
+ const options = parseArgs();
50
+
51
+ if (!options.data) {
52
+ console.error('[sync-icons] 请提供 --data 参数');
53
+ process.exit(1);
54
+ }
55
+
56
+ // 读取数据
57
+ let data;
58
+ try {
59
+ data = JSON.parse(fs.readFileSync(options.data, 'utf8'));
60
+ } catch (e) {
61
+ console.error('[sync-icons] 无法读取 data 文件:', e.message);
62
+ process.exit(1);
63
+ }
64
+
65
+ const added = data.added || {};
66
+ const modified = data.modified || {};
67
+ const deleted = data.deleted || [];
68
+
69
+ const pkgDir = process.cwd();
70
+ const svgDir = path.join(pkgDir, 'svg');
71
+
72
+ if (!fs.existsSync(svgDir)) {
73
+ fs.mkdirSync(svgDir, { recursive: true });
74
+ }
75
+
76
+ // 检查 .git 目录
77
+ const gitDir = path.join(pkgDir, '..', '..', '.git');
78
+ if (!fs.existsSync(gitDir)) {
79
+ // 没有 git,直接保存文件
80
+ console.log('[sync-icons] 未找到 .git 目录,仅保存文件。');
81
+
82
+ // 保存新增的图标
83
+ for (const [name, info] of Object.entries(added)) {
84
+ const filePath = path.join(svgDir, `${name}.svg`);
85
+ fs.writeFileSync(filePath, info.content, 'utf-8');
86
+ console.log(`[sync-icons] 新增: ${name}.svg`);
87
+ }
88
+
89
+ // 保存修改的图标
90
+ for (const [name, info] of Object.entries(modified)) {
91
+ const filePath = path.join(svgDir, `${name}.svg`);
92
+ fs.writeFileSync(filePath, info.content, 'utf-8');
93
+ console.log(`[sync-icons] 修改: ${name}.svg`);
94
+ }
95
+
96
+ // 删除图标
97
+ for (const name of deleted) {
98
+ const filePath = path.join(svgDir, `${name}.svg`);
99
+ if (fs.existsSync(filePath)) {
100
+ fs.unlinkSync(filePath);
101
+ console.log(`[sync-icons] 删除: ${name}.svg`);
102
+ }
103
+ }
104
+
105
+ const hasChanges = Object.keys(added).length > 0 || Object.keys(modified).length > 0 || deleted.length > 0;
106
+ console.log(JSON.stringify({ changed: hasChanges, added: Object.keys(added), modified: Object.keys(modified), deleted }));
107
+ return;
108
+ }
109
+
110
+ // 有 git,执行正常流程
111
+ const hasChanges = Object.keys(added).length > 0 || Object.keys(modified).length > 0 || deleted.length > 0;
112
+
113
+ if (!hasChanges) {
114
+ console.log('[sync-icons] 没有需要同步的更改。');
115
+ console.log(JSON.stringify({ changed: false, added: [], modified: [], deleted: [] }));
116
+ return;
117
+ }
118
+
119
+ // Step 1: 拉取最新代码,确保本地是最新的
120
+ console.log('[sync-icons] 拉取最新代码...');
121
+ try {
122
+ exec('git', ['pull', 'origin', 'HEAD']);
123
+ console.log('[sync-icons] 代码拉取成功。');
124
+ } catch (e) {
125
+ console.warn('[sync-icons] 代码拉取失败,继续执行:', e.message);
126
+ }
127
+
128
+ // Step 2: 重置暂存区,清除之前的缓存
129
+ console.log('[sync-icons] 重置暂存区...');
130
+ try {
131
+ exec('git', ['reset', 'HEAD', '--', path.join(svgDir, '*.svg')]);
132
+ } catch (e) {
133
+ console.warn('[sync-icons] reset 失败,继续执行:', e.message);
134
+ }
135
+
136
+ // Step 3: 保存新增的图标
137
+ for (const [name, info] of Object.entries(added)) {
138
+ const filePath = path.join(svgDir, `${name}.svg`);
139
+ fs.writeFileSync(filePath, info.content, 'utf-8');
140
+ console.log(`[sync-icons] 新增: ${name}.svg`);
141
+ }
142
+
143
+ // Step 4: 保存修改的图标
144
+ for (const [name, info] of Object.entries(modified)) {
145
+ const filePath = path.join(svgDir, `${name}.svg`);
146
+ fs.writeFileSync(filePath, info.content, 'utf-8');
147
+ console.log(`[sync-icons] 修改: ${name}.svg`);
148
+ }
149
+
150
+ // Step 5: 删除图标
151
+ for (const name of deleted) {
152
+ const filePath = path.join(svgDir, `${name}.svg`);
153
+ if (fs.existsSync(filePath)) {
154
+ fs.unlinkSync(filePath);
155
+ console.log(`[sync-icons] 删除: ${name}.svg`);
156
+ }
157
+ }
158
+
159
+ // Step 6: 添加所有 SVG 文件变更到 git(使用 -A 确保包括删除)
160
+ console.log('[sync-icons] 添加 SVG 文件变更到 git...');
161
+ exec('git', ['add', '-A', '--', svgDir]);
162
+
163
+ // Step 7: 检查是否有变更
164
+ const status = exec('git', ['status', '--porcelain', '--', svgDir]).trim();
165
+ if (!status) {
166
+ console.log('[sync-icons] Git 没有检测到变更。');
167
+ console.log(JSON.stringify({ changed: false, added: [], modified: [], deleted: [] }));
168
+ return;
169
+ }
170
+
171
+ // Step 8: 提交
172
+ const totalCount = Object.keys(added).length + Object.keys(modified).length + deleted.length;
173
+ const message = `chore(icons): sync ${totalCount} icons via sync script`;
174
+ console.log(`[sync-icons] 提交: ${message}`);
175
+ exec('git', ['commit', '-m', message, '--author', 'Icons Sync <noreply@example.com>']);
176
+
177
+ // Step 9: 推送
178
+ console.log('[sync-icons] 推送到远端...');
179
+ exec('git', ['push', 'origin', 'HEAD']);
180
+
181
+ // Step 10: 如果提供了版本号,更新 package.json
182
+ if (options.version) {
183
+ const pkgPath = path.join(pkgDir, 'package.json');
184
+ if (fs.existsSync(pkgPath)) {
185
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
186
+ pkg.version = options.version;
187
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
188
+ console.log(`[sync-icons] 更新版本号到 ${options.version}`);
189
+
190
+ // 提交版本变更
191
+ exec('git', ['add', pkgPath]);
192
+ exec('git', ['commit', '-m', `chore(release): bump version to ${options.version}`]);
193
+ exec('git', ['push', 'origin', 'HEAD']);
194
+ }
195
+ }
196
+
197
+ console.log('[sync-icons] 同步完成!');
198
+ console.log(JSON.stringify({ changed: true, added: Object.keys(added), modified: Object.keys(modified), deleted }));
199
+ }
200
+
201
+ main();
@@ -1,75 +0,0 @@
1
- <template>
2
- <view class="icon" @tap="onTap" :hover-class="hoverClass" :style="rootStyle">
3
- <!-- #ifdef H5 -->
4
- <svg v-bind="$attrs" :style="iconStyle" :width="iconW" :height="iconH" fill="none" viewBox="0 0 48 48"><path stroke="currentColor" stroke-width="2" d="M29.037 15.236s-9.174 9.267-11.48 11.594c-2.305 2.327-1.646 4.987-.329 6.316 1.317 1.33 3.994 1.953 6.258-.332L37.32 18.851c3.623-3.657 2.092-8.492 0-10.639s-6.916-3.657-10.54 0L11.3 23.838c-3.623 3.657-3.953 10.638.329 14.96s11.115 4.105 14.821.333 8.74-8.822 11.224-11.33"/></svg>
5
- <!-- #endif -->
6
- <!-- #ifndef H5 -->
7
- <image :src="imgSrc" :style="iconBoxStyle" />
8
- <!-- #endif -->
9
- <text v-if="label != ''" class="icon__label" :style="labelStyle">{{ label }}</text>
10
- </view>
11
- </template>
12
- <script setup lang="uts">
13
- import { computed } from 'vue'
14
- import imgSrc from '@/uni_modules/@phill-component/icons/mobile/uvue/icon-attachment/attachment.png'
15
- const props = defineProps({
16
- size: { type: [String, Number], default: '1em' },
17
- color: { type: String, default: 'var(--tsm-color-primary)' },
18
- label: { type: [String, Number], default: '' },
19
- labelPos: { type: String, default: 'right' },
20
- labelSize: { type: [String, Number], default: '15px' },
21
- labelColor: { type: String, default: '' },
22
- space: { type: [String, Number], default: '3px' },
23
- width: { type: [String, Number], default: '' },
24
- height: { type: [String, Number], default: '' },
25
- hoverClass: { type: String, default: '' },
26
- index: { type: [String, Number], default: '' },
27
- stop: { type: Boolean, default: false }
28
- })
29
- const emit = defineEmits(['click'])
30
- function toPx(v: any): string {
31
- if (typeof v === 'number') return (v as number).toString() + 'px'
32
- const s = (v as string)
33
- return s != '' ? s : ''
34
- }
35
- const iconW = computed((): string => (props.width != '' ? toPx(props.width) : toPx(props.size)))
36
- const iconH = computed((): string => (props.height != '' ? toPx(props.height) : toPx(props.size)))
37
- const iconStyle = computed((): UTSJSONObject => {
38
- return { 'color': props.color != '' ? props.color : 'inherit' } as UTSJSONObject
39
- })
40
- const iconBoxStyle = computed((): UTSJSONObject => ({ width: iconW.value, height: iconH.value } as UTSJSONObject))
41
- const wrapStyle = computed((): UTSJSONObject => {
42
- const map = { right: 'row', left: 'row-reverse', top: 'column-reverse', bottom: 'column' } as UTSJSONObject
43
- let dir: string = 'row'
44
- const cand = map[props.labelPos] as string | null
45
- if (cand != null && cand.length > 0) {
46
- dir = cand
47
- }
48
- return { display: 'flex', alignItems: 'center', flexDirection: dir } as UTSJSONObject
49
- })
50
- const rootStyle = computed((): UTSJSONObject => {
51
- const s = wrapStyle.value
52
- const i = iconStyle.value
53
- for (const key in i) {
54
- s[key] = i[key]
55
- }
56
- return s
57
- })
58
- const labelStyle = computed((): UTSJSONObject => {
59
- const out = {} as UTSJSONObject
60
- if (props.labelColor != '') out['color'] = props.labelColor
61
- out['fontSize'] = toPx(props.labelSize)
62
- out['marginLeft'] = props.labelPos == 'right' ? toPx(props.space) : 0
63
- out['marginTop'] = props.labelPos == 'bottom' ? toPx(props.space) : 0
64
- out['marginRight'] = props.labelPos == 'left' ? toPx(props.space) : 0
65
- out['marginBottom'] = props.labelPos == 'top' ? toPx(props.space) : 0
66
- return out
67
- })
68
- function onTap(e: UniPointerEvent) {
69
- emit('click', props.index)
70
- if (props.stop) e.stopPropagation()
71
- }
72
- </script>
73
- <style scoped>
74
- .icon__label { line-height: 1; }
75
- </style>
@@ -1,75 +0,0 @@
1
- <template>
2
- <view class="icon" @tap="onTap" :hover-class="hoverClass" :style="rootStyle">
3
- <!-- #ifdef H5 -->
4
- <svg v-bind="$attrs" :style="iconStyle" :width="iconW" :height="iconH" fill="none" viewBox="0 0 48 48"><path stroke="currentColor" stroke-width="2" d="M43 9H5m0 30h14m15.5-15H5"/></svg>
5
- <!-- #endif -->
6
- <!-- #ifndef H5 -->
7
- <image :src="imgSrc" :style="iconBoxStyle" />
8
- <!-- #endif -->
9
- <text v-if="label != ''" class="icon__label" :style="labelStyle">{{ label }}</text>
10
- </view>
11
- </template>
12
- <script setup lang="uts">
13
- import { computed } from 'vue'
14
- import imgSrc from '@/uni_modules/@phill-component/icons/mobile/uvue/icon-sort/sort.png'
15
- const props = defineProps({
16
- size: { type: [String, Number], default: '1em' },
17
- color: { type: String, default: 'var(--tsm-color-primary)' },
18
- label: { type: [String, Number], default: '' },
19
- labelPos: { type: String, default: 'right' },
20
- labelSize: { type: [String, Number], default: '15px' },
21
- labelColor: { type: String, default: '' },
22
- space: { type: [String, Number], default: '3px' },
23
- width: { type: [String, Number], default: '' },
24
- height: { type: [String, Number], default: '' },
25
- hoverClass: { type: String, default: '' },
26
- index: { type: [String, Number], default: '' },
27
- stop: { type: Boolean, default: false }
28
- })
29
- const emit = defineEmits(['click'])
30
- function toPx(v: any): string {
31
- if (typeof v === 'number') return (v as number).toString() + 'px'
32
- const s = (v as string)
33
- return s != '' ? s : ''
34
- }
35
- const iconW = computed((): string => (props.width != '' ? toPx(props.width) : toPx(props.size)))
36
- const iconH = computed((): string => (props.height != '' ? toPx(props.height) : toPx(props.size)))
37
- const iconStyle = computed((): UTSJSONObject => {
38
- return { 'color': props.color != '' ? props.color : 'inherit' } as UTSJSONObject
39
- })
40
- const iconBoxStyle = computed((): UTSJSONObject => ({ width: iconW.value, height: iconH.value } as UTSJSONObject))
41
- const wrapStyle = computed((): UTSJSONObject => {
42
- const map = { right: 'row', left: 'row-reverse', top: 'column-reverse', bottom: 'column' } as UTSJSONObject
43
- let dir: string = 'row'
44
- const cand = map[props.labelPos] as string | null
45
- if (cand != null && cand.length > 0) {
46
- dir = cand
47
- }
48
- return { display: 'flex', alignItems: 'center', flexDirection: dir } as UTSJSONObject
49
- })
50
- const rootStyle = computed((): UTSJSONObject => {
51
- const s = wrapStyle.value
52
- const i = iconStyle.value
53
- for (const key in i) {
54
- s[key] = i[key]
55
- }
56
- return s
57
- })
58
- const labelStyle = computed((): UTSJSONObject => {
59
- const out = {} as UTSJSONObject
60
- if (props.labelColor != '') out['color'] = props.labelColor
61
- out['fontSize'] = toPx(props.labelSize)
62
- out['marginLeft'] = props.labelPos == 'right' ? toPx(props.space) : 0
63
- out['marginTop'] = props.labelPos == 'bottom' ? toPx(props.space) : 0
64
- out['marginRight'] = props.labelPos == 'left' ? toPx(props.space) : 0
65
- out['marginBottom'] = props.labelPos == 'top' ? toPx(props.space) : 0
66
- return out
67
- })
68
- function onTap(e: UniPointerEvent) {
69
- emit('click', props.index)
70
- if (props.stop) e.stopPropagation()
71
- }
72
- </script>
73
- <style scoped>
74
- .icon__label { line-height: 1; }
75
- </style>
Binary file
@@ -1,58 +0,0 @@
1
- <template>
2
- <view class="icon" @tap="onTap" :hover-class="hoverClass" :style="[wrapStyle, iconStyle]">
3
- <!-- #ifdef H5 -->
4
- <svg v-bind="$attrs" :style="iconStyle" :width="iconW" :height="iconH" fill="none" viewBox="0 0 48 48"><path stroke="currentColor" stroke-width="2" d="M29.037 15.236s-9.174 9.267-11.48 11.594c-2.305 2.327-1.646 4.987-.329 6.316 1.317 1.33 3.994 1.953 6.258-.332L37.32 18.851c3.623-3.657 2.092-8.492 0-10.639s-6.916-3.657-10.54 0L11.3 23.838c-3.623 3.657-3.953 10.638.329 14.96s11.115 4.105 14.821.333 8.74-8.822 11.224-11.33"/></svg>
5
- <!-- #endif -->
6
- <!-- #ifndef H5 -->
7
- <image :src="imgSrc" :style="iconBoxStyle" />
8
- <!-- #endif -->
9
- <text v-if="label !== ''" class="icon__label" :style="labelStyle">{{ label }}</text>
10
- </view>
11
- </template>
12
- <script setup>
13
- import { computed } from 'vue'
14
- import imgSrc from '@/uni_modules/@phill-component/icons/mobile/uvue/icon-attachment/attachment.png'
15
- const props = defineProps({
16
- size: { type: [String, Number], default: '1em' },
17
- color: { type: String, default: 'var(--tsm-color-primary)' },
18
- label: { type: [String, Number], default: '' },
19
- labelPos: { type: String, default: 'right' },
20
- labelSize: { type: [String, Number], default: '15px' },
21
- labelColor: { type: String, default: '' },
22
- space: { type: [String, Number], default: '3px' },
23
- width: { type: [String, Number], default: '' },
24
- height: { type: [String, Number], default: '' },
25
- hoverClass: { type: String, default: '' },
26
- index: { type: [String, Number], default: '' },
27
- stop: { type: Boolean, default: false }
28
- })
29
- const emit = defineEmits(['click'])
30
- const toPx = (v) => typeof v === 'number' ? (v + 'px') : (String(v||''));
31
- const iconW = computed(() => props.width ? toPx(props.width) : toPx(props.size))
32
- const iconH = computed(() => props.height ? toPx(props.height) : toPx(props.size))
33
- const iconBoxStyle = computed(() => ({ width: iconW.value, height: iconH.value }))
34
- const iconStyle = computed(() => {
35
- return { color: props.color || 'inherit' }
36
- })
37
- const wrapStyle = computed(() => {
38
- const dirMap = { right: 'row', left: 'row-reverse', top: 'column-reverse', bottom: 'column' }
39
- return { display: 'flex', alignItems: 'center', flexDirection: dirMap[props.labelPos] || 'row' }
40
- })
41
- const labelStyle = computed(() => {
42
- return {
43
- color: props.labelColor || '',
44
- fontSize: toPx(props.labelSize),
45
- marginLeft: props.labelPos === 'right' ? toPx(props.space) : 0,
46
- marginTop: props.labelPos === 'bottom' ? toPx(props.space) : 0,
47
- marginRight: props.labelPos === 'left' ? toPx(props.space) : 0,
48
- marginBottom: props.labelPos === 'top' ? toPx(props.space) : 0
49
- }
50
- })
51
- function onTap(e) {
52
- emit('click', props.index)
53
- if (props.stop && e && e.stopPropagation) e.stopPropagation()
54
- }
55
- </script>
56
- <style scoped>
57
- .icon__label { line-height: 1; }
58
- </style>
@@ -1,58 +0,0 @@
1
- <template>
2
- <view class="icon" @tap="onTap" :hover-class="hoverClass" :style="[wrapStyle, iconStyle]">
3
- <!-- #ifdef H5 -->
4
- <svg v-bind="$attrs" :style="iconStyle" :width="iconW" :height="iconH" fill="none" viewBox="0 0 48 48"><path stroke="currentColor" stroke-width="2" d="M43 9H5m0 30h14m15.5-15H5"/></svg>
5
- <!-- #endif -->
6
- <!-- #ifndef H5 -->
7
- <image :src="imgSrc" :style="iconBoxStyle" />
8
- <!-- #endif -->
9
- <text v-if="label !== ''" class="icon__label" :style="labelStyle">{{ label }}</text>
10
- </view>
11
- </template>
12
- <script setup>
13
- import { computed } from 'vue'
14
- import imgSrc from '@/uni_modules/@phill-component/icons/mobile/uvue/icon-sort/sort.png'
15
- const props = defineProps({
16
- size: { type: [String, Number], default: '1em' },
17
- color: { type: String, default: 'var(--tsm-color-primary)' },
18
- label: { type: [String, Number], default: '' },
19
- labelPos: { type: String, default: 'right' },
20
- labelSize: { type: [String, Number], default: '15px' },
21
- labelColor: { type: String, default: '' },
22
- space: { type: [String, Number], default: '3px' },
23
- width: { type: [String, Number], default: '' },
24
- height: { type: [String, Number], default: '' },
25
- hoverClass: { type: String, default: '' },
26
- index: { type: [String, Number], default: '' },
27
- stop: { type: Boolean, default: false }
28
- })
29
- const emit = defineEmits(['click'])
30
- const toPx = (v) => typeof v === 'number' ? (v + 'px') : (String(v||''));
31
- const iconW = computed(() => props.width ? toPx(props.width) : toPx(props.size))
32
- const iconH = computed(() => props.height ? toPx(props.height) : toPx(props.size))
33
- const iconBoxStyle = computed(() => ({ width: iconW.value, height: iconH.value }))
34
- const iconStyle = computed(() => {
35
- return { color: props.color || 'inherit' }
36
- })
37
- const wrapStyle = computed(() => {
38
- const dirMap = { right: 'row', left: 'row-reverse', top: 'column-reverse', bottom: 'column' }
39
- return { display: 'flex', alignItems: 'center', flexDirection: dirMap[props.labelPos] || 'row' }
40
- })
41
- const labelStyle = computed(() => {
42
- return {
43
- color: props.labelColor || '',
44
- fontSize: toPx(props.labelSize),
45
- marginLeft: props.labelPos === 'right' ? toPx(props.space) : 0,
46
- marginTop: props.labelPos === 'bottom' ? toPx(props.space) : 0,
47
- marginRight: props.labelPos === 'left' ? toPx(props.space) : 0,
48
- marginBottom: props.labelPos === 'top' ? toPx(props.space) : 0
49
- }
50
- })
51
- function onTap(e) {
52
- emit('click', props.index)
53
- if (props.stop && e && e.stopPropagation) e.stopPropagation()
54
- }
55
- </script>
56
- <style scoped>
57
- .icon__label { line-height: 1; }
58
- </style>
@@ -1,53 +0,0 @@
1
- <template>
2
- <view class="icon" @tap="onTap" :hover-class="hoverClass" :style="[wrapStyle, iconStyle]">
3
- <svg v-bind="$attrs" :style="iconStyle" :width="iconW" :height="iconH" fill="none" viewBox="0 0 48 48"><path stroke="currentColor" stroke-width="2" d="M29.037 15.236s-9.174 9.267-11.48 11.594c-2.305 2.327-1.646 4.987-.329 6.316 1.317 1.33 3.994 1.953 6.258-.332L37.32 18.851c3.623-3.657 2.092-8.492 0-10.639s-6.916-3.657-10.54 0L11.3 23.838c-3.623 3.657-3.953 10.638.329 14.96s11.115 4.105 14.821.333 8.74-8.822 11.224-11.33"/></svg>
4
- <text v-if="label !== ''" class="icon__label" :style="labelStyle">{{ label }}</text>
5
- </view>
6
- </template>
7
- <script setup>
8
- import { computed } from 'vue'
9
- const props = defineProps({
10
- size: { type: [String, Number], default: '1em' },
11
- color: { type: String, default: 'inherit' },
12
- label: { type: [String, Number], default: '' },
13
- labelPos: { type: String, default: 'right' },
14
- labelSize: { type: [String, Number], default: '15px' },
15
- labelColor: { type: String, default: '' },
16
- space: { type: [String, Number], default: '3px' },
17
- width: { type: [String, Number], default: '' },
18
- height: { type: [String, Number], default: '' },
19
- hoverClass: { type: String, default: '' },
20
- index: { type: [String, Number], default: '' },
21
- stop: { type: Boolean, default: false }
22
- })
23
- const emit = defineEmits(['click'])
24
- const toPx = (v) => typeof v === 'number' ? (v + 'px') : (String(v||''));
25
- const iconW = computed(() => props.width ? toPx(props.width) : toPx(props.size))
26
- const iconH = computed(() => props.height ? toPx(props.height) : toPx(props.size))
27
- const iconBoxStyle = computed(() => ({ width: iconW.value, height: iconH.value }))
28
- const iconStyle = computed(() => {
29
- return { color: props.color || 'inherit' }
30
- })
31
- const wrapStyle = computed(() => {
32
- const dirMap = { right: 'row', left: 'row-reverse', top: 'column-reverse', bottom: 'column' }
33
- return { display: 'flex', alignItems: 'center', flexDirection: dirMap[props.labelPos] || 'row' }
34
- })
35
- const labelStyle = computed(() => {
36
- return {
37
- color: props.labelColor || '',
38
- fontSize: toPx(props.labelSize),
39
- marginLeft: props.labelPos === 'right' ? toPx(props.space) : 0,
40
- marginTop: props.labelPos === 'bottom' ? toPx(props.space) : 0,
41
- marginRight: props.labelPos === 'left' ? toPx(props.space) : 0,
42
- marginBottom: props.labelPos === 'top' ? toPx(props.space) : 0
43
- }
44
- })
45
- const imgSrc = '__IMG_SRC__'
46
- function onTap(e) {
47
- emit('click', props.index)
48
- if (props.stop && e && e.stopPropagation) e.stopPropagation()
49
- }
50
- </script>
51
- <style scoped>
52
- .icon__label { line-height: 1; }
53
- </style>
@@ -1,53 +0,0 @@
1
- <template>
2
- <view class="icon" @tap="onTap" :hover-class="hoverClass" :style="[wrapStyle, iconStyle]">
3
- <svg v-bind="$attrs" :style="iconStyle" :width="iconW" :height="iconH" fill="none" viewBox="0 0 48 48"><path stroke="currentColor" stroke-width="2" d="M43 9H5m0 30h14m15.5-15H5"/></svg>
4
- <text v-if="label !== ''" class="icon__label" :style="labelStyle">{{ label }}</text>
5
- </view>
6
- </template>
7
- <script setup>
8
- import { computed } from 'vue'
9
- const props = defineProps({
10
- size: { type: [String, Number], default: '1em' },
11
- color: { type: String, default: 'inherit' },
12
- label: { type: [String, Number], default: '' },
13
- labelPos: { type: String, default: 'right' },
14
- labelSize: { type: [String, Number], default: '15px' },
15
- labelColor: { type: String, default: '' },
16
- space: { type: [String, Number], default: '3px' },
17
- width: { type: [String, Number], default: '' },
18
- height: { type: [String, Number], default: '' },
19
- hoverClass: { type: String, default: '' },
20
- index: { type: [String, Number], default: '' },
21
- stop: { type: Boolean, default: false }
22
- })
23
- const emit = defineEmits(['click'])
24
- const toPx = (v) => typeof v === 'number' ? (v + 'px') : (String(v||''));
25
- const iconW = computed(() => props.width ? toPx(props.width) : toPx(props.size))
26
- const iconH = computed(() => props.height ? toPx(props.height) : toPx(props.size))
27
- const iconBoxStyle = computed(() => ({ width: iconW.value, height: iconH.value }))
28
- const iconStyle = computed(() => {
29
- return { color: props.color || 'inherit' }
30
- })
31
- const wrapStyle = computed(() => {
32
- const dirMap = { right: 'row', left: 'row-reverse', top: 'column-reverse', bottom: 'column' }
33
- return { display: 'flex', alignItems: 'center', flexDirection: dirMap[props.labelPos] || 'row' }
34
- })
35
- const labelStyle = computed(() => {
36
- return {
37
- color: props.labelColor || '',
38
- fontSize: toPx(props.labelSize),
39
- marginLeft: props.labelPos === 'right' ? toPx(props.space) : 0,
40
- marginTop: props.labelPos === 'bottom' ? toPx(props.space) : 0,
41
- marginRight: props.labelPos === 'left' ? toPx(props.space) : 0,
42
- marginBottom: props.labelPos === 'top' ? toPx(props.space) : 0
43
- }
44
- })
45
- const imgSrc = '__IMG_SRC__'
46
- function onTap(e) {
47
- emit('click', props.index)
48
- if (props.stop && e && e.stopPropagation) e.stopPropagation()
49
- }
50
- </script>
51
- <style scoped>
52
- .icon__label { line-height: 1; }
53
- </style>