Skip to content

Commit f7f968e

Browse files
authored
Merge pull request #2 from yyyCode/web-refactor
功能回归
2 parents 8d3b237 + f8a1109 commit f7f968e

80 files changed

Lines changed: 5930 additions & 881 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
name: frontend-design
3+
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
4+
license: Complete terms in LICENSE.txt
5+
---
6+
7+
This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
8+
9+
The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints.
10+
11+
## Design Thinking
12+
13+
Before coding, understand the context and commit to a BOLD aesthetic direction:
14+
- **Purpose**: What problem does this interface solve? Who uses it?
15+
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
16+
- **Constraints**: Technical requirements (framework, performance, accessibility).
17+
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
18+
19+
**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.
20+
21+
Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is:
22+
- Production-grade and functional
23+
- Visually striking and memorable
24+
- Cohesive with a clear aesthetic point-of-view
25+
- Meticulously refined in every detail
26+
27+
## Frontend Aesthetics Guidelines
28+
29+
Focus on:
30+
- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font.
31+
- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
32+
- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise.
33+
- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
34+
- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays.
35+
36+
NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character.
37+
38+
Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations.
39+
40+
**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.
41+
42+
Remember: Claude is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
name: frontend-design
3+
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
4+
license: Complete terms in LICENSE.txt
5+
---
6+
7+
This skill guides creation of distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
8+
9+
The user provides frontend requirements: a component, page, application, or interface to build. They may include context about the purpose, audience, or technical constraints.
10+
11+
## Design Thinking
12+
13+
Before coding, understand the context and commit to a BOLD aesthetic direction:
14+
- **Purpose**: What problem does this interface solve? Who uses it?
15+
- **Tone**: Pick an extreme: brutally minimal, maximalist chaos, retro-futuristic, organic/natural, luxury/refined, playful/toy-like, editorial/magazine, brutalist/raw, art deco/geometric, soft/pastel, industrial/utilitarian, etc. There are so many flavors to choose from. Use these for inspiration but design one that is true to the aesthetic direction.
16+
- **Constraints**: Technical requirements (framework, performance, accessibility).
17+
- **Differentiation**: What makes this UNFORGETTABLE? What's the one thing someone will remember?
18+
19+
**CRITICAL**: Choose a clear conceptual direction and execute it with precision. Bold maximalism and refined minimalism both work - the key is intentionality, not intensity.
20+
21+
Then implement working code (HTML/CSS/JS, React, Vue, etc.) that is:
22+
- Production-grade and functional
23+
- Visually striking and memorable
24+
- Cohesive with a clear aesthetic point-of-view
25+
- Meticulously refined in every detail
26+
27+
## Frontend Aesthetics Guidelines
28+
29+
Focus on:
30+
- **Typography**: Choose fonts that are beautiful, unique, and interesting. Avoid generic fonts like Arial and Inter; opt instead for distinctive choices that elevate the frontend's aesthetics; unexpected, characterful font choices. Pair a distinctive display font with a refined body font.
31+
- **Color & Theme**: Commit to a cohesive aesthetic. Use CSS variables for consistency. Dominant colors with sharp accents outperform timid, evenly-distributed palettes.
32+
- **Motion**: Use animations for effects and micro-interactions. Prioritize CSS-only solutions for HTML. Use Motion library for React when available. Focus on high-impact moments: one well-orchestrated page load with staggered reveals (animation-delay) creates more delight than scattered micro-interactions. Use scroll-triggering and hover states that surprise.
33+
- **Spatial Composition**: Unexpected layouts. Asymmetry. Overlap. Diagonal flow. Grid-breaking elements. Generous negative space OR controlled density.
34+
- **Backgrounds & Visual Details**: Create atmosphere and depth rather than defaulting to solid colors. Add contextual effects and textures that match the overall aesthetic. Apply creative forms like gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, decorative borders, custom cursors, and grain overlays.
35+
36+
NEVER use generic AI-generated aesthetics like overused font families (Inter, Roboto, Arial, system fonts), cliched color schemes (particularly purple gradients on white backgrounds), predictable layouts and component patterns, and cookie-cutter design that lacks context-specific character.
37+
38+
Interpret creatively and make unexpected choices that feel genuinely designed for the context. No design should be the same. Vary between light and dark themes, different fonts, different aesthetics. NEVER converge on common choices (Space Grotesk, for example) across generations.
39+
40+
**IMPORTANT**: Match implementation complexity to the aesthetic vision. Maximalist designs need elaborate code with extensive animations and effects. Minimalist or refined designs need restraint, precision, and careful attention to spacing, typography, and subtle details. Elegance comes from executing the vision well.
41+
42+
Remember: Claude is capable of extraordinary creative work. Don't hold back, show what can truly be created when thinking outside the box and committing fully to a distinctive vision.

