mkdocs-document-dates 3.4__tar.gz → 3.4.5__tar.gz

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.
Files changed (41) hide show
  1. mkdocs_document_dates-3.4.5/PKG-INFO +101 -0
  2. mkdocs_document_dates-3.4.5/README.md +75 -0
  3. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/cache_manager.py +2 -2
  4. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/hooks_installer.py +14 -3
  5. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/plugin.py +115 -62
  6. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/config/user.config.js +1 -1
  7. mkdocs_document_dates-3.4.5/mkdocs_document_dates/static/templates/recently_updated.html +42 -0
  8. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/utils.py +88 -52
  9. mkdocs_document_dates-3.4.5/mkdocs_document_dates.egg-info/PKG-INFO +101 -0
  10. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates.egg-info/SOURCES.txt +2 -0
  11. mkdocs_document_dates-3.4.5/pyproject.toml +4 -0
  12. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/setup.py +2 -1
  13. mkdocs_document_dates-3.4/PKG-INFO +0 -240
  14. mkdocs_document_dates-3.4/README.md +0 -214
  15. mkdocs_document_dates-3.4/mkdocs_document_dates.egg-info/PKG-INFO +0 -240
  16. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/LICENSE +0 -0
  17. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/MANIFEST.in +0 -0
  18. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/__init__.py +0 -0
  19. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/hooks/pre-commit +0 -0
  20. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/config/user.config.css +0 -0
  21. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/core.css +0 -0
  22. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/core.js +0 -0
  23. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/default.config.js +0 -0
  24. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/timeago.full.min.js +0 -0
  25. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/timeago.min.js +0 -0
  26. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/core/utils.js +0 -0
  27. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/fonts/material-icons.css +0 -0
  28. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/fonts/materialicons.woff2 +0 -0
  29. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/backdrop.css +0 -0
  30. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/light.css +0 -0
  31. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/material.css +0 -0
  32. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/popper.min.js +0 -0
  33. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/scale.css +0 -0
  34. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/shift-away.css +0 -0
  35. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/tippy.css +0 -0
  36. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates/static/tippy/tippy.umd.min.js +0 -0
  37. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates.egg-info/dependency_links.txt +0 -0
  38. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates.egg-info/entry_points.txt +0 -0
  39. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates.egg-info/requires.txt +0 -0
  40. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/mkdocs_document_dates.egg-info/top_level.txt +0 -0
  41. {mkdocs_document_dates-3.4 → mkdocs_document_dates-3.4.5}/setup.cfg +0 -0
