@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 CHANGED
@@ -1,81 +1,81 @@
1
- # likeMe
2
-
3
- > 🍰快速为你的网站添加 你喜欢我吗/Do you like me 小组件
4
-
5
- ## LeanCloud 设置
6
-
7
- 1. [登录](https://console.leancloud.app/login) 或 [注册](https://console.leancloud.app/register) `LeanCloud 国际版` 并进入 [控制台](https://console.leancloud.app/apps)
8
- 2. 点击左上角 [创建应用](https://console.leancloud.app/apps) 并起一个你喜欢的名字 (请选择免费的**开发版**):
9
- 3. 进入应用,选择左下角的 `设置` > `应用凭证`。你可以看到你的 `APP ID`,`APP Key` 和 `REST API 服务器地址`。请记录它们,以便后续使用。
10
- 4. 进入应用,选择左上角的 `数据存储` > `结构化数据` > `创建 Class`。`Class 名称` 填写为 `likeCount`,`Class 访问权限` 除 `update` 和 `find` 外均选择 `指定用户`,`默认 ACL 权限` 选定为 `限制读取`,点击 `创建` 。
11
- 5. 选择新建的 `Class` 然后 `添加行` -> `设置 ACL 权限` 均设置为 `所有用户` ,点击 `添加` ,你可以看到新建行的 `objectId,`。请记录它,以便后续使用。
12
-
13
- 此时你应该拥有了以下信息:`APP ID`,`APP Key`,`REST API 服务器地址` 和 `objectId`:tada:
14
-
15
- ## Vercel部署
16
-
17
- [![Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/5ime/likeme)
18
-
19
- 1. 点击上方按钮,跳转至 `Vercel` 进行部署。
20
-
21
- 2. 输入一个你喜欢的 `Vercel` 项目名称并点击 `Create` 继续:
22
-
23
- 3. 此时 `Vercel` 会基于 `likeMe` 模板帮助你新建并初始化仓库,仓库名为你之前输入的项目名。
24
-
25
- 一两分钟后,满屏的烟花会庆祝你部署成功。此时点击 `Go to Dashboard` 可以跳转到应用的控制台。
26
-
27
- 4. 点击顶部的 `Settings` - `Environment Variables` 进入环境变量配置页,并配置四个环境变量 `appId`, `appKey` , `serverURL` 和 `objectId` 。它们的值分别对应上一步在 `LeanCloud` 中获得的 `APP ID`, `APP KEY`,`REST API 服务器地址` 和 `objectId`。
28
-
29
- 1. 环境变量配置完成之后点击顶部的 `Deployments` 点击顶部最新的一次部署右侧的 `Redeploy` 按钮进行重新部署。该步骤是为了让刚才设置的环境变量生效。
30
-
31
- 1. 此时会跳转到 `Overview` 界面开始部署,等待片刻后 `STATUS` 会变成 `Ready`。此时请点击 `Visit` ,即可跳转到部署好的网站地址,此地址即为你的服务端地址。
32
-
33
- ## 绑定域名 (可选)
34
-
35
- 1. 点击顶部的 `Settings` - `Domains` 进入域名配置页
36
-
37
- 1. 输入需要绑定的域名并点击 `Add`
38
-
39
- 1. 在域名服务器商处添加新的 `CNAME` 解析记录
40
-
41
- | Type | Name | Value |
42
- | ----- | ------- | -------------------- |
43
- | CNAME | example | cname.vercel-dns.com |
44
-
45
- 1. 等待生效,你可以通过自己的域名来访问了:tada:
46
-
47
- ## HTML 引入
48
-
49
- 在你的网页中进行如下设置:
50
-
51
- 1. 使用 `CDN` 引入 `likeMe`:
52
-
53
- - `https://unpkg.com/ likeme@latest/static/css/likeme.css`。
54
- - `https://unpkg.com/ likeme@latest/static/js/likeme.js`。
55
-
56
- 1. 创建 `<script>` 标签使用 `new limeMe()` 初始化,并传入必要的 `el` 与 `serverURL` 选项。
57
-
58
- - `el` 选项是 `likeMe` 渲染使用的元素,你可以设置一个字符串形式的 `CSS 选择器` 或者一个 `HTMLElement` 对象。
59
- - `serverURL` 是服务端的地址,即上一步获取到的值。
60
-
61
- ```html {3-7,12-18}:line-numbers
62
- <head>
63
- <!-- ... -->
64
- <link rel="stylesheet" href='https://unpkg.com/likeme@latest/static/css/likeme.css'/>
65
- <script src="https://unpkg.com/likeme@latest/static/js/likeme.js"></script>
66
- <!-- ... -->
67
- </head>
68
- <body>
69
- <!-- ... -->
70
- <div id="likeme"></div>
71
- <script>
72
- new limeMe({
73
- el: '#likeme',
74
- serverURL: 'https://your-domain.vercel.app',
75
- });
76
- </script>
77
- </body>
78
- ```
79
-
80
- 2. 此时 `likeMe` 就会在你的网站上成功运行 :tada:
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
+ [![Vercel](https://vercel.com/button)](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` 就会在你的网站上成功运行 🎉。
@@ -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
- const { Query, User } = AV;
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(function (req, res, next) {
15
+ app.use((req, res, next) => {
17
16
  res.header('Access-Control-Allow-Origin', '*');
18
- if (req.method === 'OPTIONS') {
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 + '/static'));
26
-
27
- app.get('/', function getState(req,res){
28
- res.setHeader('Content-Type', 'text/html');
29
- res.sendFile(__dirname + '/public/index.html');
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('/info', (req,res) => {
33
- query.find().then(function (results) {
34
- const data = {code: '200', msg: 'success', data: {count: results[0].attributes.count}}
35
- res.send(data);
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
- ).catch(function (error) {
38
- const data = {code: '201', msg: 'error'}
39
- res.send(data);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@5ime/likeme",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Do you like me?",
5
5
  "main": "index.js",
6
6
  "dependencies": {
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 ?</title>
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>
@@ -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:opacity .5s;color:#fff;text-align:center}.likeCard:hover{opacity:.9}.likeCard>h3{font-size:1.2em;margin-top:.4em;margin-bottom:0}
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}
@@ -1 +1 @@
1
- var limeMe=(function(){var instance;return function(likeme){if(!instance){instance=new CreateSingleton(likeme)}return instance}})();function CreateSingleton(likeme){this.el=likeme.el;this.url=likeme.serverURL;this.color=likeme.color;this.getData()}CreateSingleton.prototype.getData=function(){const url=this.url;const html=fetch(url).then((res)=>res.text()).then((html)=>{const parser=new DOMParser();const doc=parser.parseFromString(html,"text/html");const body=doc.querySelector("body");const likeme=document.querySelector(this.el);likeme.innerHTML=body.innerHTML;if(this.color){document.querySelector(".likeCard").style.backgroundColor=this.color}var xhr=new XMLHttpRequest();xhr.open("GET",url+"/info");xhr.send();document.querySelector(".likeCard").addEventListener("click",function(){xhr.open("GET",url+"/like");xhr.send()});xhr.onreadystatechange=function(){if(xhr.readyState==4&&xhr.status==200){var data=JSON.parse(xhr.responseText);document.querySelector(".likeCard-text").innerHTML="❤ "+data.data.count}}})};
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)}}}
package/vercel.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "builds": [
3
+ {
4
+ "src": "index.js",
5
+ "use": "@vercel/node"
6
+ }
7
+ ],
8
+ "routes": [
9
+ {
10
+ "src": "/(.*)",
11
+ "dest": "index.js"
12
+ }
13
+ ]
14
+ }