OpenBlog-business/.mvn/wrapper/maven-wrapper.properties

Lines changed: 0 additions & 19 deletions
This file was deleted.

OpenBlog-business/pom.xml

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@
5151
</dependency>
5252

5353
<dependency>
54-
<groupId>org.springframework.boot</groupId>
55-
<artifactId>spring-boot-starter-data-redis</artifactId>
54+
<groupId>com.yqz</groupId>
55+
<artifactId>OpenBlog-framework-redis</artifactId>
56+
<version>${project.version}</version>
5657
</dependency>
5758

5859
<dependency>
@@ -85,6 +86,23 @@
8586
<version>0.4.20</version>
8687
</dependency>
8788

89+
<dependency>
90+
<groupId>io.minio</groupId>
91+
<artifactId>minio</artifactId>
92+
<version>8.5.17</version>
93+
</dependency>
94+
95+
<dependency>
96+
<groupId>com.vladsch.flexmark</groupId>
97+
<artifactId>flexmark-all</artifactId>
98+
<version>0.64.8</version>
99+
</dependency>
100+
101+
<dependency>
102+
<groupId>org.yaml</groupId>
103+
<artifactId>snakeyaml</artifactId>
104+
</dependency>
105+
88106
<dependency>
89107
<groupId>org.projectlombok</groupId>
90108
<artifactId>lombok</artifactId>

OpenBlog-business/src/main/java/com/yqz/openblog/OpenBlogApplication.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.yqz.openblog;
22

