@5ime/likeme 1.0.0 → 1.0.2
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.
- package/README.md +81 -81
- package/demo/index.html +22 -0
- package/index.js +45 -43
- package/package.json +1 -1
- package/public/index.html +3 -3
- package/static/css/likeme.css +1 -1
- package/static/js/likeme.js +1 -1
- package/vercel.json +14 -0
package/README.md
CHANGED
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
# likeMe
|
|
2
|
-
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
##
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- `
|
|
54
|
-
- `
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
1
|
+
# likeMe
|
|
2
|
+
|
|
3
|
+
> 🍰 快速为你的网站添加 "你喜欢我吗 / Do you like me" 小组件
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## LeanCloud 设置
|
|
8
|
+
|
|
9
|
+
1. [登录](https://console.leancloud.app/login) 或 [注册](https://console.leancloud.app/register) `LeanCloud 国际版` 并进入 [控制台](https://console.leancloud.app/apps)。
|
|
10
|
+
2. 点击左上角 [创建应用](https://console.leancloud.app/apps) 并起一个你喜欢的名字(请选择免费的 **开发版**)。
|
|
11
|
+
3. 进入应用,选择左下角的 **设置 > 应用凭证**,你可以看到你的 **APP ID**、**APP Key** 和 **REST API 服务器地址**,请记录它们以备后续使用。
|
|
12
|
+
4. 进入应用,选择左上角的 **数据存储 > 结构化数据 > 创建 Class**:
|
|
13
|
+
- **Class 名称** 填写为 `likeCount`。
|
|
14
|
+
- **Class 访问权限**:除 `update` 和 `find` 外均选择 **指定用户**。
|
|
15
|
+
- **默认 ACL 权限**:选定为 **限制读取**,然后点击 **创建**。
|
|
16
|
+
5. 选择新建的 `likeCount` Class,点击 **添加行**,并将 **ACL 权限** 设置为 **所有用户**,点击 **添加**,记录生成行的 `objectId`。
|
|
17
|
+
6. 再次 **创建 Class**,**Class 名称** 填写为 `likeUser`:
|
|
18
|
+
- **Class 访问权限**:除 `create` 和 `find` 外均选择 **指定用户**。
|
|
19
|
+
- **默认 ACL 权限**:选定为 **限制读取**,然后点击 **创建**。
|
|
20
|
+
|
|
21
|
+
此时你应该拥有以下信息:
|
|
22
|
+
- `APP ID`
|
|
23
|
+
- `APP Key`
|
|
24
|
+
- `REST API 服务器地址`
|
|
25
|
+
- `objectId` 🎉
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Vercel 部署
|
|
30
|
+
|
|
31
|
+
[](https://vercel.com/new/clone?repository-url=https://github.com/5ime/likeme)
|
|
32
|
+
|
|
33
|
+
1. 点击上方按钮跳转至 **Vercel** 进行部署。
|
|
34
|
+
2. 输入一个你喜欢的 Vercel 项目名称并点击 **Create**。
|
|
35
|
+
3. Vercel 会基于 `likeMe` 模板新建并初始化仓库,仓库名为你输入的项目名。一两分钟后,满屏的烟花会庆祝部署成功。
|
|
36
|
+
4. 点击 **Go to Dashboard** 跳转到控制台。
|
|
37
|
+
5. 进入顶部的 **Settings > Environment Variables** 配置以下环境变量:
|
|
38
|
+
- `appId`:LeanCloud 的 `APP ID`。
|
|
39
|
+
- `appKey`:LeanCloud 的 `APP Key`。
|
|
40
|
+
- `serverURL`:LeanCloud 的 `REST API 服务器地址`。
|
|
41
|
+
- `objectId`:`likeCount` 表中记录的 `objectId`。
|
|
42
|
+
6. 环境变量配置完成后,进入顶部的 **Deployments**,找到最新一次部署并点击右侧的 **Redeploy** 按钮以使环境变量生效。
|
|
43
|
+
7. 部署完成后,点击 **Visit** 跳转到部署好的地址,此地址即为你的服务端地址。
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 绑定域名 (可选)
|
|
48
|
+
|
|
49
|
+
1. 进入 **Settings > Domains** 配置域名。
|
|
50
|
+
2. 输入需要绑定的域名并点击 **Add**。
|
|
51
|
+
3. 在域名服务器商处添加新的 `CNAME` 记录:
|
|
52
|
+
- **Type**: `CNAME`
|
|
53
|
+
- **Name**: `example`
|
|
54
|
+
- **Value**: `cname.vercel-dns.com`
|
|
55
|
+
4. 等待生效后,即可通过自己的域名访问 🎉。
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## HTML 引入
|
|
60
|
+
|
|
61
|
+
在网页中进行如下设置:
|
|
62
|
+
|
|
63
|
+
1. 使用 `CDN` 引入 `likeMe`:
|
|
64
|
+
```html
|
|
65
|
+
<link rel="stylesheet" href="https://unpkg.com/@5ime/likeme@latest/static/css/likeme.css" />
|
|
66
|
+
<script src="https://unpkg.com/@5ime/likeme@latest/static/js/likeme.js"></script>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
2. 创建 `<script>` 标签并初始化 `likeMe`:
|
|
70
|
+
```html
|
|
71
|
+
<div id="likeme"></div>
|
|
72
|
+
<script>
|
|
73
|
+
likeMe({
|
|
74
|
+
el: '#likeme',
|
|
75
|
+
serverURL: 'https://your-domain.vercel.app',
|
|
76
|
+
color: '#ff9797', // 可选:设置背景颜色
|
|
77
|
+
});
|
|
78
|
+
</script>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
3. 此时 `likeMe` 就会在你的网站上成功运行 🎉。
|
package/demo/index.html
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Do You Like Me?</title>
|
|
8
|
+
<link rel="stylesheet" href="https://unpkg.com/@5ime/likeme@latest/static/css/likeme.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="likeme"></div>
|
|
12
|
+
|
|
13
|
+
<script src="https://unpkg.com/@5ime/likeme@latest/static/js/likeme.js"></script>
|
|
14
|
+
<script>
|
|
15
|
+
likeMe({
|
|
16
|
+
el: '#likeme',
|
|
17
|
+
serverURL: `${location.protocol}//${location.host}`,
|
|
18
|
+
color: '#ff4e6a',
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
21
|
+
</body>
|
|
22
|
+
</html>
|
package/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const express = require('express')
|
|
1
|
+
const express = require('express');
|
|
2
2
|
const AV = require('leancloud-storage');
|
|
3
|
-
|
|
4
|
-
const app = express()
|
|
5
|
-
const port = 80
|
|
3
|
+
|
|
4
|
+
const app = express();
|
|
5
|
+
const port = 80;
|
|
6
6
|
|
|
7
7
|
AV.init({
|
|
8
8
|
appId: process.env.appId,
|
|
@@ -10,49 +10,51 @@ AV.init({
|
|
|
10
10
|
serverURL: process.env.serverURL
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
const query = new AV.Query('likeCount');
|
|
14
13
|
const account = AV.Object.createWithoutData('likeCount', process.env.objectId);
|
|
15
14
|
|
|
16
|
-
app.use(
|
|
15
|
+
app.use((req, res, next) => {
|
|
17
16
|
res.header('Access-Control-Allow-Origin', '*');
|
|
18
|
-
|
|
19
|
-
res.sendStatus(200);
|
|
20
|
-
} else {
|
|
21
|
-
next();
|
|
22
|
-
}
|
|
17
|
+
req.method === 'OPTIONS' ? res.sendStatus(200) : next();
|
|
23
18
|
});
|
|
24
19
|
|
|
25
|
-
app.use('/static', express.static(__dirname
|
|
26
|
-
|
|
27
|
-
app.get('/',
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
20
|
+
app.use('/static', express.static(`${__dirname}/static`));
|
|
21
|
+
app.use('/demo', express.static(`${__dirname}/demo`));
|
|
22
|
+
app.get('/', (req, res) => res.sendFile(`${__dirname}/public/index.html`));
|
|
23
|
+
|
|
24
|
+
app.get('/info', async (req, res) => {
|
|
25
|
+
try {
|
|
26
|
+
const count = (await new AV.Query('likeCount').first())?.get('count') || 0;
|
|
27
|
+
res.json({ code: '200', msg: 'success', data: { count } });
|
|
28
|
+
} catch {
|
|
29
|
+
console.error('Error in /info:', error);
|
|
30
|
+
res.json({ code: '201', msg: '数据拉取失败~' });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
31
33
|
|
|
32
|
-
app.get('/
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
app.get('/like', async (req, res) => {
|
|
35
|
+
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || 'unknown';
|
|
36
|
+
try {
|
|
37
|
+
const userExists = await new AV.Query('likeUser').equalTo('ip', ip).first();
|
|
38
|
+
if (userExists) return res.json({ code: '201', msg: '今天的爱意已经收到啦~' });
|
|
39
|
+
|
|
40
|
+
await account.fetch();
|
|
41
|
+
account.increment('count');
|
|
42
|
+
const updatedAccount = await account.save();
|
|
43
|
+
|
|
44
|
+
const acl = new AV.ACL();
|
|
45
|
+
acl.setPublicReadAccess(true);
|
|
46
|
+
acl.setPublicWriteAccess(false);
|
|
47
|
+
|
|
48
|
+
const likeUser = new (AV.Object.extend('likeUser'))();
|
|
49
|
+
likeUser.set('ip', ip);
|
|
50
|
+
likeUser.setACL(acl);
|
|
51
|
+
await likeUser.save();
|
|
52
|
+
|
|
53
|
+
res.json({ code: '200', msg: 'success', data: { count: updatedAccount.get('count') } });
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('Error in /like:', error);
|
|
56
|
+
res.json({ code: '201', msg: '你的爱意传递失败~' });
|
|
36
57
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
app.get('/like', (req, res) => {
|
|
44
|
-
account.increment('count', +1);
|
|
45
|
-
account.save(null, {
|
|
46
|
-
query: new AV.Query('likeCount').greaterThanOrEqualTo('count', +1),fetchWhenSave: true
|
|
47
|
-
}).then((account) => {
|
|
48
|
-
const data = {code: '200', msg: 'success', data: {count: account.attributes.count}}
|
|
49
|
-
res.send(data);
|
|
50
|
-
}, (error) => {
|
|
51
|
-
if (error.code === 305) {
|
|
52
|
-
const data = {code: '201', msg: 'error'}
|
|
53
|
-
res.send(data);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
app.listen(port, () => {})
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
app.listen(port, () => console.log(`Server running on port ${port}`));
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>Do You Like Me
|
|
7
|
+
<title>Do You Like Me?</title>
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
|
-
<link rel="stylesheet" href='https://unpkg.com/likeme@latest/static/css/likeme.css'/>
|
|
10
|
+
<link rel="stylesheet" href='https://unpkg.com/@5ime/likeme@latest/static/css/likeme.css' />
|
|
11
11
|
<div class="likeCard">
|
|
12
12
|
<div class="likeCard-text">
|
|
13
13
|
少女祈祷中...
|
|
@@ -15,4 +15,4 @@
|
|
|
15
15
|
<h3>Do You Like Me</h3>
|
|
16
16
|
</div>
|
|
17
17
|
</body>
|
|
18
|
-
</html>
|
|
18
|
+
</html>
|
package/static/css/likeme.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.likeCard{width:auto;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:pointer;border-radius:5px;margin:0 auto;padding:20px;background:#ff9797;transition:
|
|
1
|
+
.likeCard{width:auto;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;cursor:pointer;border-radius:5px;margin:0 auto;padding:20px;background:#ff9797;transition:background .2s;color:#fff;text-align:center}.likeCard:hover{background:#ff8d8d}.likeCard>h3{font-size:1.2em;margin-top:.4em;margin-bottom:0}
|
package/static/js/likeme.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
const likeMe=(()=>{let e;return t=>e||(e=new LikeMeSingleton(t))})();class LikeMeSingleton{constructor({el:e,serverURL:t,color:r="#ff9797"}){Object.assign(this,{el:e,url:t,color:r}),this.init()}async init(){await this.renderUI(),this.attachEvents(),this.updateCount()}async renderUI(){try{const e=await fetch(this.url),t=await e.text(),r=document.querySelector(this.el);r&&(r.innerHTML=(new DOMParser).parseFromString(t,"text/html").body.innerHTML,r.querySelector(".likeCard")?.style.setProperty("background-color",this.color))}catch(e){console.error("Render UI error:",e)}}attachEvents(){document.querySelector(`${this.el} .likeCard`)?.addEventListener("click",(()=>this.handleLike()))}async updateCount(){try{const e=await fetch(`${this.url}/info`);if(e.ok){const t=(await e.json()).data?.count||0,r=document.querySelector(`${this.el} .likeCard-text`);r&&(r.textContent=`❤ ${t}`)}}catch(e){console.error("Update count error:",e)}}async handleLike(){try{const e=await fetch(`${this.url}/like`);if(e.ok){const{code:t,data:{count:r=0}={},msg:n}=await e.json(),o=document.querySelector(`${this.el} .likeCard-text`);o&&(o.textContent="200"===t?`❤ ${r}`:n)}}catch(e){console.error("Handle like error:",e)}}}
|