太美了

美化文档格式,添加标题序号,调整样式等

  1. // ==UserScript==
  2. // @name 太美了
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1
  5. // @description 美化文档格式,添加标题序号,调整样式等
  6. // @author weihao2293
  7. // @match *://*.km.sankuai.com/*
  8. // @grant none
  9. // @license MIT
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14.  
  15. // 添加 iconfont 样式
  16. function addIconFont() {
  17. const style = document.createElement('style');
  18. style.textContent = `
  19. @font-face {
  20. font-family: "iconfont";
  21. src: url('//at.alicdn.com/t/font_1444750_kz0d4j05q4.eot');
  22. src: url('//at.alicdn.com/t/font_1444750_kz0d4j05q4.eot?#iefix') format('embedded-opentype'),
  23. url('//at.alicdn.com/t/font_1444750_kz0d4j05q4.woff2') format('woff2'),
  24. url('//at.alicdn.com/t/font_1444750_kz0d4j05q4.woff') format('woff'),
  25. url('//at.alicdn.com/t/font_1444750_kz0d4j05q4.ttf') format('truetype'),
  26. url('//at.alicdn.com/t/font_1444750_kz0d4j05q4.svg#iconfont') format('svg');
  27. }
  28. .iconfont {
  29. font-family: "iconfont" !important;
  30. font-size: 16px;
  31. font-style: normal;
  32. -webkit-font-smoothing: antialiased;
  33. -moz-osx-font-smoothing: grayscale;
  34. }
  35. .ct-icon-ai:before {
  36. content: "\\e65b"; /* 这是一个示例,需要替换为正确的图标编码 */
  37. }
  38. /* 添加折叠图标样式 */
  39. .heading-collapse-btn {
  40. display: inline-flex;
  41. align-items: center;
  42. justify-content: center;
  43. width: 16px;
  44. height: 16px;
  45. margin-right: 5px;
  46. cursor: pointer;
  47. transition: transform 0.3s;
  48. user-select: none;
  49. position: relative;
  50. top: -1px;
  51. vertical-align: middle;
  52. }
  53. .heading-collapse-btn::before {
  54. content: '▼';
  55. font-size: 12px;
  56. color: #666;
  57. line-height: 1;
  58. }
  59. .heading-collapse-btn.collapsed::before {
  60. content: '▶';
  61. }
  62. .content-collapsed {
  63. display: none !important;
  64. }
  65. `;
  66. document.head.appendChild(style);
  67. }
  68.  
  69. // 创建并添加按钮
  70. function createBeautifyButton() {
  71. const button = document.createElement('button');
  72. button.textContent = '太美了';
  73. button.style.cssText = `
  74. position: fixed;
  75. bottom: 20px;
  76. right: 20px;
  77. z-index: 9999;
  78. padding: 8px 20px;
  79. font-size: 13px;
  80. font-weight: 500;
  81. color: white;
  82. background: linear-gradient(90deg,
  83. #6631FF 0%,
  84. #A431FF 50%,
  85. #EE89FF 100%
  86. );
  87. border: none;
  88. border-radius: 100px;
  89. cursor: pointer;
  90. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  91. box-shadow: 0 0 5px rgba(156, 111, 228, 0.2);
  92. `;
  93.  
  94. // 添加动画关键帧到文档
  95. const style = document.createElement('style');
  96. style.textContent = `
  97. @keyframes glowing {
  98. from {
  99. box-shadow: 0 0 5px rgba(156, 111, 228, 0.2),
  100. 0 0 0.5px #fff,
  101. 0 0 2px #fff,
  102. 0 0 8px rgba(164, 49, 255, 0.5),
  103. 0 0 12px rgba(102, 49, 255, 0.3);
  104. }
  105. to {
  106. box-shadow: 0 0 8px rgba(156, 111, 228, 0.2),
  107. 0 0 1px #fff,
  108. 0 0 3px #fff,
  109. 0 0 15px rgba(164, 49, 255, 0.4),
  110. 0 0 25px rgba(102, 49, 255, 0.2);
  111. }
  112. }
  113. `;
  114. document.head.appendChild(style);
  115.  
  116. // 添加悬停效果
  117. button.onmouseenter = () => {
  118. button.style.transform = 'translateY(-2px) scale(1.05)';
  119. button.style.filter = 'brightness(1.2)';
  120. button.style.animation = 'glowing 1.5s ease-in-out infinite alternate';
  121. };
  122. button.onmouseleave = () => {
  123. button.style.transform = 'translateY(0) scale(1)';
  124. button.style.filter = 'brightness(1)';
  125. button.style.animation = 'none';
  126. button.style.boxShadow = '0 0 5px rgba(156, 111, 228, 0.2)';
  127. };
  128.  
  129. document.body.appendChild(button);
  130. return button;
  131. }
  132.  
  133. // 设置标准宽度
  134. function setStandardWidth() {
  135. window.widthType = 1;
  136. }
  137.  
  138. // 处理标题
  139. function processHeadings() {
  140. const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
  141. let currentNumbers = [0, 0, 0, 0, 0, 0]; // 用于跟踪每个级别的编号
  142.  
  143. // 找到最高级别和最低级别的标题
  144. let highestLevel = 6;
  145. let lowestLevel = 1;
  146. headings.forEach(heading => {
  147. const level = parseInt(heading.tagName[1]);
  148. highestLevel = Math.min(highestLevel, level);
  149. lowestLevel = Math.max(lowestLevel, level);
  150. });
  151.  
  152. // 添加新序号和分隔线
  153. headings.forEach((heading, index) => {
  154. // 移除已有的序号
  155. heading.innerHTML = heading.innerHTML.replace(/^[\d\.]+\s+/, '');
  156.  
  157. // 为除第一个标题外的所有标题添加分隔线,但只在没有分隔线时添加
  158. if (index > 0 && !heading.previousElementSibling?.matches('hr.ct-node-view-dom')) {
  159. const hr = document.createElement('hr');
  160. hr.className = 'ct-node-view-dom';
  161. hr.setAttribute('contenteditable', 'false');
  162. hr.style.display = 'block';
  163. heading.parentNode.insertBefore(hr, heading);
  164. }
  165.  
  166. // 处理标题内的所有 span 元素
  167. const spans = heading.querySelectorAll('span');
  168. spans.forEach(span => {
  169. // 移除背景色
  170. if (span.classList.contains('text-background-color')) {
  171. span.style.setProperty('background-color', 'transparent', 'important');
  172. span.classList.remove('text-background-color');
  173. }
  174. // 设置文字颜色为黑色
  175. span.style.setProperty('color', '#000000', 'important');
  176. });
  177.  
  178. // 获取标题文本内容(保留原有的 HTML 结构)
  179. const originalContent = heading.innerHTML;
  180.  
  181. // 计算相对级别(从1开始)
  182. const absoluteLevel = parseInt(heading.tagName[1]);
  183. const relativeLevel = absoluteLevel - highestLevel + 1;
  184. const totalLevels = lowestLevel - highestLevel + 1; // 总共有几级标题
  185.  
  186. // 生成序号
  187. let number = '';
  188. if (relativeLevel === 1) {
  189. // 最高级标题使用两位数字
  190. currentNumbers[0]++;
  191. // 重置所有子级编号
  192. for (let i = 1; i < totalLevels; i++) {
  193. currentNumbers[i] = 0;
  194. }
  195. number = String(currentNumbers[0]).padStart(2, '0');
  196. } else {
  197. // 子级标题
  198. currentNumbers[relativeLevel - 1]++;
  199. // 重置所有更低级别的编号
  200. for (let i = relativeLevel; i < totalLevels; i++) {
  201. currentNumbers[i] = 0;
  202. }
  203. // 生成序号:去掉前导零,然后添加子级序号
  204. number = currentNumbers[0] + currentNumbers.slice(1, relativeLevel)
  205. .map(num => '.' + num)
  206. .join('');
  207. }
  208.  
  209. // 添加序号
  210. heading.innerHTML = number + ' ' + originalContent;
  211.  
  212. // 添加折叠按钮
  213. const collapseBtn = document.createElement('span');
  214. collapseBtn.className = 'heading-collapse-btn';
  215. heading.insertBefore(collapseBtn, heading.firstChild);
  216.  
  217. // 添加点击事件
  218. collapseBtn.addEventListener('click', (e) => {
  219. e.stopPropagation();
  220. const currentLevel = parseInt(heading.tagName[1]);
  221. let element = heading.nextElementSibling;
  222. const isCollapsed = collapseBtn.classList.toggle('collapsed');
  223.  
  224. while (element) {
  225. // 如果遇到更高级别的标题,停止折叠
  226. if (element.tagName && /^H[1-6]$/.test(element.tagName)) {
  227. const elementLevel = parseInt(element.tagName[1]);
  228. if (elementLevel <= currentLevel) {
  229. break;
  230. }
  231. }
  232.  
  233. // 折叠或展开内容
  234. element.classList.toggle('content-collapsed', isCollapsed);
  235. element = element.nextElementSibling;
  236. }
  237. });
  238. });
  239. }
  240.  
  241. // 处理段落 - 只处理图片和状态标签相关的逻辑,不添加空行
  242. function processParagraphs() {
  243. const paragraphs = document.querySelectorAll('p');
  244. paragraphs.forEach(p => {
  245. // 跳过包含图片的段落和图片前面的段落
  246. if (p.querySelector('.pk-image') ||
  247. (p.nextElementSibling && p.nextElementSibling.querySelector('.pk-image'))) {
  248. return;
  249. }
  250.  
  251. // 跳过包含 pk-status 的段落
  252. if (p.querySelector('.pk-status') ||
  253. (p.nextElementSibling && p.nextElementSibling.querySelector('.pk-status'))) {
  254. return;
  255. }
  256. });
  257. }
  258.  
  259. // 主函数
  260. function beautifyDocument() {
  261. setStandardWidth();
  262. processHeadings();
  263. processParagraphs();
  264.  
  265. // 移除所有已有的折叠状态
  266. document.querySelectorAll('.content-collapsed').forEach(el => {
  267. el.classList.remove('content-collapsed');
  268. });
  269. }
  270.  
  271. // 初始化
  272. addIconFont();
  273. const beautifyButton = createBeautifyButton();
  274. beautifyButton.addEventListener('click', beautifyDocument);
  275. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址