33
import com.yqz.openblog.config.AuthSecurityProperties;
4-
import com.yqz.openblog.config.CacheProperties;
54
import com.yqz.openblog.config.CorsProperties;
65
import com.yqz.openblog.config.SiteProperties;
76
import org.springframework.boot.SpringApplication;
@@ -14,8 +13,7 @@
1413
@EnableConfigurationProperties({
1514
SiteProperties.class,
1615
CorsProperties.class,
17-
AuthSecurityProperties.class,
18-
CacheProperties.class
16+
AuthSecurityProperties.class
1917
})
2018
public class OpenBlogApplication {
2119

OpenBlog-business/src/main/java/com/yqz/openblog/article/controller/ArticleController.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ public ArticleController(ArticleService articleService, CurrentUser currentUser)
3333
@GetMapping("/articles")
3434
public ApiResponse<PageResult<ArticleListItemResponse>> listPublished(
3535
@RequestParam(defaultValue = "0") int page,
36-
@RequestParam(defaultValue = "20") int size) {
37-
return ApiResponse.ok(articleService.listPublished(page, size));
36+
@RequestParam(defaultValue = "20") int size,
37+
@RequestParam(required = false) Long categoryId) {
38+
return ApiResponse.ok(articleService.listPublished(page, size, categoryId));
3839
}
3940

4041
@GetMapping("/articles/{articleId}")
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.yqz.openblog.article.controller;
2+
3+
import com.yqz.openblog.article.dto.ArticleListItemResponse;
4+
import com.yqz.openblog.article.service.ArticleImportExportService;
5+
import com.yqz.openblog.article.service.ArticleImportExportService.ArticleMarkdownExportPayload;
6+
import com.yqz.openblog.common.ApiResponse;
7+
import com.yqz.openblog.common.web.ClientIpResolver;
8+
import com.yqz.openblog.security.CurrentUser;
9+
import jakarta.servlet.http.HttpServletRequest;
10+
import org.springframework.http.ContentDisposition;
11+
import org.springframework.http.HttpHeaders;
12+
import org.springframework.http.MediaType;
13+
import org.springframework.http.ResponseEntity;
14+
import org.springframework.security.access.prepost.PreAuthorize;
15+
import org.springframework.web.bind.annotation.*;
16+
import org.springframework.web.multipart.MultipartFile;
17+
18+
import java.nio.charset.StandardCharsets;
19+
20+
@RestController
21+
@RequestMapping("/api/v1")
22+
@CrossOrigin(origins = "*")
23+
public class ArticleImportExportController {
24+
25+
private final ArticleImportExportService importExportService;
26+
private final CurrentUser currentUser;
27+
28+
public ArticleImportExportController(ArticleImportExportService importExportService, CurrentUser currentUser) {
29+
this.importExportService = importExportService;
30+
this.currentUser = currentUser;
31+
}
32+
33+
@PostMapping(value = "/articles/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
34+
@PreAuthorize("hasAnyRole('ADMIN','AUTHOR')")
35+
public ApiResponse<ArticleListItemResponse> importMarkdown(
36+
@RequestParam("file") MultipartFile file,
37+
@RequestParam(value = "mode", defaultValue = "create") String mode,
38+
@RequestParam(value = "articleId", required = false) Long articleId) {
39+
Long uid = currentUser.userId();
40+
return ApiResponse.ok(importExportService.importMarkdown(uid, file, mode, articleId));
41+
}
42+
43+
@GetMapping(value = "/users/me/articles/{articleId}/export", produces = "text/markdown")
44+
@PreAuthorize("hasAnyRole('ADMIN','AUTHOR')")
45+
public ResponseEntity<byte[]> exportMarkdown(@PathVariable("articleId") Long articleId,
46+
HttpServletRequest request) {
47+
Long uid = currentUser.userId();
48+
String clientIp = ClientIpResolver.resolve(request);
49+
ArticleMarkdownExportPayload payload = importExportService.exportMarkdown(uid, articleId, clientIp);
50+
ContentDisposition disposition = ContentDisposition.attachment()
51+
.filename(payload.filename(), StandardCharsets.UTF_8)
52+
.build();
53+
return ResponseEntity.ok()
54+
.header(HttpHeaders.CONTENT_DISPOSITION, disposition.toString())
55+
.contentType(new MediaType("text", "markdown", StandardCharsets.UTF_8))
56+
.body(payload.bytes());
57+
}
58+
}

OpenBlog-business/src/main/java/com/yqz/openblog/article/dto/ArticleDetailResponse.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class ArticleDetailResponse {
99
private String title;
1010
private String summary;
1111
private String contentMarkdown;
12+
private String contentHtml;
1213
private String coverMediaKey;
1314
private Long authorId;
1415
private String authorNickname;
@@ -20,6 +21,9 @@ public class ArticleDetailResponse {
2021
private Long commentCount;
2122
private Instant createdAt;
2223
private Instant updatedAt;
24+
private Long categoryId;
25+
private String categoryName;
26+
private java.util.List<String> categoryPath;
2327

2428
public Long getId() {
2529
return id;
@@ -53,6 +57,14 @@ public void setContentMarkdown(String contentMarkdown) {
5357
this.contentMarkdown = contentMarkdown;
5458
}
5559

60+
public String getContentHtml() {
61+
return contentHtml;
62+
}
63+
64+
public void setContentHtml(String contentHtml) {
65+
this.contentHtml = contentHtml;
66+
}
67+
5668
public String getCoverMediaKey() {
5769
return coverMediaKey;
5870
}
@@ -140,5 +152,29 @@ public Instant getUpdatedAt() {
140152
public void setUpdatedAt(Instant updatedAt) {
141153
this.updatedAt = updatedAt;
142154
}
155+
156+
public Long getCategoryId() {
157+
return categoryId;
158+
}
159+
160+
public void setCategoryId(Long categoryId) {
161+
this.categoryId = categoryId;
162+
}
163+
164+
public String getCategoryName() {
165+
return categoryName;
166+
}
167+
168+
public void setCategoryName(String categoryName) {
169+
this.categoryName = categoryName;
170+
}
171+
172+
public java.util.List<String> getCategoryPath() {
173+
return categoryPath;
174+
}
175+
176+
public void setCategoryPath(java.util.List<String> categoryPath) {
177+
this.categoryPath = categoryPath;
178+
}
143179
}
144180

OpenBlog-business/src/main/java/com/yqz/openblog/article/dto/ArticleListItemResponse.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ public class ArticleListItemResponse {
1717
private Long viewCount;
1818
private Long favoriteCount;
1919
private Long commentCount;
20+
private Long categoryId;
21+
private String categoryName;
22+
private java.util.List<String> categoryPath;
2023

2124
public Long getId() {
2225
return id;
@@ -113,5 +116,29 @@ public Long getCommentCount() {
113116
public void setCommentCount(Long commentCount) {
114117
this.commentCount = commentCount;
115118
}
119+
120+
public Long getCategoryId() {
121+
return categoryId;
122+
}
123+
124+
public void setCategoryId(Long categoryId) {
125+
this.categoryId = categoryId;
126+
}
127+
128+
public String getCategoryName() {
129+
return categoryName;
130+
}
131+
132+
public void setCategoryName(String categoryName) {
133+
this.categoryName = categoryName;
134+
}
135+
136+
public java.util.List<String> getCategoryPath() {
137+
return categoryPath;
138+
}
139+
140+
public void setCategoryPath(java.util.List<String> categoryPath) {
141+
this.categoryPath = categoryPath;
142+
}
116143
}
117144

0 commit comments

Comments
 (0)