hexo-theme-lnote 1.2.5 → 1.2.6
Sign up to get free protection for your applications and to get access to all the features.
- package/config/links.yml +21 -21
- package/languages/en.yml +4 -0
- package/languages/zh-CN.yml +4 -0
- package/languages/zh-HK.yml +4 -0
- package/languages/zh-TW.yml +4 -0
- package/package.json +3 -2
- package/scripts/index.js +1 -0
- package/source/css/_pages/_base/base.styl +3 -4
- package/source/css/_pages/_base/color-schema.styl +4 -0
- package/source/css/_pages/_post/highlight.styl +5 -4
- package/source/css/_pages/_post/markdown.styl +4 -4
- package/source/css/_pages/_post/post-tag.styl +50 -18
- package/source/css/_variables/base.styl +1 -1
- package/source/img/chat/responder.jpg +0 -0
- package/source/img/chat/sender.jpg +0 -0
- package/source/img/default8.jpg +0 -0
- package/source/js/post/img-swipe.js +6 -3
- package/templates/Chat.vue +52 -0
- package/templates/GroupImage.vue +36 -0
- package/templates/MenuNav.vue +39 -0
- package/templates/Note.vue +33 -0
- package/templates/Noun.vue +25 -0
- package/templates/NounContent.vue +29 -0
- package/templates/Tab.vue +40 -0
- package/templates/utils/uri.ts +30 -2
- package/templates/noun.vue +0 -15
@@ -28,11 +28,10 @@ body
|
|
28
28
|
transition color .2s ease-in-out, background-color .2s ease-in-out
|
29
29
|
|
30
30
|
code
|
31
|
-
|
31
|
+
user-select all
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
color var(--post-text-color)
|
33
|
+
pre code
|
34
|
+
user-select auto
|
36
35
|
|
37
36
|
img[lazyload]
|
38
37
|
object-fit cover
|
@@ -21,6 +21,8 @@
|
|
21
21
|
--inlinecode-bg-color $inlinecode-bg-color
|
22
22
|
--code-mac-top-bg #f2f2f2
|
23
23
|
--code-mac-body-bg #fff
|
24
|
+
// --chat-sender #f0f0f0
|
25
|
+
// --chat-responder #d7ecff
|
24
26
|
|
25
27
|
dark-colors()
|
26
28
|
--body-bg-color $body-bg-color-dark
|
@@ -44,6 +46,8 @@ dark-colors()
|
|
44
46
|
--inlinecode-bg-color $inlinecode-bg-color-dark
|
45
47
|
--code-mac-top-bg #181818
|
46
48
|
--code-mac-body-bg #000
|
49
|
+
// --chat-sender #16171a
|
50
|
+
// --chat-responder #002440
|
47
51
|
|
48
52
|
.navbar .dropdown-collapse, .top-nav-collapse, .navbar-col-show
|
49
53
|
if $navbar-glass-enable
|
@@ -7,8 +7,9 @@
|
|
7
7
|
|
8
8
|
.highlight
|
9
9
|
position relative
|
10
|
-
border-radius
|
11
|
-
padding-top:
|
10
|
+
border-radius 0.5rem
|
11
|
+
padding-top: 1.75rem
|
12
|
+
margin-top: 1rem
|
12
13
|
background-color: var(--code-mac-top-bg)
|
13
14
|
&::before
|
14
15
|
background: #fc625d
|
@@ -35,8 +36,8 @@
|
|
35
36
|
table-layout: fixed
|
36
37
|
width: 100%
|
37
38
|
|
38
|
-
figure
|
39
|
-
margin 1rem 0
|
39
|
+
/* figure
|
40
|
+
margin 1rem 0 */
|
40
41
|
|
41
42
|
figure.highlight
|
42
43
|
position relative
|
@@ -24,8 +24,8 @@
|
|
24
24
|
&:focus
|
25
25
|
outline none
|
26
26
|
|
27
|
-
a
|
28
|
-
color var(--bs-link-color);
|
27
|
+
/* a
|
28
|
+
color var(--bs-link-color); */
|
29
29
|
|
30
30
|
strong
|
31
31
|
font-weight bold
|
@@ -83,7 +83,7 @@ hr, .markdown-body hr
|
|
83
83
|
margin 2rem 0
|
84
84
|
|
85
85
|
// Rewrite figcaption
|
86
|
-
.markdown-body
|
86
|
+
/* .markdown-body
|
87
87
|
figcaption.image-caption
|
88
88
|
font-size .8rem
|
89
89
|
color var(--post-text-color)
|
@@ -93,4 +93,4 @@ hr, .markdown-body hr
|
|
93
93
|
text-align center
|
94
94
|
|
95
95
|
figcaption:not(.image-caption)
|
96
|
-
display none
|
96
|
+
display none */
|
@@ -1,5 +1,3 @@
|
|
1
|
-
|
2
|
-
|
3
1
|
// popover
|
4
2
|
.lnote-popover-btn
|
5
3
|
--bs-btn-padding-y 0
|
@@ -7,10 +5,23 @@
|
|
7
5
|
--bs-btn-line-height 1
|
8
6
|
.lnote-popover
|
9
7
|
--bs-popover-border-color var(--bs-primary)
|
10
|
-
--bs-popover-
|
11
|
-
--bs-popover-
|
12
|
-
--bs-popover-
|
13
|
-
|
8
|
+
--bs-popover-body-padding-x 0
|
9
|
+
--bs-popover-body-padding-y 0
|
10
|
+
--bs-popover-bg transparent
|
11
|
+
&.secondary
|
12
|
+
--bs-popover-border-color var(--bs-secondary)
|
13
|
+
&.info
|
14
|
+
--bs-popover-border-color var(--bs-info)
|
15
|
+
&.success
|
16
|
+
--bs-popover-border-color var(--bs-success)
|
17
|
+
&.warning
|
18
|
+
--bs-popover-border-color var(--bs-warning)
|
19
|
+
&.danger
|
20
|
+
--bs-popover-border-color var(--bs-danger)
|
21
|
+
&.light
|
22
|
+
--bs-popover-border-color var(--bs-light)
|
23
|
+
&.dark
|
24
|
+
--bs-popover-border-color var(--bs-dark)
|
14
25
|
|
15
26
|
// note
|
16
27
|
.note
|
@@ -26,18 +37,39 @@
|
|
26
37
|
|
27
38
|
// group-image
|
28
39
|
.group-image-container
|
29
|
-
margin
|
40
|
+
margin 1rem auto
|
30
41
|
img
|
31
|
-
width
|
32
|
-
height
|
33
|
-
// object-fit: cover
|
42
|
+
width 100%
|
43
|
+
height 100%
|
34
44
|
.image-adapter
|
35
|
-
padding-bottom
|
36
|
-
position
|
45
|
+
padding-bottom 100%
|
46
|
+
position relative
|
37
47
|
> div
|
38
|
-
width
|
39
|
-
height
|
40
|
-
position
|
41
|
-
left
|
42
|
-
top
|
43
|
-
z-index
|
48
|
+
width 100%
|
49
|
+
height 100%
|
50
|
+
position absolute
|
51
|
+
left 0
|
52
|
+
top 0
|
53
|
+
z-index 2
|
54
|
+
|
55
|
+
// chat
|
56
|
+
.chats
|
57
|
+
.chat-avatar
|
58
|
+
width: 2.8rem
|
59
|
+
height: 2.8rem
|
60
|
+
.chat-name
|
61
|
+
font-size: 0.8rem
|
62
|
+
line-height: 1
|
63
|
+
max-width: 84%
|
64
|
+
white-space: nowrap
|
65
|
+
text-overflow: ellipsis
|
66
|
+
.chat-content
|
67
|
+
max-width: 84%
|
68
|
+
:last-child
|
69
|
+
margin-bottom: 0
|
70
|
+
/* .chat-sender
|
71
|
+
.chat-content
|
72
|
+
background-color: var(--chat-sender)
|
73
|
+
.chat-responder
|
74
|
+
.chat-content
|
75
|
+
background-color: var(--chat-responder) */
|
Binary file
|
Binary file
|
package/source/img/default8.jpg
CHANGED
Binary file
|
@@ -1,7 +1,7 @@
|
|
1
|
-
import PhotoSwipeLightbox from '//
|
1
|
+
import PhotoSwipeLightbox from '//cdn.staticfile.net/photoswipe/5.4.2/photoswipe-lightbox.esm.min.js'
|
2
2
|
|
3
3
|
const lightbox = new PhotoSwipeLightbox({
|
4
|
-
pswpModule: () => import('//
|
4
|
+
pswpModule: () => import('//cdn.staticfile.net/photoswipe/5.4.2/photoswipe.esm.min.js'),
|
5
5
|
wheelToZoom: true,
|
6
6
|
})
|
7
7
|
const groups = []
|
@@ -69,9 +69,12 @@ Promise.allSettled(promiseds).then(() => {
|
|
69
69
|
order: 9,
|
70
70
|
isButton: false,
|
71
71
|
appendTo: 'root',
|
72
|
-
html:
|
72
|
+
html: null,
|
73
73
|
onInit(el, pswp) {
|
74
74
|
pswp.on('change', () => {
|
75
|
+
if (pswp.currSlide.data.alt == null) {
|
76
|
+
return
|
77
|
+
}
|
75
78
|
el.innerHTML = `<div>${pswp.currSlide.data.alt}</div>`
|
76
79
|
})
|
77
80
|
},
|
@@ -0,0 +1,52 @@
|
|
1
|
+
<template>
|
2
|
+
<article class="chats">
|
3
|
+
<template v-for="item in chats">
|
4
|
+
<section
|
5
|
+
v-if="item.role === 'sender'"
|
6
|
+
class="chat-sender py-3 d-flex align-items-start justify-content-start"
|
7
|
+
>
|
8
|
+
<img
|
9
|
+
class="chat-avatar rounded"
|
10
|
+
:src="uriFor(['/img/chat/sender.jpg'])"
|
11
|
+
/>
|
12
|
+
<div
|
13
|
+
class="chat-part overflow-hidden ms-3 flex-fill d-flex flex-column align-items-start"
|
14
|
+
>
|
15
|
+
<div class="chat-name mb-2 overflow-hidden">
|
16
|
+
{{ item.name }}
|
17
|
+
</div>
|
18
|
+
<div
|
19
|
+
class="chat-content rounded bg-secondary-subtle px-3 py-2"
|
20
|
+
v-html="item.content"
|
21
|
+
></div>
|
22
|
+
</div>
|
23
|
+
</section>
|
24
|
+
<section
|
25
|
+
v-else
|
26
|
+
class="chat-responder py-3 flex-row-reverse d-flex align-items-start justify-content-start"
|
27
|
+
>
|
28
|
+
<img
|
29
|
+
class="chat-avatar rounded"
|
30
|
+
:src="uriFor(['/img/chat/responder.jpg'])"
|
31
|
+
/>
|
32
|
+
<div
|
33
|
+
class="chat-part overflow-hidden me-3 flex-fill d-flex flex-column align-items-end"
|
34
|
+
>
|
35
|
+
<div class="chat-name mb-2 overflow-hidden">
|
36
|
+
{{ item.name }}
|
37
|
+
</div>
|
38
|
+
<div
|
39
|
+
class="chat-content rounded bg-primary-subtle px-3 py-2"
|
40
|
+
v-html="item.content"
|
41
|
+
></div>
|
42
|
+
</div>
|
43
|
+
</section>
|
44
|
+
</template>
|
45
|
+
</article>
|
46
|
+
</template>
|
47
|
+
|
48
|
+
<script lang="ts" setup>
|
49
|
+
import { uriFor } from './utils/uri'
|
50
|
+
import type { Chat } from '../types/tag'
|
51
|
+
const chats: Chat[] = []
|
52
|
+
</script>
|
@@ -0,0 +1,36 @@
|
|
1
|
+
<template>
|
2
|
+
<div v-if="rowCol === 1" class="group-image-container">
|
3
|
+
<img
|
4
|
+
class="img-fluid object-fit-cover w-100 img-swipe-single"
|
5
|
+
:alt="list[0].title"
|
6
|
+
:src="uriFor([list[0].url])"
|
7
|
+
/>
|
8
|
+
</div>
|
9
|
+
<div v-else class="group-image-container img-swipe-group">
|
10
|
+
<div :class="['row', `row-cols-${rowCol}`, 'gx-2', 'gy-2']">
|
11
|
+
<div class="col" v-for="item in list">
|
12
|
+
<img
|
13
|
+
v-if="isSameSize"
|
14
|
+
class="img-fluid object-fit-cover"
|
15
|
+
:alt="item.title"
|
16
|
+
:src="uriFor([item.url])"
|
17
|
+
/>
|
18
|
+
<div class="image-adapter" v-else>
|
19
|
+
<div>
|
20
|
+
<img
|
21
|
+
class="img-fluid object-fit-cover"
|
22
|
+
:alt="item.title"
|
23
|
+
:src="uriFor([item.url])"
|
24
|
+
/>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</template>
|
31
|
+
<script lang="ts" setup>
|
32
|
+
import { uriFor } from './utils/uri'
|
33
|
+
const rowCol: number = 1
|
34
|
+
const isSameSize: boolean = false
|
35
|
+
const list: { title: string; url: string }[] = []
|
36
|
+
</script>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<template>
|
2
|
+
<div :class="['btn-group', typeBgClass(type)]" role="group">
|
3
|
+
<div class="btn-group" role="group" v-for="menu in menus">
|
4
|
+
<button
|
5
|
+
type="button"
|
6
|
+
:class="['btn', `btn-outline-${type}`, 'dropdown-toggle']"
|
7
|
+
data-bs-toggle="dropdown"
|
8
|
+
aria-expanded="false"
|
9
|
+
>
|
10
|
+
{{ menu.text }}
|
11
|
+
</button>
|
12
|
+
<ul :class="['dropdown-menu']">
|
13
|
+
<li v-for="item in menu.secondaryMenus">
|
14
|
+
<a
|
15
|
+
:class="['dropdown-item']"
|
16
|
+
:href="uriFor([item.link])"
|
17
|
+
>
|
18
|
+
{{ item.text }}
|
19
|
+
</a>
|
20
|
+
</li>
|
21
|
+
</ul>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
</template>
|
25
|
+
|
26
|
+
<script setup lang="ts">
|
27
|
+
import { uriFor, typeBgClass } from './utils/uri'
|
28
|
+
import type { Type } from '../types/tag'
|
29
|
+
type SecondaryMenu = {
|
30
|
+
text: string
|
31
|
+
link: string
|
32
|
+
}
|
33
|
+
type FirstMenu = {
|
34
|
+
text: string
|
35
|
+
secondaryMenus: SecondaryMenu[]
|
36
|
+
}
|
37
|
+
const type: Type = 'warning'
|
38
|
+
const menus: FirstMenu[] = []
|
39
|
+
</script>
|
@@ -0,0 +1,33 @@
|
|
1
|
+
<template>
|
2
|
+
<div
|
3
|
+
v-if="iconType"
|
4
|
+
:class="[
|
5
|
+
'note',
|
6
|
+
'alert',
|
7
|
+
`alert-${alertType}`,
|
8
|
+
'd-flex',
|
9
|
+
'align-items-top',
|
10
|
+
]"
|
11
|
+
role="alert"
|
12
|
+
>
|
13
|
+
<svg
|
14
|
+
class="flex-shrink-0 me-2"
|
15
|
+
role="img"
|
16
|
+
width="1.2em"
|
17
|
+
height="1.2em"
|
18
|
+
:style="{marginTop: '0.2rem'}"
|
19
|
+
>
|
20
|
+
<use :xlink:href="`#${iconType}`"></use>
|
21
|
+
</svg>
|
22
|
+
<div v-html="html"></div>
|
23
|
+
</div>
|
24
|
+
<div v-else :class="['note', 'alert', `alert-${alertType}`]">
|
25
|
+
<div v-html="html"></div>
|
26
|
+
</div>
|
27
|
+
</template>
|
28
|
+
<script lang="ts" setup>
|
29
|
+
import type { Type } from '../types/tag'
|
30
|
+
const alertType: Type = 'info'
|
31
|
+
const iconType: Type = 'info'
|
32
|
+
const html: string = ''
|
33
|
+
</script>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<template>
|
2
|
+
<button
|
3
|
+
type="button"
|
4
|
+
:class="['btn', 'btn-link', `text-${type}-emphasis`, 'lnote-popover-btn']"
|
5
|
+
data-bs-toggle="popover"
|
6
|
+
data-bs-trigger="hover focus"
|
7
|
+
data-bs-placement="right"
|
8
|
+
:data-bs-custom-class="`lnote-popover ${type}`"
|
9
|
+
data-bs-html="true"
|
10
|
+
:data-bs-content="content"
|
11
|
+
>
|
12
|
+
{{ text }}
|
13
|
+
<svg width="18" height="18">
|
14
|
+
<use xlink:href="#question-circle-fill"></use>
|
15
|
+
</svg>
|
16
|
+
</button>
|
17
|
+
</template>
|
18
|
+
|
19
|
+
<script lang="ts" setup>
|
20
|
+
import { typeBgClass } from './utils/uri'
|
21
|
+
import type { Type } from '../types/tag'
|
22
|
+
const type: Type = 'primary'
|
23
|
+
const content = ''
|
24
|
+
const text = ''
|
25
|
+
</script>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<template>
|
2
|
+
<div :class="['card', `border-${type}`]">
|
3
|
+
<div :class="['card-header', 'fw-bold', `text-bg-${type}`]">{{ title }}</div>
|
4
|
+
<div :class="['card-body', `bg-${type}-subtle`, 'rounded-bottom']">
|
5
|
+
<!-- <h5 class="card-title" v-if="title">{{ title }}</h5> -->
|
6
|
+
<p class="card-text">
|
7
|
+
{{ text }}
|
8
|
+
</p>
|
9
|
+
<a
|
10
|
+
v-if="link"
|
11
|
+
:href="uriFor([link])"
|
12
|
+
:class="['card-link', `text-${type}-emphasis`]"
|
13
|
+
>
|
14
|
+
{{ moreText }}
|
15
|
+
</a>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
</template>
|
19
|
+
|
20
|
+
<script lang="ts" setup>
|
21
|
+
import { uriFor, typeBgClass } from './utils/uri'
|
22
|
+
import type { Type } from '../types/tag'
|
23
|
+
const type: Type = 'primary'
|
24
|
+
// const promptText = ''
|
25
|
+
const moreText = ''
|
26
|
+
const title = ''
|
27
|
+
const text = ''
|
28
|
+
const link = ''
|
29
|
+
</script>
|
@@ -0,0 +1,40 @@
|
|
1
|
+
<template>
|
2
|
+
<nav>
|
3
|
+
<ul
|
4
|
+
class="nav nav-underline mb-3 d-flex flex-nowrap overflow-x-auto text-nowrap border-bottom"
|
5
|
+
role="tablist"
|
6
|
+
>
|
7
|
+
<li class="nav-item" role="presentation" v-for="(item, index) in tabs">
|
8
|
+
<button
|
9
|
+
data-bs-toggle="tab"
|
10
|
+
role="tab"
|
11
|
+
type="button"
|
12
|
+
:aria-selected="index === 0 ? 'true' : 'false'"
|
13
|
+
:class="['nav-link', { active: index === 0 }]"
|
14
|
+
:id="`tab-${key}-${index}`"
|
15
|
+
:data-bs-target="`#nav-${key}-${index}`"
|
16
|
+
:aria-controls="`nav-${key}-${index}`"
|
17
|
+
>
|
18
|
+
{{ item.name }}
|
19
|
+
</button>
|
20
|
+
</li>
|
21
|
+
</ul>
|
22
|
+
<div class="tab-content">
|
23
|
+
<div
|
24
|
+
v-for="(item, index) in tabs"
|
25
|
+
:class="['tab-pane', 'fade', index === 0 && 'show active']"
|
26
|
+
:id="`nav-${key}-${index}`"
|
27
|
+
role="tabpanel"
|
28
|
+
:aria-labelledby="`tab-${key}-${index}`"
|
29
|
+
:tabindex="index"
|
30
|
+
>
|
31
|
+
<div v-html="item.content"></div>
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
</nav>
|
35
|
+
</template>
|
36
|
+
<script lang="ts" setup>
|
37
|
+
import type { Tab } from '../types/tag'
|
38
|
+
const key: string = ''
|
39
|
+
const tabs: Tab[] = []
|
40
|
+
</script>
|
package/templates/utils/uri.ts
CHANGED
@@ -1,12 +1,40 @@
|
|
1
1
|
import fs from 'fs'
|
2
2
|
import path from 'path'
|
3
|
+
import type { Type } from '../../types/tag'
|
3
4
|
|
4
5
|
function runtimeProjectInfo() {
|
5
6
|
const projectPath = path.resolve(process.cwd(), 'package.json')
|
6
7
|
return JSON.parse(fs.readFileSync(projectPath, 'utf-8'))
|
7
8
|
}
|
8
9
|
|
9
|
-
|
10
|
+
function linkIsCDN(url: string) {
|
11
|
+
if (/^https*:\/\//.test(url) || /^\/\//.test(url)) {
|
12
|
+
return true
|
13
|
+
}
|
14
|
+
return false
|
15
|
+
}
|
16
|
+
|
17
|
+
/**
|
18
|
+
* @description 图片链接生成
|
19
|
+
* 1. http或https开头的cdn链接,将原样转换回去,且只会返回第一个
|
20
|
+
* 2. 多个链接组合成一个,并在前面添加上当前项目的name
|
21
|
+
* @param {string[]} uris uri组,每一个uri必须带 / 开头,保持和 hexo 图片标签一样
|
22
|
+
* @returns
|
23
|
+
*/
|
24
|
+
export function uriFor(uris: string[]) {
|
25
|
+
if (uris.length === 1 && linkIsCDN(uris[0])) {
|
26
|
+
return uris[0]
|
27
|
+
}
|
10
28
|
const { name } = runtimeProjectInfo()
|
11
|
-
return ['', name,
|
29
|
+
return ['/', name, ...uris].join('')
|
30
|
+
}
|
31
|
+
|
32
|
+
export function typeBgClass(type: Type) {
|
33
|
+
if (['warning', 'info', 'light'].includes(type)) {
|
34
|
+
return 'bg-dark'
|
35
|
+
}
|
36
|
+
if (['dark'].includes(type)) {
|
37
|
+
return 'bg-light'
|
38
|
+
}
|
39
|
+
return ''
|
12
40
|
}
|
package/templates/noun.vue
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
<template>
|
2
|
-
<button type="button" class="btn btn-link lnote-popover-btn" data-bs-toggle="popover" data-bs-trigger="hover focus"
|
3
|
-
data-bs-placement="right" data-bs-custom-class="lnote-popover" :data-bs-title="title" :data-bs-content="desc">
|
4
|
-
{{ text }}
|
5
|
-
<svg width="18" height="18">
|
6
|
-
<use xlink:href="#question-circle-fill"></use>
|
7
|
-
</svg>
|
8
|
-
</button>
|
9
|
-
</template>
|
10
|
-
|
11
|
-
<script lang="ts" setup>
|
12
|
-
const title: string | undefined = undefined
|
13
|
-
const desc = ''
|
14
|
-
const text = ''
|
15
|
-
</script>
|