@@ -0,0 +1,101 @@
1
+ Metadata-Version: 2.4
2
+ Name: mkdocs-document-dates
3
+ Version: 3.4.5
4
+ Summary: A new generation MkDocs plugin for displaying exact creation time, last update time, authors, email of documents
5
+ Home-page: https://github.com/jaywhj/mkdocs-document-dates
6
+ Author: Aaron Wang
7
+ Author-email: aaronwqt@gmail.com
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.7
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: mkdocs>=1.1.0
15
+ Dynamic: author
16
+ Dynamic: author-email
17
+ Dynamic: classifier
18
+ Dynamic: description
19
+ Dynamic: description-content-type
20
+ Dynamic: home-page
21
+ Dynamic: license
22
+ Dynamic: license-file
23
+ Dynamic: requires-dist
24
+ Dynamic: requires-python
25
+ Dynamic: summary
26
+
27
+ # mkdocs-document-dates
28
+
29
+ English | [简体中文](README_zh.md)
30
+
31
+ <br />
32
+
33
+ A new generation MkDocs plugin for displaying exact **creation time, last update time, authors, email** of documents
34
+
35
+ ![render](render.gif)
36
+
37
+ ## Features
38
+
39
+ - [x] Always displays **exact** meta information of the document and works in any environment (no Git, Git environments, Docker containers, all CI/CD build systems, etc.)
40
+ - [x] Support for manually specifying time and author in `Front Matter`
41
+ - [x] Support for multiple time formats (date, datetime, timeago)
42
+ - [x] Support for multiple author modes (avatar, text, hidden)
43
+ - [x] Flexible display position (top or bottom)
44
+ - [x] Elegant styling (fully customizable)
45
+ - [x] Smart Tooltip Hover Tips
46
+ - [x] Support list display of recently updated documents
47
+ - [x] Multi-language support, localization support, intelligent recognition of user language, automatic adaptation
48
+ - [x] Cross-platform support (Windows, macOS, Linux)
49
+ - [x] **Ultimate build efficiency**: O(1), no need to set env vars to distinguish runs
50
+
51
+ | PK of Build Efficiency: | 100 md: | 1000 md: | Time Complexity: |
52
+ | --------------------------- | :-----: | :------: | :----------: |
53
+ | git-revision-date-localized | > 3 s | > 30 s | O(n) |
54
+ | document-dates | < 0.1 s | < 0.15 s | O(1) |
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ pip install mkdocs-document-dates
60
+ ```
61
+
62
+ ## Configuration
63
+
64
+ Just add the plugin to your `mkdocs.yml`:
65
+
66
+ ```yaml
67
+ plugins:
68
+ - document-dates
69
+ ```
70
+
71
+ Or, full configuration:
72
+
73
+ ```yaml
74
+ plugins:
75
+ - document-dates:
76
+ position: top # Display position: top(after title) bottom(end of document)
77
+ type: date # Date type: date datetime timeago, default: date
78
+ exclude: # List of excluded files
79
+ - temp.md # Example: exclude the specified file
80
+ - blog/* # Example: exclude all files in blog folder, including subfolders
81
+ date_format: '%Y-%m-%d' # Date format strings (e.g., %Y-%m-%d, %b %d, %Y)
82
+ time_format: '%H:%M:%S' # Time format strings (valid only if type=datetime)
83
+ show_author: true # Author display mode: true(avatar) text(text) false(hidden)
84
+ recently-updated: true # Whether to turn on recently updated data, default: false
85
+ ```
86
+
87
+ ## Customization Settings
88
+
89
+ In addition to the above basic configuration, the plug-in also provides a wealth of customization options to meet a variety of individual needs:
90
+
91
+ - [Specify Datetime](https://jaywhj.netlify.app/document-dates-en#Specify-Datetime): You can manually specify the creation time and last update time for each document
92
+ - [Specify Author](https://jaywhj.netlify.app/document-dates-en#Specify-Author): You can manually specify the author information for each document
93
+ - [Specify Avatar](https://jaywhj.netlify.app/document-dates-en#Specify-Avatar): You can manually specify the avatar for each author
94
+ - [Set Plugin Style](https://jaywhj.netlify.app/document-dates-en#Set-Plugin-Style): Such as icons, themes, colors, fonts, animations, dividing line, etc.
95
+ - [Add Localization Language](https://jaywhj.netlify.app/document-dates-en#Add-Localization-Language): More localization languages for `timeago` and `tooltip`
96
+ - [Use Template Variables](https://jaywhj.netlify.app/document-dates-en#Use-Template-Variables): Can be used to optimize `sitemap.xml` for site SEO, can be used to re-customize plug-ins, etc.
97
+ - [Add Recently Updated Module](https://jaywhj.netlify.app/document-dates-en#Add-Recently-Updated-Module): Enable list of recently updated documents
98
+ - [Other Tips](https://jaywhj.netlify.app/document-dates-en#Other-Tips): Introduction to technical principles, caching mechanisms, and how to use it in Docker
99
+ - [Development Stories](https://jaywhj.netlify.app/document-dates-en#Development-Stories): Describes the origin of the plug-in, the difficulties and solutions encountered in development, and the principles and directions of product design
100
+
101
+ See the documentation for details: https://jaywhj.netlify.app/document-dates-en
@@ -0,0 +1,75 @@
1
+ # mkdocs-document-dates
2
+
3
+ English | [简体中文](README_zh.md)
4
+
5
+ <br />
6
+
7
+ A new generation MkDocs plugin for displaying exact **creation time, last update time, authors, email** of documents
8
+
9
+ ![render](render.gif)
10
+
11
+ ## Features
12
+
13
+ - [x] Always displays **exact** meta information of the document and works in any environment (no Git, Git environments, Docker containers, all CI/CD build systems, etc.)
14
+ - [x] Support for manually specifying time and author in `Front Matter`
15
+ - [x] Support for multiple time formats (date, datetime, timeago)
16
+ - [x] Support for multiple author modes (avatar, text, hidden)
17
+ - [x] Flexible display position (top or bottom)
18
+ - [x] Elegant styling (fully customizable)
19
+ - [x] Smart Tooltip Hover Tips
20
+ - [x] Support list display of recently updated documents
21
+ - [x] Multi-language support, localization support, intelligent recognition of user language, automatic adaptation
22
+ - [x] Cross-platform support (Windows, macOS, Linux)
23
+ - [x] **Ultimate build efficiency**: O(1), no need to set env vars to distinguish runs
24
+
25
+ | PK of Build Efficiency: | 100 md: | 1000 md: | Time Complexity: |
26
+ | --------------------------- | :-----: | :------: | :----------: |
27
+ | git-revision-date-localized | > 3 s | > 30 s | O(n) |
28
+ | document-dates | < 0.1 s | < 0.15 s | O(1) |
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install mkdocs-document-dates
34
+ ```
35
+
36
+ ## Configuration
37
+
38
+ Just add the plugin to your `mkdocs.yml`:
39
+
40
+ ```yaml
41
+ plugins:
42
+ - document-dates
43
+ ```
44
+
45
+ Or, full configuration:
46
+
47
+ ```yaml
48
+ plugins:
49
+ - document-dates:
50
+ position: top # Display position: top(after title) bottom(end of document)
51
+ type: date # Date type: date datetime timeago, default: date
52
+ exclude: # List of excluded files
53
+ - temp.md # Example: exclude the specified file
54
+ - blog/* # Example: exclude all files in blog folder, including subfolders
55
+ date_format: '%Y-%m-%d' # Date format strings (e.g., %Y-%m-%d, %b %d, %Y)
56
+ time_format: '%H:%M:%S' # Time format strings (valid only if type=datetime)
57
+ show_author: true # Author display mode: true(avatar) text(text) false(hidden)
58
+ recently-updated: true # Whether to turn on recently updated data, default: false
59
+ ```
60
+
61
+ ## Customization Settings
62
+
63
+ In addition to the above basic configuration, the plug-in also provides a wealth of customization options to meet a variety of individual needs:
64
+
65
+ - [Specify Datetime](https://jaywhj.netlify.app/document-dates-en#Specify-Datetime): You can manually specify the creation time and last update time for each document
66
+ - [Specify Author](https://jaywhj.netlify.app/document-dates-en#Specify-Author): You can manually specify the author information for each document
67
+ - [Specify Avatar](https://jaywhj.netlify.app/document-dates-en#Specify-Avatar): You can manually specify the avatar for each author
68
+ - [Set Plugin Style](https://jaywhj.netlify.app/document-dates-en#Set-Plugin-Style): Such as icons, themes, colors, fonts, animations, dividing line, etc.
69
+ - [Add Localization Language](https://jaywhj.netlify.app/document-dates-en#Add-Localization-Language): More localization languages for `timeago` and `tooltip`
70
+ - [Use Template Variables](https://jaywhj.netlify.app/document-dates-en#Use-Template-Variables): Can be used to optimize `sitemap.xml` for site SEO, can be used to re-customize plug-ins, etc.
71
+ - [Add Recently Updated Module](https://jaywhj.netlify.app/document-dates-en#Add-Recently-Updated-Module): Enable list of recently updated documents
72
+ - [Other Tips](https://jaywhj.netlify.app/document-dates-en#Other-Tips): Introduction to technical principles, caching mechanisms, and how to use it in Docker
73
+ - [Development Stories](https://jaywhj.netlify.app/document-dates-en#Development-Stories): Describes the origin of the plug-in, the difficulties and solutions encountered in development, and the principles and directions of product design
74
+
75
+ See the documentation for details: https://jaywhj.netlify.app/document-dates-en
@@ -11,7 +11,7 @@ def find_mkdocs_projects():
11
11
  try:
12
12
  git_root = Path(subprocess.check_output(
13
13
  ['git', 'rev-parse', '--show-toplevel'],
14
- text=True, encoding='utf-8'
14
+ encoding='utf-8'
15
15
  ).strip())
16
16
 
17
17
  # 遍历 git_root 及子目录, 寻找 mkdocs.yml 文件
@@ -65,7 +65,7 @@ def update_cache():
65
65
 
66
66
  # 获取docs目录下已跟踪(tracked)的markdown文件
67
67
  cmd = ["git", "ls-files", "*.md"]
68
- result = subprocess.run(cmd, cwd=docs_dir, capture_output=True, text=True)
68
+ result = subprocess.run(cmd, cwd=docs_dir, capture_output=True, encoding='utf-8')
69
69
  tracked_files = result.stdout.splitlines() if result.stdout else []
70
70
 
71
71
  if not tracked_files:
@@ -12,13 +12,20 @@ def get_config_dir():
12
12
  if platform.system().lower().startswith('win'):
13
13
  return Path(os.getenv('APPDATA', str(Path.home() / 'AppData' / 'Roaming')))
14
14
  else:
15
- return Path.home() / '.config'
15
+ # 优先级:XDG_CONFIG_HOME > $HOME/.config > cwd/.config
16
+ xdg_config = os.getenv('XDG_CONFIG_HOME')
17
+ if xdg_config:
18
+ return Path(xdg_config)
19
+ home = os.getenv('HOME')
20
+ if home:
21
+ return Path(home) / '.config'
22
+ return Path.cwd() / '.config'
16
23
 
17
24
  def check_python_version(interpreter):
18
25
  try:
19
26
  result = subprocess.run(
20
27
  [interpreter, "-c", "import sys; print(sys.version_info >= (3, 7))"],
21
- capture_output=True, text=True)
28
+ capture_output=True, encoding='utf-8')
22
29
  if result.returncode == 0 and result.stdout.strip().lower() == 'true':
23
30
  return True
24
31
  else:
@@ -44,7 +51,11 @@ def setup_hooks_directory():
44
51
  os.chmod(config_dir, 0o755)
45
52
  return config_dir
46
53
  except PermissionError:
47
- logger.error(f"No permission to create directory: {config_dir}")
54
+ logger.error(
55
+ f"No permission to create directory: {config_dir}\n"
56
+ "If running inside Docker, please set environment variable HOME=/docs "
57
+ "or XDG_CONFIG_HOME to a writable path."
58
+ )
48
59
  except Exception as e:
49
60
  logger.error(f"Failed to create directory {config_dir}: {str(e)}")
50
61
  return None
@@ -2,13 +2,14 @@ import os
2
2
  import yaml
3
3
  import shutil
4
4
  import logging
5
+ from jinja2 import Environment, FileSystemLoader, select_autoescape
5
6
  from datetime import datetime
6
7
  from pathlib import Path
7
8
  from mkdocs.plugins import BasePlugin
8
9
  from mkdocs.config import config_options
9
10
  from mkdocs.structure.pages import Page
10
11
  from urllib.parse import urlparse
11
- from .utils import get_file_creation_time, load_git_cache, read_jsonl_cache,is_excluded, get_recently_modified_files
12
+ from .utils import get_file_creation_time, load_git_cache, read_jsonl_cache,is_excluded, get_recently_updated_files
12
13
 
13
14
  logger = logging.getLogger("mkdocs.plugins.document_dates")
14
15
  logger.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, CRITICAL
@@ -40,17 +41,20 @@ class DocumentDatesPlugin(BasePlugin):
40
41
  ('time_format', config_options.Type(str, default='%H:%M:%S')),
41
42
  ('position', config_options.Type(str, default='top')),
42
43
  ('exclude', config_options.Type(list, default=[])),
43
- ('created_field_names', config_options.Type(list, default=['created', 'date', 'creation'])),
44
- ('modified_field_names', config_options.Type(list, default=['modified', 'updated', 'last_modified', 'last_updated'])),
45
- ('show_author', config_options.Type(bool, default=True)),
44
+ ('created_field_names', config_options.Type(list, default=['created', 'date'])),
45
+ ('modified_field_names', config_options.Type(list, default=['modified', 'updated'])),
46
+ ('show_author', config_options.Choice((True, False, 'text'), default=True)),
46
47
  ('recently-updated', config_options.Type((dict, bool), default={}))
47
48
  )
48
49
 
49
50
  def __init__(self):
50
51
  super().__init__()
51
52
  self.dates_cache = {}
53
+ self.last_updated_dates = {}
52
54
  self.authors_yml = {}
53
55
  self.github_username = None
56
+ self.recent_docs_html = None
57
+ self.recent_enable = False
54
58
 
55
59
  def on_config(self, config):
56
60
  docs_dir_path = Path(config['docs_dir'])
@@ -70,7 +74,7 @@ class DocumentDatesPlugin(BasePlugin):
70
74
 
71
75
  # 加载 git 缓存
72
76
  self.dates_cache = load_git_cache(docs_dir_path)
73
- # 加载 jsonl 缓存覆盖
77
+ # 覆盖 jsonl 文件缓存
74
78
  jsonl_cache_file = docs_dir_path / '.dates_cache.jsonl'
75
79
  if jsonl_cache_file.exists():
76
80
  jsonl_cache = read_jsonl_cache(jsonl_cache_file)
@@ -78,35 +82,9 @@ class DocumentDatesPlugin(BasePlugin):
78
82
  if filename in self.dates_cache:
79
83
  self.dates_cache[filename].update(new_info)
80
84
 
81
- """
82
- Tippy.js, for Tooltip
83
- # core
84
- https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js
85
- https://unpkg.com/tippy.js@6/dist/tippy.umd.min.js
86
- https://unpkg.com/tippy.js@6/dist/tippy.css
87
- # animations
88
- https://unpkg.com/tippy.js@6/animations/scale.css
89
- # animations: Material filling effect
90
- https://unpkg.com/tippy.js@6/dist/backdrop.css
91
- https://unpkg.com/tippy.js@6/animations/shift-away.css
92
- # themes
93
- https://unpkg.com/tippy.js@6/themes/light.css
94
- https://unpkg.com/tippy.js@6/themes/material.css
95
- """
96
- # 复制静态资源到用户目录
85
+ # 复制配置文件到用户目录(如果不存在)
97
86
  dest_dir = docs_dir_path / 'assets' / 'document_dates'
98
87
  dest_dir.mkdir(parents=True, exist_ok=True)
99
-
100
- for dir_name in ['tippy', 'core', 'fonts']:
101
- source_dir = Path(__file__).parent / 'static' / dir_name
102
- target_dir = dest_dir / dir_name
103
- # shutil.copytree(source_dir, target_dir, dirs_exist_ok=True)
104
- target_dir.mkdir(parents=True, exist_ok=True)
105
- for item in source_dir.iterdir():
106
- if item.is_file():
107
- shutil.copy2(item, target_dir / item.name)
108
-
109
- # 复制配置文件模板到用户目录(如果不存在)
110
88
  config_files = ['user.config.css', 'user.config.js']
111
89
  for config_file in config_files:
112
90
  source_config = Path(__file__).parent / 'static' / 'config' / config_file
@@ -114,35 +92,49 @@ class DocumentDatesPlugin(BasePlugin):
114
92
  if not target_config.exists():
115
93
  shutil.copy2(source_config, target_config)
116
94
 
117
- # 加载离线 Google Fonts Icons: https://fonts.google.com/icons
95
+ # 添加离线 Google Fonts Icons: https://fonts.google.com/icons
118
96
  # material_icons_url = 'https://fonts.googleapis.com/icon?family=Material+Icons'
119
97
  material_icons_url = 'assets/document_dates/fonts/material-icons.css'
120
- if material_icons_url not in config['extra_css']:
121
- config['extra_css'].append(material_icons_url)
122
-
123
- # 加载 timeago.js
98
+ config['extra_css'].append(material_icons_url)
99
+
100
+ # 添加 timeago.js
124
101
  # https://cdn.jsdelivr.net/npm/timeago.js@4.0.2/dist/timeago.min.js
125
102
  # https://cdnjs.cloudflare.com/ajax/libs/timeago.js/4.0.2/timeago.full.min.js
126
103
  if self.config['type'] == 'timeago':
127
104
  config['extra_javascript'].insert(0, 'assets/document_dates/core/timeago.min.js')
128
105
 
129
- # 加载 Tippy CSS 文件
130
- tippy_css_dir = dest_dir / 'tippy'
106
+ """
107
+ Tippy.js, for Tooltip
108
+ # core
109
+ https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js
110
+ https://unpkg.com/tippy.js@6/dist/tippy.umd.min.js
111
+ https://unpkg.com/tippy.js@6/dist/tippy.css
112
+ # animations
113
+ https://unpkg.com/tippy.js@6/animations/scale.css
114
+ # animations: Material filling effect
115
+ https://unpkg.com/tippy.js@6/dist/backdrop.css
116
+ https://unpkg.com/tippy.js@6/animations/shift-away.css
117
+ # themes
118
+ https://unpkg.com/tippy.js@6/themes/light.css
119
+ https://unpkg.com/tippy.js@6/themes/material.css
120
+ """
121
+ # 添加 Tippy CSS 文件
122
+ tippy_css_dir = Path(__file__).parent / 'static' / 'tippy'
131
123
  for css_file in tippy_css_dir.glob('*.css'):
132
124
  config['extra_css'].append(f'assets/document_dates/tippy/{css_file.name}')
133
125
 
134
- # 加载自定义 CSS 文件
126
+ # 添加自定义 CSS 文件
135
127
  config['extra_css'].extend([
136
128
  'assets/document_dates/core/core.css',
137
129
  'assets/document_dates/user.config.css'
138
130
  ])
139
131
 
140
- # 按顺序加载 Tippy JS 文件
132
+ # 按顺序添加 Tippy JS 文件
141
133
  js_core_files = ['popper.min.js', 'tippy.umd.min.js']
142
134
  for js_file in js_core_files:
143
135
  config['extra_javascript'].append(f'assets/document_dates/tippy/{js_file}')
144
136
 
145
- # 加载自定义 JS 文件
137
+ # 添加自定义 JS 文件
146
138
  config['extra_javascript'].extend([
147
139
  'assets/document_dates/core/default.config.js',
148
140
  'assets/document_dates/user.config.js',
@@ -154,8 +146,8 @@ class DocumentDatesPlugin(BasePlugin):
154
146
 
155
147
  def on_nav(self, nav, config, files):
156
148
  recently_updated_config = self.config.get('recently-updated')
157
- if not recently_updated_config:
158
- return nav
149
+ if recently_updated_config:
150
+ self.recent_enable = True
159
151
 
160
152
  # 兼容 true 配置
161
153
  if recently_updated_config is True:
@@ -164,17 +156,48 @@ class DocumentDatesPlugin(BasePlugin):
164
156
  # 获取配置
165
157
  exclude_list = recently_updated_config.get('exclude', [])
166
158
  limit = recently_updated_config.get('limit', 10)
159
+ template_path = recently_updated_config.get('template')
167
160
 
168
- # 获取 docs 目录下最近更新的文档
169
- recently_modified_files = get_recently_modified_files(files, exclude_list, limit)
161
+ # 获取最近更新日期和最近更新的文档数据
162
+ docs_dir = Path(config['docs_dir'])
163
+ self.last_updated_dates, recently_updated_docs = get_recently_updated_files(docs_dir, files, exclude_list, limit, self.recent_enable)
170
164
 
171
165
  # 将数据注入到 config['extra'] 中供全局访问
172
166
  if 'extra' not in config:
173
167
  config['extra'] = {}
174
- config['extra']['recently_updated_docs'] = recently_modified_files
168
+ config['extra']['recently_updated_docs'] = recently_updated_docs
169
+
170
+ # 渲染HTML
171
+ if self.recent_enable:
172
+ self.recent_docs_html = self._render_recently_updated_html(docs_dir, template_path, recently_updated_docs)
175
173
 
176
174
  return nav
177
175
 
176
+ def _render_recently_updated_html(self, docs_dir, template_path, recently_updated_data):
177
+ # 获取自定义模板路径
178
+ if template_path:
179
+ user_full_path = docs_dir / template_path
180
+
181
+ # 选择模板路径
182
+ if template_path and user_full_path.is_file():
183
+ template_dir = user_full_path.parent
184
+ template_file = user_full_path.name
185
+ else:
186
+ # 默认模板路径
187
+ default_template_path = Path(__file__).parent / 'static' / 'templates' / 'recently_updated.html'
188
+ template_dir = default_template_path.parent
189
+ template_file = default_template_path.name
190
+
191
+ # 加载模板
192
+ env = Environment(
193
+ loader=FileSystemLoader(str(template_dir)),
194
+ autoescape=select_autoescape(["html", "xml"])
195
+ )
196
+ template = env.get_template(template_file)
197
+
198
+ # 渲染模板
199
+ return template.render(recent_docs=recently_updated_data)
200
+
178
201
  def on_page_markdown(self, markdown, page: Page, config, files):
179
202
  # 获取相对路径,src_uri 总是以"/"分隔
180
203
  rel_path = getattr(page.file, 'src_uri', page.file.src_path)
@@ -188,7 +211,7 @@ class DocumentDatesPlugin(BasePlugin):
188
211
  if not created:
189
212
  created = self._get_file_creation_time(file_path, rel_path)
190
213
  if not modified:
191
- modified = self._get_file_modification_time(file_path)
214
+ modified = self._get_file_modification_time(file_path, rel_path)
192
215
 
193
216
  # 获取作者信息
194
217
  authors = self._get_author_info(rel_path, page, config)
@@ -198,6 +221,10 @@ class DocumentDatesPlugin(BasePlugin):
198
221
  page.meta['document_dates_modified'] = modified.isoformat()
199
222
  page.meta['document_dates_authors'] = authors
200
223
 
224
+ # 占位符替换
225
+ if self.recent_enable and '\n<!-- RECENTLY_UPDATED_DOCS -->' in markdown:
226
+ markdown = markdown.replace('\n<!-- RECENTLY_UPDATED_DOCS -->', self.recent_docs_html or '')
227
+
201
228
  # 检查是否需要排除
202
229
  if is_excluded(rel_path, self.config['exclude']):
203
230
  return markdown
@@ -208,6 +235,16 @@ class DocumentDatesPlugin(BasePlugin):
208
235
  # 将信息写入 markdown
209
236
  return self._insert_date_info(markdown, info_html)
210
237
 
238
+ def on_post_build(self, config):
239
+ site_dest_dir = Path(config['site_dir']) / 'assets' / 'document_dates'
240
+ for dir_name in ['tippy', 'core', 'fonts']:
241
+ source_dir = Path(__file__).parent / 'static' / dir_name
242
+ target_dir = site_dest_dir / dir_name
243
+ # shutil.copytree(source_dir, target_dir, dirs_exist_ok=True)
244
+ target_dir.mkdir(parents=True, exist_ok=True)
245
+ for item in source_dir.iterdir():
246
+ if item.is_file():
247
+ shutil.copy2(item, target_dir / item.name)
211
248
 
212
249
  def _extract_github_username(self, url):
213
250
  try:
@@ -257,7 +294,10 @@ class DocumentDatesPlugin(BasePlugin):
257
294
  # 从文件系统获取
258
295
  return get_file_creation_time(file_path).astimezone()
259
296
 
260
- def _get_file_modification_time(self, file_path):
297
+ def _get_file_modification_time(self, file_path, rel_path):
298
+ # 优先从缓存中读取
299
+ if rel_path in self.last_updated_dates:
300
+ return datetime.fromtimestamp(self.last_updated_dates[rel_path]).astimezone()
261
301
  # 从文件系统获取最后修改时间
262
302
  stat = os.stat(file_path)
263
303
  return datetime.fromtimestamp(stat.st_mtime).astimezone()
@@ -348,9 +388,9 @@ class DocumentDatesPlugin(BasePlugin):
348
388
  if self.config['show_author'] and authors:
349
389
  def get_author_tooltip(author):
350
390
  if author.url:
351
- return f'&lt;a href="{author.url}" target="_blank"&gt;{author.name}&lt;/a&gt;'
391
+ return f'<a href="{author.url}" target="_blank">{author.name}</a>'
352
392
  elif author.email:
353
- return f'&lt;a href="mailto:{author.email}"&gt;{author.name}&lt;/a&gt;'
393
+ return f'<a href="mailto:{author.email}">{author.name}</a>'
354
394
  return author.name
355
395
 
356
396
  def get_avatar_img_url(author):
@@ -360,19 +400,32 @@ class DocumentDatesPlugin(BasePlugin):
360
400
  return f"https://avatars.githubusercontent.com/{self.github_username}"
361
401
  return ""
362
402
 
363
- icon = 'doc_author' if len(authors) == 1 else 'doc_authors'
364
- html_parts.append(f"<span class='material-icons' data-icon='{icon}'></span>")
365
- html_parts.append("<div class='avatar-group'>")
366
- for author in authors:
367
- tooltip = get_author_tooltip(author)
368
- img_url = get_avatar_img_url(author)
403
+ if self.config['show_author'] == 'text':
404
+ # 显示文本模式
405
+ tooltip_text = ',&nbsp;'.join(get_author_tooltip(author) for author in authors)
406
+ author_text = ', '.join(author.name for author in authors)
407
+ icon = 'doc_author' if len(authors) == 1 else 'doc_authors'
369
408
  html_parts.append(
370
- f"<div class='avatar-wrapper' data-name='{author.name}' data-tippy-content data-tippy-raw='{tooltip}'>"
371
- f"<span class='avatar-text'></span>"
372
- f"<img class='avatar' src='{img_url}' />"
373
- f"</div>"
409
+ f"<span data-tippy-content data-tippy-raw='{tooltip_text}'>"
410
+ f"<span class='material-icons' data-icon='{icon}'></span>"
411
+ f"{author_text}"
412
+ f"</span>"
374
413
  )
375
- html_parts.append("</div>")
414
+ else:
415
+ # 显示头像模式(默认)
416
+ icon = 'doc_author' if len(authors) == 1 else 'doc_authors'
417
+ html_parts.append(f"<span class='material-icons' data-icon='{icon}'></span>")
418
+ html_parts.append("<div class='avatar-group'>")
419
+ for author in authors:
420
+ tooltip = get_author_tooltip(author)
421
+ img_url = get_avatar_img_url(author)
422
+ html_parts.append(
423
+ f"<div class='avatar-wrapper' data-name='{author.name}' data-tippy-content data-tippy-raw='{tooltip}'>"
424
+ f"<span class='avatar-text'></span>"
425
+ f"<img class='avatar' src='{img_url}' />"
426
+ f"</div>"
427
+ )
428
+ html_parts.append("</div>")
376
429
 
377
430
  html_parts.append("</div></div>")
378
431
  return ''.join(html_parts)
@@ -33,7 +33,7 @@ TooltipConfig.setConfig({
33
33
 
34
34
  /*
35
35
  Part 2:
36
- Demonstrates how to register a local language when using 'timeago.js',
36
+ Demonstrates how to register a local language for 'timeago.js',
37
37
  then you can configure the localeStr you just registered anywhere!
38
38
  */
