Skip to content

Commit

Permalink
Merge branch 'reminders'
Browse files Browse the repository at this point in the history
  • Loading branch information
movsb committed Dec 28, 2024
2 parents 3266c14 + 8769ac9 commit 529ec6c
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 2 deletions.
8 changes: 8 additions & 0 deletions service/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/movsb/taoblog/service/modules/comment_notify"
"github.com/movsb/taoblog/service/modules/renderers/exif"
"github.com/movsb/taoblog/service/modules/renderers/friends"
"github.com/movsb/taoblog/service/modules/renderers/reminders"
"github.com/movsb/taoblog/service/modules/search"
theme_fs "github.com/movsb/taoblog/theme/modules/fs"
"github.com/movsb/taorm"
Expand Down Expand Up @@ -87,6 +88,8 @@ type Service struct {
exifTask *exif.Task
// 朋友头像数据缓存任务
friendsTask *friends.Task
// 提醒事项任务
remindersTask *reminders.Task

// 文章内容缓存。
// NOTE:缓存 Key 是跟文章编号和内容选项相关的(因为内容选项不同内容也就不同),
Expand Down Expand Up @@ -231,6 +234,11 @@ func newService(ctx context.Context, cancel context.CancelFunc, cfg *config.Conf
s.updatePostMetadataTime(int64(postID), time.Now())
})

s.remindersTask = reminders.NewTask(s.GetPluginStorage(`reminders`), func(pid int64) {
s.deletePostContentCacheFor(pid)
s.updatePostMetadataTime(pid, time.Now())
})

s.certDaysLeft.Store(-1)
s.domainExpirationDaysLeft.Store(-1)
s.exporter = _NewExporter(s)
Expand Down
4 changes: 2 additions & 2 deletions service/modules/renderers/highlight/highlight.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import (
"github.com/yuin/goldmark/util"
)

//go:generate sass --style compressed style.scss style.css
//go:generate sass --no-source-map --style compressed style.scss style.css

//go:embed style.css style.css.map script.js
//go:embed style.css script.js
var _root embed.FS

func init() {
Expand Down
12 changes: 12 additions & 0 deletions service/modules/renderers/reminders/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# 提醒事项

主要用于长期的提醒事项备忘📝;例如:生日、纪念日。

## 格式

```reminder
title: 纪念日!
description: 详细的描述。
dates:
start: 2014-12-24
```
171 changes: 171 additions & 0 deletions service/modules/renderers/reminders/reminder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package reminders

import (
"bytes"
"embed"
"html/template"
"time"

"github.com/movsb/taoblog/modules/utils"
"github.com/movsb/taoblog/modules/utils/dir"
dynamic "github.com/movsb/taoblog/service/modules/renderers/_dynamic"
"github.com/movsb/taoblog/theme/modules/sass"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
"gopkg.in/yaml.v2"
)

//go:generate sass --no-source-map style.scss style.css

//go:embed reminder.html style.css
var _root embed.FS

func init() {
dynamic.RegisterInit(func() {
dynamic.Dynamic[`reminders`] = dynamic.Content{
Styles: []string{
string(utils.Must1(_root.ReadFile(`style.css`))),
},
}
sass.WatchDefaultAsync(string(dir.SourceAbsoluteDir()))
})
}

type Reminders struct {
task *Task
pid int
}

func New(task *Task, pid int) *Reminders {
f := &Reminders{
task: task,
pid: pid,
}

return f
}

type UserDate time.Time

var layouts = [...]string{
`2006-01-02`,
}

// TODO 需要修改成服务器时间。
var fixedZone = time.FixedZone(`fixed`, 8*60*60)

func (u *UserDate) UnmarshalYAML(unmarshal func(interface{}) error) error {
var s string
if err := unmarshal(&s); err != nil {
return err
}
var outErr error
for _, layout := range layouts {
// TODO 需要区分 Parse 与 ParseInLocation
t, err := time.ParseInLocation(layout, s, fixedZone)
if err != nil {
outErr = err
continue
}
*u = UserDate(t)
}
return outErr
}

type Reminder struct {
Title string `yaml:"title"`
Description string `yaml:"description"`
Dates struct {
Start UserDate `yaml:"start"`
} `yaml:"dates"`
}

func (r *Reminder) Days() int {
return int(time.Since(time.Time(r.Dates.Start)).Hours() / 24)
}

func (r *Reminder) Start() string {
return time.Time(r.Dates.Start).Format(`2006-01-02`)
}

var _ interface {
parser.ASTTransformer
goldmark.Extender
renderer.NodeRenderer
} = (*Reminders)(nil)

var tmpl = template.Must(template.New(`reminder`).Parse(string(utils.Must1(_root.ReadFile(`reminder.html`)))))

func (r *Reminders) Extend(m goldmark.Markdown) {
m.Parser().AddOptions(parser.WithASTTransformers(util.Prioritized(r, 100)))
m.Renderer().AddOptions(renderer.WithNodeRenderers(util.Prioritized(r, 100)))
}

type _ReminderRendererBlock struct {
ast.BaseBlock
ref *ast.FencedCodeBlock
}

var _reminderCodeBLockKind = ast.NewNodeKind(`reminder_code_block`)

func (b *_ReminderRendererBlock) Kind() ast.NodeKind {
return _reminderCodeBLockKind
}
func (b *_ReminderRendererBlock) Dump(source []byte, level int) {
b.ref.Dump(source, level)
}

func (r *Reminders) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(_reminderCodeBLockKind, r.renderCodeBlock)
}

