feat: add custom publish time and last updated time display
- Add custom publish time field to article create/edit forms - Support datetime-local input for manual time setting - Auto-set on first publish if left blank - Works for both admin and user article forms - Display last updated time on article detail page - Show both published time and last updated time - Auto-maintained by GORM on each update - Format: YYYY-MM-DD HH:MM - Add i18n support for new fields - article_published_at: Published Time / 发布时间 - article_published_at_hint: Leave blank to auto-set on publish / 留空则在发布时自动设置 - article_last_updated: Last Updated / 最后更新 - Update handlers and templates - handlers/article.go: Add parsePublishedAt/formatPublishedAt functions - handlers/home.go: Add formatUpdateTime function - handlers/my_articles.go: Support custom publish time in user articles - templates: Add datetime-local inputs and time display Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# 文章详情页显示最后更新时间功能
|
||||
|
||||
## 功能概述
|
||||
|
||||
为文章详情页添加了最后更新时间的显示,让读者可以看到文章的发布时间和最后修改时间。
|
||||
|
||||
## 修改的文件
|
||||
|
||||
### 1. 前端模板
|
||||
|
||||
#### `/templates/pages/article.html`
|
||||
- 修改了文章元信息显示部分(第24-33行)
|
||||
- 将原来的单一时间戳改为显示两个时间:
|
||||
- **发布时间**:文章首次发布的时间(`PublishedAt`)
|
||||
- **最后更新**:文章最后修改的时间(`UpdatedAt`)
|
||||
- 使用条件判断确保只在有值时显示
|
||||
|
||||
显示格式:
|
||||
```
|
||||
作者名 · 发布时间: 2024-01-15 10:30 · 最后更新: 2024-01-20 14:25
|
||||
```
|
||||
|
||||
### 2. 后端处理器
|
||||
|
||||
#### `/handlers/home.go`
|
||||
- 修改 `renderArticleDetail()` 函数(第189-201行):
|
||||
- 添加 `data["UpdatedAt"]` 传递更新时间到模板
|
||||
- 添加 `formatUpdateTime()` 函数(第213-216行):
|
||||
- 格式化 `UpdatedAt` 字段为可读的时间字符串
|
||||
- 格式:`2006-01-02 15:04`(年-月-日 时:分)
|
||||
|
||||
### 3. 国际化文本
|
||||
|
||||
#### `/i18n/i18n.go`
|
||||
添加了翻译键:
|
||||
- `article_last_updated`: "Last Updated" / "最后更新"
|
||||
|
||||
## 功能特性
|
||||
|
||||
1. **双时间戳显示**:
|
||||
- 发布时间(PublishedAt):文章首次发布的时间
|
||||
- 最后更新(UpdatedAt):文章最后一次修改的时间
|
||||
|
||||
2. **自动更新**:
|
||||
- `UpdatedAt` 字段由 GORM 自动维护
|
||||
- 每次调用 `Updates()` 或 `Save()` 时自动更新
|
||||
|
||||
3. **智能显示**:
|
||||
- 如果文章没有发布时间,不显示发布时间
|
||||
- 始终显示最后更新时间
|
||||
|
||||
4. **时间格式**:
|
||||
- 统一使用 `YYYY-MM-DD HH:MM` 格式
|
||||
- 清晰易读
|
||||
|
||||
## 显示效果
|
||||
|
||||
文章详情页顶部会显示:
|
||||
|
||||
### 英文界面
|
||||
```
|
||||
John Doe · Published: 2024-01-15 10:30 · Last Updated: 2024-01-20 14:25
|
||||
```
|
||||
|
||||
### 中文界面
|
||||
```
|
||||
张三 · 发布时间: 2024-01-15 10:30 · 最后更新: 2024-01-20 14:25
|
||||
```
|
||||
|
||||
## 技术实现
|
||||
|
||||
- **数据库字段**:`updated_at` 字段是 GORM 的标准字段,类型为 `time.Time`
|
||||
- **自动维护**:GORM 在每次更新记录时自动设置 `updated_at`
|
||||
- **格式化**:使用 Go 的标准时间格式 `2006-01-02 15:04`
|
||||
|
||||
## 与发布时间编辑功能的配合
|
||||
|
||||
这个功能与之前实现的"自定义发布时间"功能完美配合:
|
||||
- **发布时间**(PublishedAt):可以由用户手动设置或自动生成
|
||||
- **更新时间**(UpdatedAt):始终由系统自动维护,反映真实的修改时间
|
||||
|
||||
这样读者可以清楚地知道:
|
||||
1. 文章最初是什么时候发布的
|
||||
2. 文章最后一次修改是什么时候
|
||||
|
||||
## 用户价值
|
||||
|
||||
1. **内容时效性**:读者可以判断文章内容是否及时更新
|
||||
2. **信息透明**:清楚显示文章的发布和修改历史
|
||||
3. **信任度提升**:显示更新时间表明作者在持续维护内容
|
||||
@@ -0,0 +1,93 @@
|
||||
# 文章发布时间编辑功能
|
||||
|
||||
## 功能概述
|
||||
|
||||
为博客系统的文章编辑页面添加了自定义发布时间的功能,允许管理员和普通用户在创建或编辑文章时手动设置发布时间。
|
||||
|
||||
## 修改的文件
|
||||
|
||||
### 1. 前端模板
|
||||
|
||||
#### `/templates/admin/article_create.html`
|
||||
- 在"置顶"选项前添加了发布时间输入框
|
||||
- 使用 `datetime-local` 类型的输入框,支持选择日期和时间
|
||||
- 添加提示文本:留空则在发布时自动设置
|
||||
|
||||
#### `/templates/user/my_article_form.html`
|
||||
- 在状态选择框前添加了发布时间输入框
|
||||
- 使用相同的 `datetime-local` 输入框
|
||||
- 添加相应的提示文本
|
||||
|
||||
### 2. 后端处理器
|
||||
|
||||
#### `/handlers/article.go`
|
||||
- 修改 `articleForm` 结构体,添加 `PublishedAt string` 字段
|
||||
- 修改 `parseArticleForm()` 函数,解析表单中的 `published_at` 字段
|
||||
- 修改 `applyFormToData()` 函数,将 `PublishedAt` 传递给模板
|
||||
- 添加 `parsePublishedAt()` 函数:解析 datetime-local 格式的时间字符串
|
||||
- 添加 `formatPublishedAt()` 函数:将时间格式化为 datetime-local 格式用于表单回显
|
||||
- 修改 `ArticleEditPage()` 函数:在编辑页面回显发布时间
|
||||
- 修改 `ArticleUpdate()` 函数:
|
||||
- 如果用户提供了自定义发布时间,则使用该时间
|
||||
- 否则保持原有逻辑(首次发布时自动设置当前时间)
|
||||
- 修改 `ArticleCreate()` 函数:
|
||||
- 如果用户提供了自定义发布时间,则使用该时间
|
||||
- 否则在发布时自动设置当前时间
|
||||
|
||||
#### `/handlers/my_articles.go`
|
||||
- 修改 `MyArticleEditPage()` 函数:在编辑页面回显发布时间
|
||||
- 修改 `MyArticleUpdate()` 函数:
|
||||
- 如果用户提供了自定义发布时间,则使用该时间
|
||||
- 否则保持原有逻辑(首次发布时自动设置当前时间)
|
||||
|
||||
### 3. 国际化文本
|
||||
|
||||
#### `/i18n/i18n.go`
|
||||
添加了以下翻译键:
|
||||
- `article_published_at`: "Published Time" / "发布时间"
|
||||
- `article_published_at_hint`: "Leave blank to auto-set on publish" / "留空则在发布时自动设置"
|
||||
|
||||
## 功能特性
|
||||
|
||||
1. **自定义发布时间**:用户可以手动设置文章的发布时间,适用于:
|
||||
- 导入历史文章时保留原始发布时间
|
||||
- 预设未来的发布时间(虽然文章会立即可见)
|
||||
- 修正错误的发布时间
|
||||
|
||||
2. **自动时间戳**:如果用户不填写发布时间:
|
||||
- 保存为草稿:不设置发布时间
|
||||
- 首次发布:自动设置为当前时间
|
||||
- 已发布文章再次编辑:保持原发布时间不变
|
||||
|
||||
3. **向后兼容**:
|
||||
- 现有的自动时间戳逻辑完全保留
|
||||
- 只有在用户明确输入时间时才会覆盖自动时间
|
||||
|
||||
4. **双语支持**:中英文界面均已适配
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 管理员编辑页面
|
||||
1. 访问 `/admin/articles/:id/edit` 或 `/admin/articles/new`
|
||||
2. 在"发布时间"字段中选择日期和时间
|
||||
3. 留空则使用自动时间戳
|
||||
|
||||
### 普通用户编辑页面
|
||||
1. 访问 `/my/articles/:id/edit` 或 `/my/articles/new`
|
||||
2. 在"发布时间"字段中选择日期和时间
|
||||
3. 留空则使用自动时间戳
|
||||
|
||||
## 技术实现
|
||||
|
||||
- **时间格式**:使用 HTML5 `datetime-local` 输入类型,格式为 `2006-01-02T15:04`
|
||||
- **时区处理**:使用服务器的本地时区 (`time.Local`) 进行解析和格式化
|
||||
- **数据库**:`published_at` 字段类型为 `*time.Time`(可为空)
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. 创建新文章时设置自定义发布时间
|
||||
2. 创建新文章时留空发布时间(应自动设置)
|
||||
3. 编辑已发布文章并修改发布时间
|
||||
4. 编辑已发布文章但不修改发布时间(应保持原时间)
|
||||
5. 将草稿改为发布状态(应自动设置发布时间或使用自定义时间)
|
||||
6. 测试中英文界面的显示
|
||||
+73
-35
@@ -69,29 +69,31 @@ func fallbackSlug(id uint) string {
|
||||
// articleForm holds the parsed article form fields, shared by the create and
|
||||
// edit handlers and their validation-error repopulation paths.
|
||||
type articleForm struct {
|
||||
Title string
|
||||
Slug string
|
||||
Summary string
|
||||
Content string
|
||||
Cover string
|
||||
StatusStr string
|
||||
IsTop bool
|
||||
Action string // form action URL
|
||||
TitleText string // page heading text (create vs edit)
|
||||
ArticleID uint // existing article ID (edit page); 0 on create
|
||||
SessionToken string // pending-attachment ownership token (create page)
|
||||
Title string
|
||||
Slug string
|
||||
Summary string
|
||||
Content string
|
||||
Cover string
|
||||
StatusStr string
|
||||
IsTop bool
|
||||
PublishedAt string // datetime-local format: "2006-01-02T15:04"
|
||||
Action string // form action URL
|
||||
TitleText string // page heading text (create vs edit)
|
||||
ArticleID uint // existing article ID (edit page); 0 on create
|
||||
SessionToken string // pending-attachment ownership token (create page)
|
||||
}
|
||||
|
||||
// parseArticleForm reads and trims the article form fields from the request.
|
||||
func parseArticleForm(c *gin.Context) articleForm {
|
||||
return articleForm{
|
||||
Title: strings.TrimSpace(c.PostForm("title")),
|
||||
Slug: strings.TrimSpace(c.PostForm("slug")),
|
||||
Summary: strings.TrimSpace(c.PostForm("summary")),
|
||||
Content: strings.TrimSpace(c.PostForm("content")),
|
||||
Cover: strings.TrimSpace(c.PostForm("cover")),
|
||||
StatusStr: c.PostForm("status"),
|
||||
IsTop: c.PostForm("is_top") == "1",
|
||||
Title: strings.TrimSpace(c.PostForm("title")),
|
||||
Slug: strings.TrimSpace(c.PostForm("slug")),
|
||||
Summary: strings.TrimSpace(c.PostForm("summary")),
|
||||
Content: strings.TrimSpace(c.PostForm("content")),
|
||||
Cover: strings.TrimSpace(c.PostForm("cover")),
|
||||
StatusStr: c.PostForm("status"),
|
||||
IsTop: c.PostForm("is_top") == "1",
|
||||
PublishedAt: strings.TrimSpace(c.PostForm("published_at")),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +107,7 @@ func applyFormToData(data gin.H, f articleForm) {
|
||||
data["FormCover"] = f.Cover
|
||||
data["FormStatus"] = f.StatusStr
|
||||
data["FormIsTop"] = f.IsTop
|
||||
data["FormPublishedAt"] = f.PublishedAt
|
||||
data["FormAction"] = f.Action
|
||||
data["FormTitleText"] = f.TitleText
|
||||
data["FormArticleID"] = f.ArticleID
|
||||
@@ -154,6 +157,29 @@ func statusFromForm(statusStr string) int {
|
||||
return models.ArticleDraft
|
||||
}
|
||||
|
||||
// parsePublishedAt parses the datetime-local format ("2006-01-02T15:04") from
|
||||
// the form into a time.Time pointer. Returns nil if the string is empty or invalid.
|
||||
func parsePublishedAt(publishedAtStr string) *time.Time {
|
||||
if publishedAtStr == "" {
|
||||
return nil
|
||||
}
|
||||
// datetime-local format: "2006-01-02T15:04"
|
||||
t, err := time.ParseInLocation("2006-01-02T15:04", publishedAtStr, time.Local)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return &t
|
||||
}
|
||||
|
||||
// formatPublishedAt formats a time.Time pointer into datetime-local format for the form.
|
||||
// Returns empty string if the pointer is nil.
|
||||
func formatPublishedAt(t *time.Time) string {
|
||||
if t == nil {
|
||||
return ""
|
||||
}
|
||||
return t.Local().Format("2006-01-02T15:04")
|
||||
}
|
||||
|
||||
// ArticleCreatePage renders the article creation form.
|
||||
func ArticleCreatePage(db *gorm.DB) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
@@ -205,7 +231,11 @@ func ArticleCreate(db *gorm.DB) gin.HandlerFunc {
|
||||
}
|
||||
|
||||
var publishedAt *time.Time
|
||||
if status == models.ArticlePublished {
|
||||
if f.PublishedAt != "" {
|
||||
// User provided a custom published time
|
||||
publishedAt = parsePublishedAt(f.PublishedAt)
|
||||
} else if status == models.ArticlePublished {
|
||||
// Auto-stamp with current time if publishing without custom time
|
||||
now := time.Now()
|
||||
publishedAt = &now
|
||||
}
|
||||
@@ -271,16 +301,17 @@ func ArticleEditPage(db *gorm.DB) gin.HandlerFunc {
|
||||
}
|
||||
|
||||
renderArticleForm(c, db, articleForm{
|
||||
Title: article.Title,
|
||||
Slug: article.Slug,
|
||||
Summary: article.Summary,
|
||||
Content: article.Content,
|
||||
Cover: article.Cover,
|
||||
StatusStr: strconv.Itoa(article.Status),
|
||||
IsTop: article.IsTop,
|
||||
Action: "/admin/articles/" + id + "/edit",
|
||||
TitleText: tr["article_edit_title"],
|
||||
ArticleID: article.ID,
|
||||
Title: article.Title,
|
||||
Slug: article.Slug,
|
||||
Summary: article.Summary,
|
||||
Content: article.Content,
|
||||
Cover: article.Cover,
|
||||
StatusStr: strconv.Itoa(article.Status),
|
||||
IsTop: article.IsTop,
|
||||
PublishedAt: formatPublishedAt(article.PublishedAt),
|
||||
Action: "/admin/articles/" + id + "/edit",
|
||||
TitleText: tr["article_edit_title"],
|
||||
ArticleID: article.ID,
|
||||
}, "")
|
||||
}
|
||||
}
|
||||
@@ -319,12 +350,19 @@ func ArticleUpdate(db *gorm.DB) gin.HandlerFunc {
|
||||
|
||||
newStatus := statusFromForm(f.StatusStr)
|
||||
|
||||
// Stamp the publish time the first time an article is published.
|
||||
wasPublished := article.Status == models.ArticlePublished
|
||||
var publishedAt *time.Time = article.PublishedAt
|
||||
if newStatus == models.ArticlePublished && !wasPublished && publishedAt == nil {
|
||||
now := time.Now()
|
||||
publishedAt = &now
|
||||
// Handle published_at: use form value if provided, otherwise auto-stamp on first publish.
|
||||
var publishedAt *time.Time
|
||||
if f.PublishedAt != "" {
|
||||
// User provided a custom published time
|
||||
publishedAt = parsePublishedAt(f.PublishedAt)
|
||||
} else {
|
||||
// Auto-stamp the publish time the first time an article is published.
|
||||
wasPublished := article.Status == models.ArticlePublished
|
||||
publishedAt = article.PublishedAt
|
||||
if newStatus == models.ArticlePublished && !wasPublished && publishedAt == nil {
|
||||
now := time.Now()
|
||||
publishedAt = &now
|
||||
}
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{
|
||||
|
||||
@@ -191,6 +191,7 @@ func renderArticleDetail(c *gin.Context, db *gorm.DB, article *models.Article, f
|
||||
data["Article"] = article
|
||||
data["AuthorName"] = authorName
|
||||
data["PublishedAt"] = formatPublishTime(article.PublishedAt)
|
||||
data["UpdatedAt"] = formatUpdateTime(article.UpdatedAt)
|
||||
data["Comments"] = tree
|
||||
data["CommentConfig"] = models.GetCommentConfig()
|
||||
data["CommentForm"] = form
|
||||
@@ -209,6 +210,11 @@ func formatPublishTime(publishedAt *time.Time) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// formatUpdateTime returns the last update time as a readable string.
|
||||
func formatUpdateTime(updatedAt time.Time) string {
|
||||
return updatedAt.Format("2006-01-02 15:04")
|
||||
}
|
||||
|
||||
// commentFlashKey is the session key for the one-time comment notice.
|
||||
const commentFlashKey = "comment_flash"
|
||||
|
||||
|
||||
+24
-16
@@ -66,16 +66,17 @@ func MyArticleEditPage(db *gorm.DB) gin.HandlerFunc {
|
||||
}
|
||||
|
||||
renderMyArticleForm(c, db, articleForm{
|
||||
Title: article.Title,
|
||||
Slug: article.Slug,
|
||||
Summary: article.Summary,
|
||||
Content: article.Content,
|
||||
Cover: article.Cover,
|
||||
StatusStr: strconv.Itoa(article.Status),
|
||||
IsTop: article.IsTop,
|
||||
Action: "/my/articles/" + id + "/edit",
|
||||
TitleText: tr["article_edit_title"],
|
||||
ArticleID: article.ID,
|
||||
Title: article.Title,
|
||||
Slug: article.Slug,
|
||||
Summary: article.Summary,
|
||||
Content: article.Content,
|
||||
Cover: article.Cover,
|
||||
StatusStr: strconv.Itoa(article.Status),
|
||||
IsTop: article.IsTop,
|
||||
PublishedAt: formatPublishedAt(article.PublishedAt),
|
||||
Action: "/my/articles/" + id + "/edit",
|
||||
TitleText: tr["article_edit_title"],
|
||||
ArticleID: article.ID,
|
||||
}, "")
|
||||
}
|
||||
}
|
||||
@@ -117,12 +118,19 @@ func MyArticleUpdate(db *gorm.DB) gin.HandlerFunc {
|
||||
|
||||
newStatus := statusFromForm(f.StatusStr)
|
||||
|
||||
// Stamp the publish time the first time an article is published.
|
||||
wasPublished := article.Status == models.ArticlePublished
|
||||
var publishedAt *time.Time = article.PublishedAt
|
||||
if newStatus == models.ArticlePublished && !wasPublished && publishedAt == nil {
|
||||
now := time.Now()
|
||||
publishedAt = &now
|
||||
// Handle published_at: use form value if provided, otherwise auto-stamp on first publish.
|
||||
var publishedAt *time.Time
|
||||
if f.PublishedAt != "" {
|
||||
// User provided a custom published time
|
||||
publishedAt = parsePublishedAt(f.PublishedAt)
|
||||
} else {
|
||||
// Stamp the publish time the first time an article is published.
|
||||
wasPublished := article.Status == models.ArticlePublished
|
||||
publishedAt = article.PublishedAt
|
||||
if newStatus == models.ArticlePublished && !wasPublished && publishedAt == nil {
|
||||
now := time.Now()
|
||||
publishedAt = &now
|
||||
}
|
||||
}
|
||||
|
||||
updates := map[string]interface{}{
|
||||
|
||||
@@ -122,6 +122,8 @@ var translations = map[Lang]map[string]string{
|
||||
"article_published": "Published",
|
||||
"article_field_is_top": "Pin to top",
|
||||
"article_is_top": "Pin to top",
|
||||
"article_published_at": "Published Time",
|
||||
"article_published_at_hint": "Leave blank to auto-set on publish",
|
||||
"article_save_draft": "Save Draft",
|
||||
"article_save": "Save",
|
||||
"article_cancel": "Cancel",
|
||||
@@ -160,6 +162,7 @@ var translations = map[Lang]map[string]string{
|
||||
"article_col_status": "Status",
|
||||
"article_col_published": "Published",
|
||||
"article_col_actions": "Actions",
|
||||
"article_last_updated": "Last Updated",
|
||||
|
||||
// Settings (platform configuration)
|
||||
"settings_nav": "Platform Settings",
|
||||
@@ -475,6 +478,8 @@ var translations = map[Lang]map[string]string{
|
||||
"article_published": "已发布",
|
||||
"article_field_is_top": "置顶",
|
||||
"article_is_top": "置顶",
|
||||
"article_published_at": "发布时间",
|
||||
"article_published_at_hint": "留空则在发布时自动设置",
|
||||
"article_save_draft": "保存草稿",
|
||||
"article_save": "保存",
|
||||
"article_cancel": "取消",
|
||||
@@ -513,6 +518,7 @@ var translations = map[Lang]map[string]string{
|
||||
"article_col_status": "状态",
|
||||
"article_col_published": "发布时间",
|
||||
"article_col_actions": "操作",
|
||||
"article_last_updated": "最后更新",
|
||||
|
||||
// 平台设置
|
||||
"settings_nav": "平台设置",
|
||||
|
||||
@@ -77,6 +77,14 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Published At -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">{{index .Tr "article_published_at"}}</label>
|
||||
<input type="datetime-local" name="published_at" value="{{.FormPublishedAt}}"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors">
|
||||
<p class="text-xs text-gray-400 mt-1">{{index .Tr "article_published_at_hint"}}</p>
|
||||
</div>
|
||||
|
||||
<!-- IsTop -->
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="checkbox" name="is_top" value="1" id="isTopCheckbox" {{if .FormIsTop}}checked{{end}}
|
||||
|
||||
@@ -28,7 +28,14 @@
|
||||
<img src="/uploads/avatars/{{.Article.Author.Avatar}}" alt="avatar" class="w-7 h-7 rounded-full object-cover">
|
||||
{{end}}
|
||||
<span class="font-medium text-gray-700">{{.AuthorName}}</span>
|
||||
{{if .PublishedAt}}<span>·</span><span>{{.PublishedAt}}</span>{{end}}
|
||||
{{if .PublishedAt}}
|
||||
<span>·</span>
|
||||
<span>{{index .Tr "article_col_published"}}: {{.PublishedAt}}</span>
|
||||
{{end}}
|
||||
{{if .UpdatedAt}}
|
||||
<span>·</span>
|
||||
<span>{{index .Tr "article_last_updated"}}: {{.UpdatedAt}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{if .Article.Cover}}
|
||||
|
||||
@@ -48,6 +48,13 @@
|
||||
<p class="mt-1 text-sm text-gray-500">{{index .Tr "article_cover_help"}}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">{{index .Tr "article_published_at"}}</label>
|
||||
<input type="datetime-local" name="published_at" value="{{.FormPublishedAt}}"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<p class="mt-1 text-sm text-gray-500">{{index .Tr "article_published_at_hint"}}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">{{index .Tr "article_field_status"}}</label>
|
||||
|
||||
Reference in New Issue
Block a user