39
39
  /*
@@ -0,0 +1,42 @@
1
+ <style>
2
+ .recently-updated {
3
+ display: grid;
4
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
5
+ gap: 10px;
6
+ margin: 0;
7
+ padding: 16px;
8
+ border: 1px solid rgba(142, 142, 142, 0.15);
9
+ border-radius: 4px;
10
+ font-family: system-ui, sans-serif;
11
+ }
12
+ .recently-updated-item {
13
+ display: flex;
14
+ align-items: center;
15
+ }
16
+ .recently-updated-item span {
17
+ font-size: 0.85em;
18
+ color: rgba(142, 142, 142, 0.5);
19
+ margin-right: 8px;
20
+ flex-shrink: 0;
21
+ width: 90px;
22
+ }
23
+ .recently-updated-item a {
24
+ overflow: hidden;
25
+ text-overflow: ellipsis;
26
+ white-space: nowrap;
27
+ color: #0077cc;
28
+ text-decoration: none;
29
+ transition: color 0.2s ease;
30
+ }
31
+ .recently-updated-item a:hover {
32
+ text-decoration: underline;
33
+ }
34
+ </style>
35
+ <div class="recently-updated">
36
+ {%- for mtime, rel_path, title, url in recent_docs %}
37
+ <div class="recently-updated-item">
38
+ <span>{{ mtime[:10] }}</span>
39
+ <a href="{{ url }}" target="_blank">{{ title }}</a>
40
+ </div>
41
+ {%- endfor %}
42
+ </div>