// Transform implements parser.ASTTransformer.
func (r *Reminders) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
rCodeBlocks := []*ast.FencedCodeBlock{}
ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if entering && n.Kind() == ast.KindFencedCodeBlock {
cb := n.(*ast.FencedCodeBlock)
if cb.Info != nil {
info := string(cb.Info.Segment.Value(reader.Source()))
if info == `reminder` {
rCodeBlocks = append(rCodeBlocks, cb)
}
}
}
return ast.WalkContinue, nil
})
for _, cb := range rCodeBlocks {
cb.Parent().ReplaceChild(cb.Parent(), cb, &_ReminderRendererBlock{
ref: cb,
})
}
}

func (r *Reminders) renderCodeBlock(writer util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}

n = n.(*_ReminderRendererBlock).ref
b := bytes.NewBuffer(nil)
for i := 0; i < n.Lines().Len(); i++ {
line := n.Lines().At(i)
b.Write(line.Value(source))
}
y := b.Bytes()

rm := Reminder{}
if err := yaml.UnmarshalStrict(y, &rm); err != nil {
return ast.WalkStop, err
}

if err := tmpl.Execute(writer, &rm); err != nil {
return ast.WalkStop, err
}

return ast.WalkContinue, nil
}
11 changes: 11 additions & 0 deletions service/modules/renderers/reminders/reminder.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div class="reminder">
<div class="title">
{{ .Title }}
</div>
<div class="days">
{{ .Days }}
</div>
<div class="start">
开始时间:{{ .Start }}
</div>
</div>
19 changes: 19 additions & 0 deletions service/modules/renderers/reminders/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.reminder {
border: 1px solid var(--border-color);
display: inline-block;
padding: .5em 1em;
margin: 10px;

.title {
font-size: 1.5em;
font-weight: bold;
border-bottom: 1px solid var(--border-color);
text-align: center;
padding: 0 2em;
}
.days {
font-size: 3em;
color: var(--accent-color);
text-align: center;
}
}
35 changes: 35 additions & 0 deletions service/modules/renderers/reminders/task.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package reminders

import (
"time"

"github.com/movsb/taoblog/modules/utils"
)

type Task struct {
invalidate func(pid int64)
posts map[int64]struct{}
}

func NewTask(storage utils.PluginStorage, invalidate func(pid int64)) *Task {
t := &Task{
invalidate: invalidate,
}
go t.invalidatePosts()
return t
}

func (t *Task) AddReminder(pid int64) {
t.posts[pid] = struct{}{}
}

func (t *Task) invalidatePosts() {
for now := range time.Tick(time.Second) {
// TODO 这个时间可能不精确。比如进程挂起后?
if now.Hour() == 23 && now.Minute() == 59 && now.Second() == 59 {
for id := range t.posts {
t.invalidate(id)
}
}
}
}
2 changes: 2 additions & 0 deletions service/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
katex "github.com/movsb/taoblog/service/modules/renderers/math"
"github.com/movsb/taoblog/service/modules/renderers/media_size"
"github.com/movsb/taoblog/service/modules/renderers/media_tags"
"github.com/movsb/taoblog/service/modules/renderers/reminders"
"github.com/movsb/taoblog/service/modules/renderers/rooted_path"
"github.com/movsb/taoblog/service/modules/renderers/scoped_css"
task_list "github.com/movsb/taoblog/service/modules/renderers/tasklist"
Expand Down Expand Up @@ -317,6 +318,7 @@ func (s *Service) renderMarkdown(secure bool, postId, commentId int64, sourceTyp
wikitable.New(),
extension.GFM,
extension.NewFootnote(extension.WithFootnoteBacklinkHTML(`^`)),
reminders.New(s.remindersTask, int(postId)),

// 所有人禁止贴无效协议的链接。
invalid_scheme.New(),
Expand Down

0 comments on commit 529ec6c

Please sign in to comment.