diff --git a/install/package.json b/install/package.json index 9db6a5705d..1fcd562522 100644 --- a/install/package.json +++ b/install/package.json @@ -29,6 +29,8 @@ }, "dependencies": { "@adactive/bootstrap-tagsinput": "0.8.2", + "@fontsource/inter": "^4.5.14", + "@fontsource/poppins": "^4.5.10", "@isaacs/ttlcache": "1.4.0", "@popperjs/core": "2.11.8", "ace-builds": "1.22.0", @@ -82,7 +84,6 @@ "lodash": "4.17.21", "logrotate-stream": "0.2.9", "lru-cache": "9.1.1", - "material-design-lite": "1.3.0", "mime": "3.0.0", "mkdirp": "3.0.1", "mongodb": "5.5.0", diff --git a/public/language/en-GB/admin/admin.json b/public/language/en-GB/admin/admin.json index dcf9696ca2..89e08402cd 100644 --- a/public/language/en-GB/admin/admin.json +++ b/public/language/en-GB/admin/admin.json @@ -4,6 +4,13 @@ "acp-title": "%1 | NodeBB Admin Control Panel", "settings-header-contents": "Contents", + "changes-saved": "Changes Saved", + "changes-saved-message": "Your changes to the NodeBB configuration have been saved.", "changes-not-saved": "Changes Not Saved", - "changes-not-saved-message": "NodeBB encountered a problem saving your changes. (%1)" + "changes-not-saved-message": "NodeBB encountered a problem saving your changes. (%1)", + "save-changes": "Save changes", + "min": "Min:", + "max": "Max:", + "view": "View", + "edit": "Edit" } \ No newline at end of file diff --git a/public/language/en-GB/admin/advanced/database.json b/public/language/en-GB/admin/advanced/database.json index 9167b381ed..55eea6c023 100644 --- a/public/language/en-GB/admin/advanced/database.json +++ b/public/language/en-GB/admin/advanced/database.json @@ -5,7 +5,7 @@ "uptime-seconds": "Uptime in Seconds", "uptime-days": "Uptime in Days", - "mongo": "Mongo", + "mongo": "MongoDB", "mongo.version": "MongoDB Version", "mongo.storage-engine": "Storage Engine", "mongo.collections": "Collections", diff --git a/public/language/en-GB/admin/dashboard.json b/public/language/en-GB/admin/dashboard.json index ba945e281a..c77f7ff0c2 100644 --- a/public/language/en-GB/admin/dashboard.json +++ b/public/language/en-GB/admin/dashboard.json @@ -26,13 +26,13 @@ "updates": "Updates", "running-version": "You are running NodeBB v%1.", "keep-updated": "Always make sure that your NodeBB is up to date for the latest security patches and bug fixes.", - "up-to-date": "
You are up-to-date
", - "upgrade-available": "A new version (v%1) has been released. Consider upgrading your NodeBB.
", - "prerelease-upgrade-available": "This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider upgrading your NodeBB.
", - "prerelease-warning": "This is a pre-release version of NodeBB. Unintended bugs may occur.
", + "up-to-date": "You are up-to-date ", + "upgrade-available": "A new version (v%1) has been released. Consider upgrading your NodeBB.", + "prerelease-upgrade-available": "This is an outdated pre-release version of NodeBB. A new version (v%1) has been released. Consider upgrading your NodeBB.", + "prerelease-warning": "This is a pre-release version of NodeBB. Unintended bugs may occur. ", "fallback-emailer-not-found": "Fallback emailer not found!", - "running-in-development": "Forum is running in development mode. The forum may be open to potential vulnerabilities; please contact your system administrator.", - "latest-lookup-failed": "Failed to look up latest available version of NodeBB
", + "running-in-development": "Forum is running in development mode. The forum may be open to potential vulnerabilities; please contact your system administrator", + "latest-lookup-failed": "Failed to look up latest available version of NodeBB", "notices": "Notices", "restart-not-required": "Restart not required", diff --git a/public/language/en-GB/admin/extend/plugins.json b/public/language/en-GB/admin/extend/plugins.json index f7e60c4360..4849f0cab2 100644 --- a/public/language/en-GB/admin/extend/plugins.json +++ b/public/language/en-GB/admin/extend/plugins.json @@ -1,4 +1,5 @@ { + "plugins": "Plugins", "trending": "Trending", "installed": "Installed", "active": "Active", diff --git a/public/language/en-GB/admin/extend/rewards.json b/public/language/en-GB/admin/extend/rewards.json index df89d441a7..2706a25f51 100644 --- a/public/language/en-GB/admin/extend/rewards.json +++ b/public/language/en-GB/admin/extend/rewards.json @@ -1,10 +1,12 @@ { "rewards": "Rewards", + "add-reward": "Add reward", "condition-if-users": "If User's", "condition-is": "Is:", "condition-then": "Then:", "max-claims": "Amount of times reward is claimable", "zero-infinite": "Enter 0 for infinite", + "select-reward": "Select reward", "delete": "Delete", "enable": "Enable", "disable": "Disable", diff --git a/public/language/en-GB/admin/extend/widgets.json b/public/language/en-GB/admin/extend/widgets.json index 9adfb98ab5..ab3a4b11d2 100644 --- a/public/language/en-GB/admin/extend/widgets.json +++ b/public/language/en-GB/admin/extend/widgets.json @@ -1,4 +1,5 @@ { + "widgets": "Widgets", "available": "Available Widgets", "explanation": "Select a widget from the dropdown menu and then drag and drop it into a template's widget area on the left.", "none-installed": "No widgets found! Activate the widget essentials plugin in the plugins control panel.", diff --git a/public/language/en-GB/admin/manage/admins-mods.json b/public/language/en-GB/admin/manage/admins-mods.json index f9bbc63632..999ce33aa4 100644 --- a/public/language/en-GB/admin/manage/admins-mods.json +++ b/public/language/en-GB/admin/manage/admins-mods.json @@ -1,10 +1,11 @@ { + "manage-admins-and-mods": "Manage Admins & Mods", "administrators": "Administrators", "global-moderators": "Global Moderators", "moderators": "Moderators", "no-global-moderators": "No Global Moderators", "no-sub-categories": "No subcategories", - "subcategories": "%1 subcategories", + "view-children": "View children (%1)", "no-moderators": "No Moderators", "add-administrator": "Add Administrator", "add-global-moderator": "Add Global Moderator", diff --git a/public/language/en-GB/admin/manage/categories.json b/public/language/en-GB/admin/manage/categories.json index ed5462e9be..0cfb251c56 100644 --- a/public/language/en-GB/admin/manage/categories.json +++ b/public/language/en-GB/admin/manage/categories.json @@ -1,7 +1,11 @@ { + "manage-categories": "Manage Categories", + "add-category": "Add category", + "jump-to": "Jump to...", "settings": "Category Settings", + "edit-category": "Edit Category", "privileges": "Privileges", - + "back-to-categories": "Back to categories", "name": "Category Name", "description": "Category Description", "bg-color": "Background Colour", @@ -15,8 +19,11 @@ "post-queue": "Post queue", "tag-whitelist": "Tag Whitelist", "upload-image": "Upload Image", + "upload": "Upload", + "select-icon": "Select Icon", "delete-image": "Remove", "category-image": "Category Image", + "image-and-icon": "Image & Icon", "parent-category": "Parent Category", "optional-parent-category": "(Optional) Parent Category", "top-level": "Top Level", @@ -31,6 +38,7 @@ "disable": "Disable", "edit": "Edit", "analytics": "Analytics", + "view-category": "View category", "set-order": "Set order", "set-order-help": "Setting the order of the category will move this category to that order and update the order of other categories as necessary. Minimum order is 1 which puts the category at the top.", diff --git a/public/language/en-GB/admin/manage/groups.json b/public/language/en-GB/admin/manage/groups.json index bd8c5bce15..9b98b745fa 100644 --- a/public/language/en-GB/admin/manage/groups.json +++ b/public/language/en-GB/admin/manage/groups.json @@ -1,4 +1,10 @@ { + "manage-groups": "Manage groups", + "add-group": "Add group", + "edit-group": "Edit Group", + "back-to-groups": "Back to groups", + "view-group": "View group", + "icon-and-title": "Icon & Title", "name": "Group Name", "badge": "Badge", "properties": "Properties", @@ -10,7 +16,7 @@ "edit": "Edit", "delete": "Delete", "privileges": "Privileges", - "download-csv": "CSV", + "members-csv": "Members (CSV)", "search-placeholder": "Search", "create": "Create Group", "description-placeholder": "A short description about your group", diff --git a/public/language/en-GB/admin/manage/privileges.json b/public/language/en-GB/admin/manage/privileges.json index 0e8d7a4ff9..9af075bcfa 100644 --- a/public/language/en-GB/admin/manage/privileges.json +++ b/public/language/en-GB/admin/manage/privileges.json @@ -1,4 +1,6 @@ { + "manage-privileges": "Manage Privileges", + "discard-changes": "Discard changes", "global": "Global", "admin": "Admin", "group-privileges": "Group Privileges", diff --git a/public/language/en-GB/admin/manage/tags.json b/public/language/en-GB/admin/manage/tags.json index 01363dfda0..2bb50e7048 100644 --- a/public/language/en-GB/admin/manage/tags.json +++ b/public/language/en-GB/admin/manage/tags.json @@ -1,9 +1,11 @@ { + "manage-tags": "Manage Tags", "none": "Your forum does not have any topics with tags yet.", "bg-color": "Background Colour", "text-color": "Text Colour", "description": "Select tags by clicking or dragging, useCTRL
to select multiple tags.",
"create": "Create Tag",
+ "add-tag": "Add tag",
"modify": "Modify Tags",
"rename": "Rename Tags",
"delete": "Delete Selected Tags",
diff --git a/public/language/en-GB/admin/manage/uploads.json b/public/language/en-GB/admin/manage/uploads.json
index 72a695ccdc..e5f3a2a940 100644
--- a/public/language/en-GB/admin/manage/uploads.json
+++ b/public/language/en-GB/admin/manage/uploads.json
@@ -1,4 +1,5 @@
{
+ "manage-uploads": "Manage Uploads",
"upload-file": "Upload File",
"filename": "Filename",
"usage": "Post Usage",
diff --git a/public/language/en-GB/admin/manage/users.json b/public/language/en-GB/admin/manage/users.json
index 9064153de7..6b668a31ef 100644
--- a/public/language/en-GB/admin/manage/users.json
+++ b/public/language/en-GB/admin/manage/users.json
@@ -1,4 +1,5 @@
{
+ "manage-users": "Manage Users",
"users": "Users",
"edit": "Actions",
"make-admin": "Make Admin",
diff --git a/public/language/en-GB/admin/menu.json b/public/language/en-GB/admin/menu.json
index 379e0b2687..bdc794d943 100644
--- a/public/language/en-GB/admin/menu.json
+++ b/public/language/en-GB/admin/menu.json
@@ -72,7 +72,9 @@
"development/info": "Info",
"rebuild-and-restart-forum": "Rebuild & Restart Forum",
+ "rebuild-and-restart": "Rebuild & Restart",
"restart-forum": "Restart Forum",
+ "restart": "Restart",
"logout": "Log out",
"view-forum": "View Forum",
diff --git a/public/language/en-GB/admin/settings/general.json b/public/language/en-GB/admin/settings/general.json
index 29b939861b..2369a49d1c 100644
--- a/public/language/en-GB/admin/settings/general.json
+++ b/public/language/en-GB/admin/settings/general.json
@@ -1,11 +1,13 @@
{
+ "general-settings": "General Settings",
+ "on-this-page": "On this page:",
"site-settings": "Site Settings",
"title": "Site Title",
"title.short": "Short Title",
"title.short-placeholder": "If no short title is specified, the site title will be used",
"title.url": "Title Link URL",
"title.url-placeholder": "The URL of the site title",
- "title.url-help": "When the title is clicked, send users to this address. If left blank, user will be sent to the forum index. url
property in config.json",
+ "title.url-help": "When the title is clicked, send users to this address. If left blank, user will be sent to the forum index. Note: This is not the external URL used in emails, etc. That is set by the url
property in config.json",
"title.name": "Your Community Name",
"title.show-in-header": "Show Site Title in Header",
"browser-title": "Browser Title",
@@ -16,7 +18,7 @@
"description": "Site Description",
"keywords": "Site Keywords",
"keywords-placeholder": "Keywords describing your community, comma-separated",
- "logo": "Site Logo",
+ "logo-and-icons": "Site Logo & Icons",
"logo.image": "Image",
"logo.image-placeholder": "Path to a logo to display on forum header",
"logo.upload": "Upload",
diff --git a/public/language/en-GB/admin/settings/guest.json b/public/language/en-GB/admin/settings/guest.json
index 75d44f37e4..44370e3668 100644
--- a/public/language/en-GB/admin/settings/guest.json
+++ b/public/language/en-GB/admin/settings/guest.json
@@ -1,5 +1,6 @@
{
"settings": "Settings",
+ "guest-settings": "Guest settings",
"handles.enabled": "Allow guest handles",
"handles.enabled-help": "This option exposes a new field that allows guests to pick a name to associate with each post they make. If disabled, they will simply be called \"Guest\"",
"topic-views.enabled": "Allow guests to increase topic view counts",
diff --git a/public/language/en-GB/admin/settings/navigation.json b/public/language/en-GB/admin/settings/navigation.json
index 32b2722074..931ac5f4ba 100644
--- a/public/language/en-GB/admin/settings/navigation.json
+++ b/public/language/en-GB/admin/settings/navigation.json
@@ -1,4 +1,5 @@
{
+ "navigation": "Navigation",
"icon": "Icon:",
"change-icon": "change",
"route": "Route:",
diff --git a/public/language/en-GB/admin/settings/post.json b/public/language/en-GB/admin/settings/post.json
index 57cc855319..9dc61afe57 100644
--- a/public/language/en-GB/admin/settings/post.json
+++ b/public/language/en-GB/admin/settings/post.json
@@ -1,4 +1,5 @@
{
+ "general": "General",
"sorting": "Post Sorting",
"sorting.post-default": "Default Post Sorting",
"sorting.oldest-to-newest": "Oldest to Newest",
@@ -23,10 +24,8 @@
"restrictions.seconds-edit-after": "Number of seconds a post remains editable (set to 0 to disable)",
"restrictions.seconds-delete-after": "Number of seconds a post remains deletable (set to 0 to disable)",
"restrictions.replies-no-delete": "Number of replies after users are disallowed to delete their own topics (set to 0 to disable)",
- "restrictions.min-title-length": "Minimum Title Length",
- "restrictions.max-title-length": "Maximum Title Length",
- "restrictions.min-post-length": "Minimum Post Length",
- "restrictions.max-post-length": "Maximum Post Length",
+ "restrictions.title-length": "Title Length",
+ "restrictions.post-length": "Post Length",
"restrictions.days-until-stale": "Days until topic is considered stale",
"restrictions.stale-help": "If a topic is considered \"stale\", then a warning will be shown to users who attempt to reply to that topic.",
"timestamp": "Timestamp",
@@ -41,10 +40,9 @@
"teaser.last-reply": "Last – Show the latest reply, or a \"No replies\" placeholder if no replies",
"teaser.first": "First",
"showPostPreviewsOnHover": "Show a preview of posts when mouse overed",
- "unread": "Unread Settings",
+ "unread-and-recent": "Unread & Recent Settings",
"unread.cutoff": "Unread cutoff days",
"unread.min-track-last": "Minimum posts in topic before tracking last read",
- "recent": "Recent Settings",
"recent.max-topics": "Maximum topics on /recent",
"recent.categoryFilter.disable": "Disable filtering of topics in ignored categories on the /recent page",
"signature": "Signature Settings",
diff --git a/public/language/en-GB/admin/settings/reputation.json b/public/language/en-GB/admin/settings/reputation.json
index e790ec094f..293aa5b440 100644
--- a/public/language/en-GB/admin/settings/reputation.json
+++ b/public/language/en-GB/admin/settings/reputation.json
@@ -27,5 +27,5 @@
"flags.action-on-resolve": "Do the following when a flag is resolved",
"flags.action-on-reject": "Do the following when a flag is rejected",
"flags.action.nothing": "Do nothing",
- "flags.action.rescind": "Rescind the notification send to moderators/administrators"
+ "flags.action.rescind": "Rescind the notification sent to moderators/administrators"
}
\ No newline at end of file
diff --git a/public/language/en-GB/admin/settings/social.json b/public/language/en-GB/admin/settings/social.json
index 23aedfcfaa..257e20b54b 100644
--- a/public/language/en-GB/admin/settings/social.json
+++ b/public/language/en-GB/admin/settings/social.json
@@ -1,5 +1,4 @@
{
"post-sharing": "Post Sharing",
- "info-plugins-additional": "Plugins can add additional networks for sharing posts.",
- "save-success": "Successfully saved Post Sharing Networks!"
+ "info-plugins-additional": "Plugins can add additional networks for sharing posts."
}
\ No newline at end of file
diff --git a/public/language/en-GB/admin/settings/tags.json b/public/language/en-GB/admin/settings/tags.json
index 080010f6f0..c1cdb2b644 100644
--- a/public/language/en-GB/admin/settings/tags.json
+++ b/public/language/en-GB/admin/settings/tags.json
@@ -3,6 +3,7 @@
"link-to-manage": "Manage Tags",
"system-tags": "System Tags",
"system-tags-help": "Only privileged users will be able to use these tags.",
+ "tags-per-topic": "Tags per topic",
"min-per-topic": "Minimum Tags per Topic",
"max-per-topic": "Maximum Tags per Topic",
"min-length": "Minimum Tag Length",
diff --git a/public/language/en-GB/admin/settings/user.json b/public/language/en-GB/admin/settings/user.json
index c8c418a206..368548ba74 100644
--- a/public/language/en-GB/admin/settings/user.json
+++ b/public/language/en-GB/admin/settings/user.json
@@ -59,7 +59,7 @@
"max-about-me-length": "Maximum About Me Length",
"terms-of-use": "Forum Terms of Use (Leave blank to disable)",
"user-search": "User Search",
- "user-search-results-per-page": "Number of results to display",
+ "user-search-results-per-page": "Number of users to display in search results",
"default-user-settings": "Default User Settings",
"show-email": "Show email",
"show-fullname": "Show fullname",
diff --git a/public/language/en-GB/global.json b/public/language/en-GB/global.json
index 09a90dea4c..857bd05377 100644
--- a/public/language/en-GB/global.json
+++ b/public/language/en-GB/global.json
@@ -24,6 +24,7 @@
"save_changes": "Save Changes",
"save": "Save",
+ "create": "Create",
"cancel": "Cancel",
"close": "Close",
diff --git a/public/openapi/read.yaml b/public/openapi/read.yaml
index 5343d130ae..34326163bd 100644
--- a/public/openapi/read.yaml
+++ b/public/openapi/read.yaml
@@ -82,14 +82,8 @@ paths:
$ref: 'read/admin/dashboard/searches.yaml'
"/api/admin/settings/{term}":
$ref: 'read/admin/settings/term.yaml'
- /api/admin/settings/languages:
- $ref: 'read/admin/settings/languages.yaml'
/api/admin/settings/navigation:
$ref: 'read/admin/settings/navigation.yaml'
- /api/admin/settings/homepage:
- $ref: 'read/admin/settings/homepage.yaml'
- /api/admin/settings/social:
- $ref: 'read/admin/settings/social.yaml'
/api/admin/settings/api:
$ref: 'read/admin/settings/api.yaml'
/api/admin/settings/email:
diff --git a/public/openapi/read/admin/manage/categories.yaml b/public/openapi/read/admin/manage/categories.yaml
index 36b8d4f9a8..b4e6102ac1 100644
--- a/public/openapi/read/admin/manage/categories.yaml
+++ b/public/openapi/read/admin/manage/categories.yaml
@@ -13,6 +13,8 @@ get:
properties:
categoriesPerPage:
type: number
+ selectCategoryLabel:
+ type: string
categoriesTree:
type: array
items:
@@ -23,6 +25,8 @@ get:
description: A category identifier
name:
type: string
+ description:
+ type: string
disabled:
type: number
icon:
diff --git a/public/openapi/read/admin/settings/advanced.yaml b/public/openapi/read/admin/settings/advanced.yaml
index 2cebeeb7e9..c6dfbbbcd9 100644
--- a/public/openapi/read/admin/settings/advanced.yaml
+++ b/public/openapi/read/admin/settings/advanced.yaml
@@ -11,6 +11,8 @@ get:
allOf:
- type: object
properties:
+ title:
+ type: string
groupsExemptFromMaintenanceMode:
type: array
items:
diff --git a/public/openapi/read/admin/settings/api.yaml b/public/openapi/read/admin/settings/api.yaml
index 1e955d32c8..29fde9f691 100644
--- a/public/openapi/read/admin/settings/api.yaml
+++ b/public/openapi/read/admin/settings/api.yaml
@@ -11,6 +11,8 @@ get:
allOf:
- type: object
properties:
+ title:
+ type: string
tokens:
type: array
items:
diff --git a/public/openapi/read/admin/settings/email.yaml b/public/openapi/read/admin/settings/email.yaml
index e2d9b76257..235d6cc833 100644
--- a/public/openapi/read/admin/settings/email.yaml
+++ b/public/openapi/read/admin/settings/email.yaml
@@ -11,6 +11,8 @@ get:
allOf:
- type: object
properties:
+ title:
+ type: string
emails:
type: array
items:
diff --git a/public/openapi/read/admin/settings/homepage.yaml b/public/openapi/read/admin/settings/homepage.yaml
deleted file mode 100644
index 3225629c37..0000000000
--- a/public/openapi/read/admin/settings/homepage.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-get:
- tags:
- - admin
- summary: Get homepage settings
- responses:
- "200":
- description: ""
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- routes:
- type: array
- items:
- type: object
- properties:
- route:
- type: string
- name:
- type: string
- - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps
\ No newline at end of file
diff --git a/public/openapi/read/admin/settings/languages.yaml b/public/openapi/read/admin/settings/languages.yaml
deleted file mode 100644
index 64b1e6b54e..0000000000
--- a/public/openapi/read/admin/settings/languages.yaml
+++ /dev/null
@@ -1,35 +0,0 @@
-get:
- tags:
- - admin
- summary: Get language settings
- responses:
- "200":
- description: A JSON object containing available languages and settings
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- languages:
- type: array
- items:
- type: object
- properties:
- name:
- type: string
- description: Localised name of the language
- code:
- type: string
- description: A language code (similar to ISO-639)
- dir:
- type: string
- description: Directionality of the language
- enum: [ltr, rtl]
- selected:
- type: boolean
- description: Denotes the currently selected default system language on the forum
- autoDetectLang:
- type: integer
- description: Whether the forum will attempt to guess language based on browser's `Accept-Language` header
- - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps
\ No newline at end of file
diff --git a/public/openapi/read/admin/settings/navigation.yaml b/public/openapi/read/admin/settings/navigation.yaml
index 05ffbc6bf7..c86f387997 100644
--- a/public/openapi/read/admin/settings/navigation.yaml
+++ b/public/openapi/read/admin/settings/navigation.yaml
@@ -111,4 +111,6 @@ get:
navigation:
type: array
description: A clone of `enabled`
+ title:
+ type: string
- $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps
\ No newline at end of file
diff --git a/public/openapi/read/admin/settings/post.yaml b/public/openapi/read/admin/settings/post.yaml
index f8273c8b8c..9fdf7685c4 100644
--- a/public/openapi/read/admin/settings/post.yaml
+++ b/public/openapi/read/admin/settings/post.yaml
@@ -11,6 +11,8 @@ get:
allOf:
- type: object
properties:
+ title:
+ type: string
groupsExemptFromPostQueue:
type: array
items:
diff --git a/public/openapi/read/admin/settings/social.yaml b/public/openapi/read/admin/settings/social.yaml
deleted file mode 100644
index 7d32a17064..0000000000
--- a/public/openapi/read/admin/settings/social.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-get:
- tags:
- - admin
- summary: Get post social sharing settings
- responses:
- "200":
- description: "A JSON object containing post social sharing settings"
- content:
- application/json:
- schema:
- allOf:
- - type: object
- properties:
- posts:
- type: array
- items:
- type: object
- properties:
- id:
- type: string
- name:
- type: string
- class:
- type: string
- description: A FontAwesome icon string
- activated:
- type: boolean
- - $ref: ../../../components/schemas/CommonProps.yaml#/CommonProps
\ No newline at end of file
diff --git a/public/openapi/read/admin/settings/term.yaml b/public/openapi/read/admin/settings/term.yaml
index 1801041776..86eaf50b4e 100644
--- a/public/openapi/read/admin/settings/term.yaml
+++ b/public/openapi/read/admin/settings/term.yaml
@@ -17,7 +17,17 @@ get:
schema:
allOf:
- type: object
- properties: {}
+ properties:
+ title:
+ type: string
+ routes:
+ type: array
+ postSharing:
+ type: array
+ languages:
+ type: array
+ autoDetectLang:
+ type: number
additionalProperties:
type: object
description: Most of the settings pages have their values loaded on the client-side, so the settings are not exposed server-side.
diff --git a/public/openapi/read/admin/settings/user.yaml b/public/openapi/read/admin/settings/user.yaml
index 6dccccedee..89b0b1067a 100644
--- a/public/openapi/read/admin/settings/user.yaml
+++ b/public/openapi/read/admin/settings/user.yaml
@@ -11,6 +11,8 @@ get:
allOf:
- type: object
properties:
+ title:
+ type: string
notificationSettings:
type: array
items:
diff --git a/public/scss/admin/admin.scss b/public/scss/admin/admin.scss
index 1be7f930f5..c7ee741967 100644
--- a/public/scss/admin/admin.scss
+++ b/public/scss/admin/admin.scss
@@ -1,6 +1,8 @@
-@import "./mixins";
+@import "fonts";
+@import "mixins";
+@import "common";
-@import "./header";
+@import "sidebar";
@import "./mobile";
@import "./general/dashboard";
@@ -12,10 +14,8 @@
@import "./settings/api";
@import "./appearance/customise";
@import "./extend/plugins";
-@import "./extend/rewards";
@import "./extend/widgets";
-@import "./advanced/database";
-@import "./settings";
+@import "settings";
@import "./modules/alerts";
@import "./modules/selectable";
@@ -27,26 +27,29 @@ body {
}
.admin {
- background: #fff;
- font-size: 14px;
-
- h1 {
- font-size: 35px;
- }
- .form-label, .form-check-label {
- font-weight: 700;
- }
- .btn {
- border-radius: 0;
- }
- .btn-outline-secondary {
- color: $gray-700;
- box-shadow: 0 1px 4px rgba(0, 0, 0, .4) !important;
- &:hover {
- background-color: $gray-200 !important;
+ .acp-page-container {
+ max-width: 800px;
+ margin: 0 auto;
+ display: flex;
+ flex-direction: column;
+ gap: $spacer * 1.5;
+ padding: $spacer * 1.5;
+ padding-top: 0;
+ }
+ .acp-page-main-header {
+ background-color: white;
+ }
+
+ .settings, .categories, .category, .admins-mods {
+ hr {
+ color: $gray-500;
}
}
+ .form-control::placeholder, .bootstrap-tagsinput::placeholder {
+ color: $gray-500 !important;
+ }
+
// .floating-button can either be a container or the button itself
.floating-button {
position: fixed;
@@ -73,22 +76,6 @@ body {
background: $primary !important;
}
- .nodebb-logo {
- img {
- height: 31px;
- margin-top: -8px;
- margin-left: -7px;
- vertical-align: -43%;
- }
-
- @include box-header-font;
- color: #fff;
- }
-
- #breadcrumbs {
- cursor: default;
- }
-
@mixin acp-panel-heading() {
padding: 7px 14px;
border: 0;
@@ -114,10 +101,6 @@ body {
}
}
- .nav-header {
- @include box-header-font;
- }
-
.icon-container {
.fa-nbb-none {
border: 1px dotted black;
@@ -141,27 +124,6 @@ body {
}
}
- .navbar-static-top, .navbar-fixed-top {
- box-shadow: 0px -3px 12px rgba(0, 0, 0, 0.5);
- }
-
- .navbar-header > .navbar-toggle {
- margin-right: 8px;
- }
-
- .navbar-nav {
- >li {
- >#reconnect {
- color: $gray-700;
- }
-
- >#reconnect:focus, >#reconnect:hover {
- color: $gray-700;
- background-color: transparent;
- }
- }
- }
-
#taskbar {
display: none; /* not sure why I have to do this, but it only seems to show up on prod */
}
@@ -172,57 +134,21 @@ body {
}
.bootstrap-tagsinput {
+ box-shadow: $input-box-shadow;
width: 100%;
- border: 0;
- box-shadow: none;
- padding-left: 0;
input {
- width: 100%;
- margin-left: 1px;
- margin-top: 9px;
- border-bottom: 1px dotted #ccc !important;
- padding-bottom: 5px;
- padding-left: 0;
+ font-size: 0.875rem;
+ width: 64px;
+ padding: 0;
}
}
}
-// Allowing text to the right of an image-type brand
-// See: https://github.com/twbs/bootstrap/commit/8e2348e9eda51296eb680192379ab37f10355ca3
-.navbar-brand > img {
- display: inline-block;
-}
-
-.category-settings-form {
- h3 {
- margin-top: 0;
- cursor: pointer;
- }
-
- h4 {
- cursor: pointer;
- }
-}
-
-.category-preview {
- cursor: pointer;
- width: 100%;
- height: 100px;
- text-align: center;
- color: white;
- margin-top: 0;
-
- .icon {
- width: 30px;
- height: 30px;
- line-height: 40px;
- display: inline-block;
- margin: 35px 5px 0 5px;
- }
+.dropdown-left .dropdown-menu {
+ --bs-position: start;
}
-
-.category-dropdown-container.right .category-dropdown-menu {
+.dropdown-right .dropdown-menu {
--bs-position: end;
}
@@ -261,10 +187,6 @@ body {
opacity: 0.5;
}
-form small {
- color: $gray-700;
-}
-
.caret {
display: inline-block;
width: 0;
diff --git a/public/scss/admin/advanced/database.scss b/public/scss/admin/advanced/database.scss
deleted file mode 100644
index a68332708c..0000000000
--- a/public/scss/admin/advanced/database.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-.database-info {
- span {
- display:inline-block;
- width:220px;
- }
-}
diff --git a/public/scss/admin/common.scss b/public/scss/admin/common.scss
new file mode 100644
index 0000000000..85cea66ed2
--- /dev/null
+++ b/public/scss/admin/common.scss
@@ -0,0 +1,73 @@
+
+.form-label {
+ font-weight: 500;
+ font-size: $font-size-sm;
+ font-family: $font-family-base;
+ margin-bottom: 0;
+}
+
+.form-text {
+ font-size: 0.75rem!important;;
+ font-family: $font-family-base;
+}
+
+.tracking-tight { letter-spacing: -0.02em; }
+
+$btn-ghost-hover-color: mix($light, $dark, 90%);
+
+@mixin btn-ghost-base {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: ($spacer * 0.5);
+ border-radius: $border-radius-sm;
+ border-width: 1px;
+ border-color: transparent;
+ background-color: transparent;
+ padding: ($spacer * 0.25) ($spacer * 0.5);
+ text-align: left;
+ --bs-text-opacity: 1;
+ color: rgb(73 80 87 / var(--bs-text-opacity));
+ font-family: $font-family-secondary;
+ cursor: pointer;
+ &:hover, &.active {
+ background-color: $btn-ghost-hover-color;
+ color: rgb(73 80 87 / var(--bs-text-opacity));
+ text-decoration: none;
+ }
+}
+
+.btn-ghost {
+ @include btn-ghost-base();
+ line-height: 1.5rem;
+ > i {
+ line-height: 1.5rem;
+ }
+}
+
+.btn-ghost-sm {
+ @include btn-ghost-base();
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ > i {
+ line-height: 1.25rem;
+ }
+}
+
+.btn-outline {
+ @include btn-ghost-base();
+ border-color: $border-color;
+}
+
+.btn-outline-sm {
+ @include btn-ghost-base();
+ border-color: $border-color;
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+}
+
+.flex-basis-md-200 {
+ @include media-breakpoint-up(md) {
+ flex-basis: 200px!important;
+ }
+}
\ No newline at end of file
diff --git a/public/scss/admin/extend/plugins.scss b/public/scss/admin/extend/plugins.scss
index 70c441c190..0dcd19b2d2 100644
--- a/public/scss/admin/extend/plugins.scss
+++ b/public/scss/admin/extend/plugins.scss
@@ -1,24 +1,4 @@
.plugins {
- padding-left: 0px;
-
- li {
- list-style-type: none;
- background: rgba(64, 64, 64, 0.05);
- padding: 1em;
- margin-bottom: 5px;
- border-left: 5px solid #08c;
- margin-left: -40px;
-
- h2 {
- font-size: 16px;
- margin: 0;
- }
-
- p {
- font-size: 12px;
- }
- }
-
.plugin-list.ui-sortable {
li {
cursor: pointer;
diff --git a/public/scss/admin/extend/rewards.scss b/public/scss/admin/extend/rewards.scss
deleted file mode 100644
index 4f20b44bf2..0000000000
--- a/public/scss/admin/extend/rewards.scss
+++ /dev/null
@@ -1,52 +0,0 @@
-#rewards {
- ul {
- list-style-type: none;
- padding: 0px;
- margin: 0px;
-
- > li {
- border-bottom: 1px solid #ddd;
- margin-bottom: 20px;
- &:last-child {
- border-bottom: 0;
- }
- }
- }
-
- .rewards { width: 100%; }
-
- .card {
- border-radius: 2px;
- border-width: 2px;
- color: #333;
-
- &.if-block {
- border-color: $primary;
- max-width: 33%;
- }
- &.this-block {
- border-color: $warning;
- max-width: 33%;
- }
- &.then-block {
- border-color: $success;
- max-width: 33%;
- }
- &.reward-block {
- border-color: $success;
- background-color: lighten($success, 15%);
- color: #fff;
- a, select, input { color: #fff; }
- select > option { color: #333; }
- width: 100%;
- min-height: 110px;
- }
- }
-}
-
-.page-admin-rewards {
- #new {
- bottom: calc(64px + $spacer);
- background-color: $success;
- }
-}
\ No newline at end of file
diff --git a/public/scss/admin/fonts.scss b/public/scss/admin/fonts.scss
new file mode 100644
index 0000000000..11b0d4d1a2
--- /dev/null
+++ b/public/scss/admin/fonts.scss
@@ -0,0 +1,21 @@
+@use "@fontsource/inter/scss/mixins" as Inter;
+@use "@fontsource/poppins/scss/mixins" as Poppins;
+
+$weights: $font-weight-light, $font-weight-normal, $font-weight-semibold, $font-weight-bold;
+
+@each $weight in $weights {
+ @include Inter.fontFace(
+ $weight: $weight,
+ $display: fallback,
+ $fontDir: "./plugins/core/inter"
+ );
+ @include Poppins.fontFace(
+ $weight: $weight,
+ $display: fallback,
+ $fontDir: "./plugins/core/poppins"
+ );
+}
+
+.ff-base { font-family: $font-family-base !important; }
+.ff-sans { font-family: $font-family-sans-serif !important; }
+.ff-secondary { font-family: $font-family-secondary; }
\ No newline at end of file
diff --git a/public/scss/admin/header.scss b/public/scss/admin/header.scss
deleted file mode 100644
index 1d9b08b4b9..0000000000
--- a/public/scss/admin/header.scss
+++ /dev/null
@@ -1,159 +0,0 @@
-.header {
- user-select: none;
- position: relative;
- background: #333;
- width: 100%;
- height: 200px;
- margin-bottom: 50px;
- font-size: 16px;
-
- #main-page-title {
- position: absolute;
- left: 48px;
- bottom: 50px;
- color: #aaa;
- font-size: 47px;
- font-weight: 300;
- }
-
- .quick-actions {
- position: static;
- padding: 15px;
- display: flex;
- flex-direction: row-reverse;
- margin: 0;
-
- > * {
- margin-right: 20px;
- }
-
- > .menu-button {
- margin-right: 0;
- padding: 0 5px;
- }
-
- .alert {
- font-size: 14px;
- margin-bottom: 0px;
-
- &.alert-info {
- background-color: #eee;
- color: #333;
- }
- }
-
- .dropdown {
- margin-right: 0px;
-
- .dropdown-toggle i {
- padding: 0 1rem;
- }
- }
-
- .fa {
- line-height: 44px;
- font-size: 25px;
- }
-
- #user_dropdown {
- font-size: 25px;
- color: #eee;
-
- i {
- margin-top: 12px;
- display: block;
- }
- }
- }
-
- #acp-search {
- input {
- padding: 10px 20px;
- width: 250px;
- height: 44px;
- background-color: rgba(0,0,0,.2);
- border-radius: 3px;
- box-shadow: none;
- transition: .4s ease background-color;
-
- &:focus {
- background-color: #eee;
- color: #333;
- }
- }
-
- .dropdown:not(.open) {
- &:before {
- content: '/';
- border: 1px solid $gray-500;
- border-radius: 5px;
- padding: 0px 6px;
- font-size: 12px;
- font-weight: 600;
- pointer-events: none;
-
- position: absolute;
- top: 13px;
- left: 1em;
- }
-
- &:after {
- content: attr(data-text);
- position: absolute;
- top: 13px;
- left: 3em;
- font-size: small;
- font-weight: 600;
- pointer-events: none;
- }
-
- input {
- color: transparent;
- }
- }
-
- .search-match {
- font-weight: 700;
- color: black;
- }
- }
-
- #main-menu > li {
- padding-bottom: 10px;
- }
-
- > ul {
- list-style-type: none;
- padding: 0px;
- position: absolute;
- bottom: -16px;
- left: 50px;
-
- > li {
- float: left;
- margin-right: 30px;
- border-bottom: 4px solid transparent;
- transition: border-color 150ms linear;
-
- &:hover {
- border-color: darken($primary, 20%);
- }
-
- &.active {
- border-color: $primary;
- }
-
- > a {
- color: white;
- text-transform: uppercase;
- text-decoration: none;
- outline: none;
- }
- }
- }
-
- .plugins-menu {
- max-height: 50vh;
- overflow-y: auto;
- }
-}
diff --git a/public/scss/admin/manage/categories.scss b/public/scss/admin/manage/categories.scss
index 8c5117990f..39c61f429f 100644
--- a/public/scss/admin/manage/categories.scss
+++ b/public/scss/admin/manage/categories.scss
@@ -1,51 +1,20 @@
div.categories {
ul[data-cid] {
- user-select: none;
- list-style-type: none;
- margin: 0;
- padding: 0;
-
> li > ul > li {
- margin-left: 4.5rem;
- }
- > li > a {
- margin-left: 4.5rem;
- }
- .row {
- margin-left: -15px;
- margin-right: -15px;
+ padding-left: 3rem;
}
- > li li:last-child {
- .row {
- border-bottom: 0px;
- }
- }
> li {
- margin: 16px 0 24px 0;
-
&.placeholder {
border: 1px dashed #2196F3;
background-color: #E1F5FE;
+ width: 100%;
}
}
}
- .stats {
- display: inline-block;
-
- li {
- min-height: 0;
- display: inline;
- margin: 0 16px 0 0;
- left: 0;
- }
- }
-
-
.disabled > .category-row {
-
- .icon, .category-header, .description {
+ .icon, .title, .description {
opacity: 0.5;
}
@@ -57,34 +26,15 @@ div.categories {
.toggle {
width: 24px;
height: 24px;
- border-radius: 50%;
line-height: 24px;
- text-align: center;
- vertical-align: bottom;
- background-size: cover;
- float: left;
- margin-right: 0px;
cursor: pointer;
- .fa {
- font-size: 85%;
- }
}
.information {
cursor: move;
- padding-left: 3rem;
- }
-
- .category-header {
- margin-top: 0;
- margin-bottom: 8px;
- }
-
- .description {
- margin: 0;
}
- .children-placeholder{
+ .children-placeholder {
min-height: 20px;
height: 20px;
}
diff --git a/public/scss/admin/manage/groups.scss b/public/scss/admin/manage/groups.scss
index 8cad8083b2..24718ac43d 100644
--- a/public/scss/admin/manage/groups.scss
+++ b/public/scss/admin/manage/groups.scss
@@ -1,30 +1,5 @@
-.group {
- [component="groups/members"] {
- padding: 0;
- tbody {
- max-height: 500px;
- display: block;
- overflow-y: auto;
- .member-name {
- width: 100%;
- }
- }
- }
-
- #group-icon {
- cursor: pointer;
- }
-}
-
.groups {
- #group-search {
- margin-bottom: 10px;
- }
-
.groups-list {
- p {
- margin: 0;
- }
td {
max-width: 350px;
}
diff --git a/public/scss/admin/manage/tags.scss b/public/scss/admin/manage/tags.scss
index dc7d608129..d242288997 100644
--- a/public/scss/admin/manage/tags.scss
+++ b/public/scss/admin/manage/tags.scss
@@ -1,22 +1,12 @@
.tags {
.tag-list {
- h3 {
- min-width: 225px;
- }
.tag-row {
- padding: 0.5rem;
float: left;
- margin-left: 0.5rem;
-
- .tag-item {
- cursor: pointer;
- display: inline-block;
- font-size: 11px;
- }
&.ui-selected {
background: lighten($success, 25%);
+ border-radius: $border-radius-sm;
}
&.ui-selecting {
@@ -24,8 +14,4 @@
}
}
}
-
- .tag-topic-count {
- font-size: 14px;
- }
}
\ No newline at end of file
diff --git a/public/scss/admin/mobile.scss b/public/scss/admin/mobile.scss
index d0a509e8ac..6ebca156d8 100644
--- a/public/scss/admin/mobile.scss
+++ b/public/scss/admin/mobile.scss
@@ -1,191 +1,12 @@
-#mobile-menu {
- display: none;
-}
-
@media (max-width: 991px) {
body {
height: 100%;
- }
-
- #panel {
- background-color: inherit;
- min-height: 100%;
- }
-
- body, #panel, .slideout-menu {
- -webkit-overflow-scrolling: touch;
- }
-
- .header {
- height: 58px;
- box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.26);
- position: fixed;
- top: 0px;
- z-index: 5;
-
- #main-page-title {
- bottom: -31px;
- font-size: 20px;
- color: #FFF;
- left: 52px;
- font-weight: 400;
- }
-
- #main-menu {
- display: none;
- }
- }
-
- #mobile-menu {
- width: 22px;
- background: none;
- border: none;
- margin-right: 10px;
- margin-left: -5px;
- outline: none !important;
- display: block;
-
- position: absolute;
- top: 22px;
- left: 22px;
-
- .bar {
- width: 100%;
- height: 2px;
- background: #fff;
- margin-bottom: 3px;
- border-radius: 10px;
- }
- }
-
- #menu {
- background-color: #1D1F20;
- background-image: linear-gradient(145deg, #1D1F20, #404348);
-
- a {
- color: #fff;
- text-decoration: none;
- }
-
- a:hover {
- text-decoration: underline;
- }
- }
-
- .menu-header-title {
- font-weight: 400;
- letter-spacing: 0.5px;
- margin: 0;
- }
-
- .menu-section {
- margin: 25px 0;
-
- &.quick-actions {
- margin: 0;
-
- .button-group {
- display: flex;
- justify-content: center;
- }
-
- .alert {
- border-radius: 0;
-
- .span {
- display: block;
- }
- }
- }
- }
-
- .menu-section-title {
- text-transform: uppercase;
- color: #85888d;
- font-weight: 200;
- font-size: 13px;
- letter-spacing: 1px;
- padding: 0 20px;
- margin:0;
- }
-
- .menu-section-list {
- padding: 0;
- margin: 10px 0;
- list-style: none;
-
- a {
- display: block;
- padding: 10px 20px;
- }
-
- a:hover {
- background-color: rgba(255, 255, 255, 0.1);
- text-decoration: none;
- }
- }
-
- #panel {
- background: white;
- min-height: 100%;
- padding-top: 80px;
- }
-
- .slideout-menu {
- position: fixed;
- left: 0;
- top: 0;
- bottom: 0;
- right: 0;
- z-index: 0;
- width: 256px;
- overflow-y: auto;
- -webkit-overflow-scrolling: touch;
- display: none;
- }
-
-
- .slideout-panel {
- position: relative;
- }
-
- .slideout-open,
- .slideout-open body,
- .slideout-open .slideout-panel {
- overflow: hidden;
- overflow-y: hidden !important;
- }
-
- .slideout-open .slideout-menu {
- display: block;
+ overflow-y: scroll;
+ overflow-x: hidden;
}
html {
height: 100%;
overflow-y: hidden;
}
-
- .slideout-open {
- overflow-y: hidden;
- height: 100%;
- }
-
- body {
- overflow-y: scroll;
- overflow-x: hidden;
- }
}
-
-@media (max-width: 768px) {
- .content-header, .settings-header {
- font-size: 200%;
- margin-bottom: 20px;
- margin-left: -2px;
- }
-
-
- .dropdown-menu {
- margin-top: -35px;
- margin-right: -2px;
- }
-}
\ No newline at end of file
diff --git a/public/scss/admin/modules/search.scss b/public/scss/admin/modules/search.scss
index 57b8d8613e..c25748f85a 100644
--- a/public/scss/admin/modules/search.scss
+++ b/public/scss/admin/modules/search.scss
@@ -1,12 +1,9 @@
-#acp-search {
+.acp-search {
.dropdown-menu {
max-height: 75vh;
overflow-y: auto;
> li > a {
- // &.focus {
- // &:extend(.dropdown-menu>li>a:focus);
- // }
&:focus {
outline: none;
}
diff --git a/public/scss/admin/overrides.scss b/public/scss/admin/overrides.scss
new file mode 100644
index 0000000000..58922bd310
--- /dev/null
+++ b/public/scss/admin/overrides.scss
@@ -0,0 +1,62 @@
+$white: #fff !default;
+$gray-100: #f8f9fa !default;
+$gray-200: #e9ecef !default;
+$gray-300: #dee2e6 !default;
+$gray-400: #ced4da !default;
+$gray-500: #adb5bd !default;
+$gray-600: #6c757d !default;
+$gray-700: #495057 !default;
+$gray-800: #343a40 !default;
+$gray-900: #212529 !default;
+$black: #000 !default;
+
+$blue: #0d6efd !default;
+$red: #dc3545 !default;
+$yellow: #ffc107 !default;
+$green: #198754 !default;
+$cyan: #0dcaf0 !default;
+
+$body-color: $gray-800;
+$text-muted: $gray-600 !default;
+
+// Custom fonts
+$font-family-sans-serif: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+
+$font-family-secondary: "Poppins", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default;
+$font-weight-semibold: 500 !default;
+$font-size-base: 1rem !default;
+
+$link-decoration: none;
+$link-hover-decoration: underline;
+
+// options
+$enable-gradients: false;
+
+// no caret on dropdown-toggle
+$enable-caret: false;
+
+// disable smooth scroll, this makes window.scrollTo(0,0) in ajaxify.js take x milliseconds
+$enable-smooth-scroll: false;
+
+$enable-shadows: true;
+
+
+// Buttons
+$input-btn-padding-y: .4rem !default;
+$input-btn-padding-x: 1rem !default;
+
+// Forms
+
+$input-padding-y: 0.5rem !default;
+$input-padding-x: 0.75rem !default;
+// $input-padding-y-sm: 0 !default;
+// $input-padding-x-sm: 0 !default;
+// $input-padding-y-lg: ($font-size-base * 1.25) !default;
+// $input-padding-x-lg: 0 !default;
+
+$input-btn-focus-color: #c29ffa80 !default;
+$input-border-radius: 0.25rem !default;
+$input-focus-border-color: #c29ffa80 !default;
+// change inset shadow to outset
+$box-shadow-inset: 0 1px 2px rgba($black, .075) !default;
+
diff --git a/public/scss/admin/settings.scss b/public/scss/admin/settings.scss
index e760d71787..e69de29bb2 100644
--- a/public/scss/admin/settings.scss
+++ b/public/scss/admin/settings.scss
@@ -1,20 +0,0 @@
-.settings {
- .section-content {
- border-left: 3px solid $primary;
-
- ul {
- list-style-type: none;
- font-size: 16px;
- padding-left: 20px;
- li:not(:last-child) {
- margin-bottom: 5px;
- }
- a {
- text-decoration: none;
- &:hover{
- text-decoration: underline;
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/public/scss/admin/sidebar.scss b/public/scss/admin/sidebar.scss
new file mode 100644
index 0000000000..0a354fdd6c
--- /dev/null
+++ b/public/scss/admin/sidebar.scss
@@ -0,0 +1,13 @@
+#sidebar-left, #offcanvas {
+ .btn-ghost, .btn-ghost-sm {
+ i {
+ color: $gray-500;
+ }
+ }
+
+ .accordion-body {
+ .btn-ghost-sm {
+ padding-left: 38px!important;
+ }
+ }
+}
\ No newline at end of file
diff --git a/public/scss/admin/vars.scss b/public/scss/admin/vars.scss
deleted file mode 100644
index e5330b8924..0000000000
--- a/public/scss/admin/vars.scss
+++ /dev/null
@@ -1,45 +0,0 @@
-// system font family
-// based on those in [bootstrap@5.0.0-alpha1](https://github.com/twbs/bootstrap/blob/b531bda07cbea2e124194aefe3b8597b3ac2578e/scss/_variables.scss#L386)
-// and [wordpress admin](https://core.trac.wordpress.org/browser/trunk/src/wp-admin/css/common.css?rev=47835#L220)
-// system-ui : supported by the latest browsers for this very purpose
-// apple-system, BlinkMacSystemFont : iOS and MacOS
-// "Segoe UI" : Windows Vista, 7, 8, 10
-// Roboto : Android 4.0+
-// Oxygen-Sans : KDE
-// Ubuntu : Ubuntu
-// Cantarell : GNOME
-// "Helvetica Neue" : Mac OS X
-// Helvetica : backup, better looking than Arial
-// Arial : backup
-// "Noto Sans" : broader language support on Android
-// sans-serif : whatever the browser can give us
-// "Apple Color Emoji" : Emoji on iOS and MacOS
-// "Segoe UI Emoji", "Segoe UI Symbol" : Emoji on Windows
-// "Noto Color Emoji" : Emoji on Android
-$font-family-system: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
-$font-family-sans-serif: $font-family-system;
-$font-size-base: 0.875rem!default;
-
-$body-color: #666!default;
-$light: #f5f5f5;
-
-// options
-$enable-gradients: false;
-// no caret on dropdown-toggle
-$enable-caret: false;
-
-$font-size-base: 1rem !default;
-$font-weight-base: 400 !default;
-
-// Buttons
-$input-btn-padding-y: .4rem !default;
-$input-btn-padding-x: 1rem !default;
-
-// Forms
-
-$input-padding-y: 0.4rem !default;
-$input-padding-x: 0 !default;
-$input-padding-y-sm: 0 !default;
-$input-padding-x-sm: 0 !default;
-$input-padding-y-lg: ($font-size-base * 1.25) !default;
-$input-padding-x-lg: 0 !default;
\ No newline at end of file
diff --git a/public/src/admin/admin.js b/public/src/admin/admin.js
index d65e291ea7..d39046d543 100644
--- a/public/src/admin/admin.js
+++ b/public/src/admin/admin.js
@@ -42,9 +42,17 @@ app.onDomReady();
}
require(['hooks'], (hooks) => {
- hooks.on('action:ajaxify.end', () => {
+ hooks.on('action:ajaxify.end', (data) => {
+ updatePageTitle(data.url);
+ setupRestartLinks();
showCorrectNavTab();
startLogoutTimer();
+
+ $('[data-bs-toggle="tooltip"]').tooltip({
+ animation: false,
+ container: '#content',
+ });
+
if ($('.settings').length) {
require(['admin/settings'], function (Settings) {
Settings.prepare();
@@ -52,21 +60,35 @@ app.onDomReady();
});
}
});
+ hooks.on('action:ajaxify.start', function () {
+ require(['bootstrap'], function (boostrap) {
+ const offcanvas = boostrap.Offcanvas.getInstance('#offcanvas');
+ if (offcanvas) {
+ offcanvas.hide();
+ }
+ });
+ });
});
function showCorrectNavTab() {
- // show correct tab if url has #
- if (window.location.hash) {
- $('.nav-pills a[href="' + window.location.hash + '"]').tab('show');
+ const accordionEl = $('[component="acp/accordion"]');
+ let pathname = window.location.pathname;
+ if (pathname === '/admin') {
+ pathname = '/admin/dashboard';
+ }
+ const selectedButton = accordionEl.find(`a[href="${pathname}"]`);
+ if (selectedButton.length) {
+ accordionEl.find('a').removeClass('active');
+ accordionEl.find('.accordion-collapse').removeClass('show');
+ selectedButton.addClass('active');
+ selectedButton.parents('.accordion-collapse').addClass('show');
}
}
$(document).ready(function () {
- if (!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
- require(['admin/modules/search'], function (search) {
- search.init();
- });
- }
+ require(['admin/modules/search'], function (search) {
+ search.init();
+ });
$('[component="logout"]').on('click', function () {
require(['logout'], function (logout) {
@@ -75,16 +97,25 @@ app.onDomReady();
return false;
});
- configureSlidemenu();
setupNProgress();
+ fixAccordionIds();
});
- $(window).on('action:ajaxify.contentLoaded', function (ev, data) {
- selectMenuItem(data.url);
- setupRestartLinks();
- require('material-design-lite');
- componentHandler.upgradeDom();
- });
+ function fixAccordionIds() {
+ // fix mobile accordion, so it doesn't have same ids as desktop
+ // the same accordion partial is used in both places
+ const offcanvasAccordion = $('#offcanvas #accordionACP');
+ offcanvasAccordion.attr('id', 'accordionACP-offcanvas');
+ offcanvasAccordion.find('[data-bs-target]').each((i, el) => {
+ $(el).attr('data-bs-target', $(el).attr('data-bs-target') + '-offcanvas');
+ });
+ offcanvasAccordion.find('[data-bs-parent]').each((i, el) => {
+ $(el).attr('data-bs-parent', '#accordionACP-offcanvas');
+ });
+ offcanvasAccordion.find('.accordion-collapse').each((i, el) => {
+ $(el).attr('id', $(el).attr('id') + '-offcanvas');
+ });
+ }
function setupNProgress() {
require(['nprogress', 'hooks'], function (NProgress, hooks) {
@@ -98,7 +129,7 @@ app.onDomReady();
});
}
- function selectMenuItem(url) {
+ function updatePageTitle(url) {
require(['translator'], function (translator) {
url = url
.replace(/\/\d+$/, '')
@@ -113,17 +144,8 @@ app.onDomReady();
url = [config.relative_path, url].join('/');
let fallback;
- $('#main-menu li').removeClass('active');
- $('#main-menu a').removeClass('active').filter('[href="' + url + '"]').each(function () {
- const menu = $(this);
- if (menu.parent().attr('data-link')) {
- return;
- }
-
- menu
- .parent().addClass('active')
- .parents('.menu-item').addClass('active');
- fallback = menu.text();
+ $(`[component="acp/accordion"] a[href="${url}"]`).each(function () {
+ fallback = $(this).text();
});
let mainTitle;
@@ -152,9 +174,6 @@ app.onDomReady();
translator.translate(pageTitle, function (title) {
document.title = title.replace(/>/g, '>');
});
- translator.translate(mainTitle, function (text) {
- $('#main-page-title').text(text);
- });
});
}
@@ -164,7 +183,7 @@ app.onDomReady();
// otherwise it can be unloaded when rebuild & restart is run
// the client can't fetch the template file, resulting in an error
benchpress.render('partials/toast', {}).then(function () {
- $('.rebuild-and-restart').off('click').on('click', function () {
+ $('[component="rebuild-and-restart"]').off('click').on('click', function () {
bootbox.confirm('[[admin/admin:alert.confirm-rebuild-and-restart]]', function (confirm) {
if (confirm) {
instance.rebuildAndRestart();
@@ -172,7 +191,7 @@ app.onDomReady();
});
});
- $('.restart').off('click').on('click', function () {
+ $('[component="restart"]').off('click').on('click', function () {
bootbox.confirm('[[admin/admin:alert.confirm-restart]]', function (confirm) {
if (confirm) {
instance.restart();
@@ -182,62 +201,4 @@ app.onDomReady();
});
});
}
-
- function configureSlidemenu() {
- require(['slideout'], function (Slideout) {
- let env = utils.findBootstrapEnvironment();
-
- const slideout = new Slideout({
- panel: document.getElementById('panel'),
- menu: document.getElementById('menu'),
- padding: 256,
- tolerance: 70,
- });
-
- if (env === 'md' || env === 'lg') {
- slideout.disableTouch();
- }
-
- $('#mobile-menu').on('click', function () {
- slideout.toggle();
- });
-
- $('#menu a').on('click', function () {
- slideout.close();
- });
-
- $(window).on('resize', function () {
- slideout.close();
-
- env = utils.findBootstrapEnvironment();
- if (['xxl', 'xl', 'lg'].includes(env)) {
- slideout.disableTouch();
- $('#header').css({
- position: 'relative',
- });
- } else {
- slideout.enableTouch();
- $('#header').css({
- position: 'fixed',
- });
- }
- });
-
- function onOpeningMenu() {
- $('#header').css({
- top: ($('#panel').position().top * -1) + 'px',
- position: 'absolute',
- });
- }
-
- slideout.on('open', onOpeningMenu);
-
- slideout.on('close', function () {
- $('#header').css({
- top: '0px',
- position: 'fixed',
- });
- });
- });
- }
}());
diff --git a/public/src/admin/dashboard.js b/public/src/admin/dashboard.js
index d8bdd5386d..5cab8c9c35 100644
--- a/public/src/admin/dashboard.js
+++ b/public/src/admin/dashboard.js
@@ -43,10 +43,6 @@ define('admin/dashboard', [
isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
- $('[data-bs-toggle="tooltip"]').tooltip({
- animation: false,
- });
-
setupRealtimeButton();
setupGraphs(function () {
socket.emit('admin.rooms.getAll', Admin.updateRoomUsage);
@@ -68,19 +64,19 @@ define('admin/dashboard', [
const html = '' +
@@ -60,11 +60,17 @@ define('admin/modules/search', ['mousetrap', 'alerts'], function (mousetrap, ale
};
function setupACPSearch(dict) {
- const dropdown = $('#acp-search .dropdown');
- const menu = $('#acp-search .dropdown-menu');
- const input = $('#acp-search input');
- const placeholderText = dropdown.attr('data-text');
+ const searchEls = $('[component="acp/search"]');
+ searchEls.each((index, searchEl) => {
+ setupSearch(dict, $(searchEl));
+ });
+ }
+ function setupSearch(dict, searchEl) {
+ const dropdown = searchEl.find('.dropdown');
+ const menu = searchEl.find('.dropdown-menu');
+ const input = searchEl.find('input');
+ const placeholderText = dropdown.attr('data-text');
if (!config.searchEnabled) {
menu.addClass('search-disabled');
}
@@ -73,7 +79,7 @@ define('admin/modules/search', ['mousetrap', 'alerts'], function (mousetrap, ale
dropdown.addClass('open');
});
- $('#acp-search').parents('form').on('submit', function (ev) {
+ searchEl.parents('form').on('submit', function (ev) {
const query = input.val();
const selected = menu.get(0).querySelector('li.result > a.focus') || menu.get(0).querySelector('li.result > a');
const href = selected ? selected.getAttribute('href') : config.relative_path + '/search?in=titlesposts&term=' + escape(query);
diff --git a/public/src/admin/settings.js b/public/src/admin/settings.js
index 26a2f53545..adfec55339 100644
--- a/public/src/admin/settings.js
+++ b/public/src/admin/settings.js
@@ -1,29 +1,55 @@
'use strict';
-define('admin/settings', ['uploader', 'mousetrap', 'hooks', 'alerts', 'settings'], function (uploader, mousetrap, hooks, alerts, settings) {
+define('admin/settings', [
+ 'uploader', 'mousetrap', 'hooks', 'alerts', 'settings', 'bootstrap',
+], function (uploader, mousetrap, hooks, alerts, settings, bootstrap) {
const Settings = {};
Settings.populateTOC = function () {
const headers = $('.settings-header');
+ const tocEl = $('[component="settings/toc"]');
+ const tocList = $('[component="settings/toc/list"]');
+ const mainHader = $('[component="settings/main/header"]');
- if (headers.length > 1) {
+ if (headers.length > 1 && tocList.length) {
headers.each(function () {
const header = $(this).text();
- const anchor = header.toLowerCase().replace(/ /g, '-').trim();
+ const anchor = header.toLowerCase()
+ .replace(/ /g, '-')
+ .replace(/&/g, '-')
+ .trim();
+ $(this).parent().attr('id', anchor);
+ tocList.append(`${header}`);
+ });
+ const offset = mainHader.outerHeight(true);
+ // https://stackoverflow.com/a/11814275/583363
+ tocList.find('a').on('click', function (event) {
+ event.preventDefault();
+ const href = $(this).attr('href');
+ $(href)[0].scrollIntoView();
+ window.location.hash = href;
+ scrollBy(0, -offset);
+ setTimeout(() => {
+ tocList.find('a').removeClass('active');
+ $(this).addClass('active');
+ }, 10);
+ return false;
+ });
- $(this).prepend('');
- $('.section-content ul').append('' + header + ' ');
+ new bootstrap.ScrollSpy($('#spy-container')[0], {
+ target: '#settings-navbar',
+ rootMargin: '-10% 0px -70%',
+ smoothScroll: true,
});
- const scrollTo = $('a[name="' + window.location.hash.replace('#', '') + '"]');
+ const scrollTo = $(`${window.location.hash}`);
if (scrollTo.length) {
$('html, body').animate({
- scrollTop: (scrollTo.offset().top) + 'px',
+ scrollTop: (scrollTo.offset().top - offset) + 'px',
}, 400);
}
- } else {
- $('.content-header').parents('.row').remove();
+ tocEl.removeClass('hidden');
}
};
@@ -117,7 +143,7 @@ define('admin/settings', ['uploader', 'mousetrap', 'hooks', 'alerts', 'settings'
saveBtnEl.classList.toggle('saved', true);
setTimeout(() => {
saveBtnEl.classList.toggle('saved', false);
- }, 5000);
+ }, 2500);
}
};
diff --git a/public/src/admin/settings/general.js b/public/src/admin/settings/general.js
index 805f9f1c8f..65f1f0bce4 100644
--- a/public/src/admin/settings/general.js
+++ b/public/src/admin/settings/general.js
@@ -20,7 +20,19 @@ define('admin/settings/general', ['admin/settings'], function () {
$('button[data-action="removeOgImage"]').on('click', function () {
$('input[data-field="removeOgImage"]').val('');
});
+
+ $('[data-field="homePageRoute"]').on('change', toggleCustomRoute);
+
+ toggleCustomRoute();
};
+ function toggleCustomRoute() {
+ if ($('[data-field="homePageRoute"]').val() === 'custom') {
+ $('#homePageCustom').show();
+ } else {
+ $('#homePageCustom').hide();
+ }
+ }
+
return Module;
});
diff --git a/public/src/admin/settings/homepage.js b/public/src/admin/settings/homepage.js
deleted file mode 100644
index 96447d9bbb..0000000000
--- a/public/src/admin/settings/homepage.js
+++ /dev/null
@@ -1,22 +0,0 @@
-'use strict';
-
-
-define('admin/settings/homepage', ['admin/settings'], function () {
- function toggleCustomRoute() {
- if ($('[data-field="homePageRoute"]').val() === 'custom') {
- $('#homePageCustom').show();
- } else {
- $('#homePageCustom').hide();
- }
- }
-
- const Homepage = {};
-
- Homepage.init = function () {
- $('[data-field="homePageRoute"]').on('change', toggleCustomRoute);
-
- toggleCustomRoute();
- };
-
- return Homepage;
-});
diff --git a/public/src/admin/settings/navigation.js b/public/src/admin/settings/navigation.js
index 6ae9fa1918..c858f8ccc4 100644
--- a/public/src/admin/settings/navigation.js
+++ b/public/src/admin/settings/navigation.js
@@ -163,13 +163,12 @@ define('admin/settings/navigation', [
function toggle() {
const btn = $(this);
- const disabled = btn.hasClass('btn-success');
+ const disabled = btn.hasClass('enable');
const index = btn.parents('[data-index]').attr('data-index');
- translator.translate(disabled ? '[[admin/settings/navigation:btn.disable]]' : '[[admin/settings/navigation:btn.enable]]', function (html) {
- btn.toggleClass('btn-warning').toggleClass('btn-success').html(html);
- btn.parents('li').find('[name="enabled"]').val(disabled ? 'on' : '');
- $('#active-navigation [data-index="' + index + '"] a').toggleClass('text-muted', !disabled);
- });
+ btn.siblings('.toggle').removeClass('hidden');
+ btn.addClass('hidden');
+ btn.parents('li').find('[name="enabled"]').val(disabled ? 'on' : '');
+ $('#active-navigation [data-index="' + index + '"] a').toggleClass('text-muted', !disabled);
return false;
}
diff --git a/public/src/admin/settings/social.js b/public/src/admin/settings/social.js
deleted file mode 100644
index 20e6f87a9f..0000000000
--- a/public/src/admin/settings/social.js
+++ /dev/null
@@ -1,27 +0,0 @@
-'use strict';
-
-
-define('admin/settings/social', ['alerts'], function (alerts) {
- const social = {};
-
- social.init = function () {
- $('#save').on('click', function () {
- const networks = [];
- $('#postSharingNetworks input[type="checkbox"]').each(function () {
- if ($(this).prop('checked')) {
- networks.push($(this).attr('id'));
- }
- });
-
- socket.emit('admin.social.savePostSharingNetworks', networks, function (err) {
- if (err) {
- return alerts.error(err);
- }
-
- alerts.success('[[admin/settings/social:save-success]]');
- });
- });
- };
-
- return social;
-});
diff --git a/public/src/client/groups/memberlist.js b/public/src/client/groups/memberlist.js
index 7a3376eb51..2b8bce8107 100644
--- a/public/src/client/groups/memberlist.js
+++ b/public/src/client/groups/memberlist.js
@@ -22,7 +22,8 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b
title: '[[groups:details.add-member]]',
message: html,
buttons: {
- ok: {
+ OK: {
+ label: '[[groups:details.add-member]]',
callback: function () {
const users = [];
modal.find('[data-uid][data-selected]').each(function (index, el) {
diff --git a/public/src/modules/categoryFilter.js b/public/src/modules/categoryFilter.js
index 271bf83448..169242349b 100644
--- a/public/src/modules/categoryFilter.js
+++ b/public/src/modules/categoryFilter.js
@@ -9,7 +9,7 @@ define('categoryFilter', ['categorySearch', 'api', 'hooks'], function (categoryS
}
options = options || {};
options.states = options.states || ['watching', 'notwatching', 'ignoring'];
- options.template = 'partials/category/filter-dropdown-left';
+ options.template = options.template || 'partials/category/filter-dropdown-left';
hooks.fire('action:category.filter.options', { el: el, options: options });
diff --git a/public/src/modules/categorySearch.js b/public/src/modules/categorySearch.js
index 608ed21275..5dccf8308a 100644
--- a/public/src/modules/categorySearch.js
+++ b/public/src/modules/categorySearch.js
@@ -8,6 +8,7 @@ define('categorySearch', ['alerts', 'bootstrap'], function (alerts, bootstrap) {
options = options || {};
options.privilege = options.privilege || 'topics:read';
options.states = options.states || ['watching', 'notwatching', 'ignoring'];
+ options.cacheList = options.hasOwnProperty('cacheList') ? options.cacheList : true;
let localCategories = [];
if (Array.isArray(options.localCategories)) {
@@ -36,7 +37,7 @@ define('categorySearch', ['alerts', 'bootstrap'], function (alerts, bootstrap) {
const val = searchEl.find('input').val();
if (val.length > 1 || (!val && !categoriesList)) {
loadList(val, function (categories) {
- categoriesList = categoriesList || categories;
+ categoriesList = options.cacheList && (categoriesList || categories);
renderList(categories);
});
} else if (!val && categoriesList) {
diff --git a/public/src/modules/categorySelector.js b/public/src/modules/categorySelector.js
index 1713c28747..3e2bfa5982 100644
--- a/public/src/modules/categorySelector.js
+++ b/public/src/modules/categorySelector.js
@@ -1,8 +1,8 @@
'use strict';
define('categorySelector', [
- 'categorySearch', 'bootbox', 'hooks',
-], function (categorySearch, bootbox, hooks) {
+ 'categorySearch', 'bootbox', 'hooks', 'translator',
+], function (categorySearch, bootbox, hooks, translator) {
const categorySelector = {};
categorySelector.init = function (el, options) {
@@ -13,7 +13,7 @@ define('categorySelector', [
const onSelect = options.onSelect || function () {};
options.states = options.states || ['watching', 'notwatching', 'ignoring'];
- options.template = 'partials/category/selector-dropdown-left';
+ options.template = options.template || 'partials/category/selector-dropdown-left';
hooks.fire('action:category.selector.options', { el: el, options: options });
categorySearch.init(el, options);
@@ -22,15 +22,21 @@ define('categorySelector', [
el: el,
selectedCategory: null,
};
+
el.on('click', '[data-cid]', function () {
const categoryEl = $(this);
if (categoryEl.hasClass('disabled')) {
return false;
}
selector.selectCategory(categoryEl.attr('data-cid'));
- onSelect(selector.selectedCategory);
+ return onSelect(selector.selectedCategory);
+ });
+
+ let defaultSelectHtml = selector.el.find('[component="category-selector-selected"]').html();
+
+ translator.translate(defaultSelectHtml, (translated) => {
+ defaultSelectHtml = translated;
});
- const defaultSelectHtml = selector.el.find('[component="category-selector-selected"]').html();
selector.selectCategory = function (cid) {
const categoryEl = selector.el.find('[data-cid="' + cid + '"]');
selector.selectedCategory = {
@@ -54,6 +60,14 @@ define('categorySelector', [
selector.getSelectedCid = function () {
return selector.selectedCategory ? selector.selectedCategory.cid : 0;
};
+
+ if (options.hasOwnProperty('selectedCategory')) {
+ app.parseAndTranslate(options.template, { selectedCategory: options.selectedCategory }, function (html) {
+ selector.el.find('[component="category-selector-selected"]').html(
+ html.find('[component="category-selector-selected"]').html()
+ );
+ });
+ }
return selector;
};
diff --git a/public/src/modules/iconSelect.js b/public/src/modules/iconSelect.js
index b85fd5af1c..3795c00e23 100644
--- a/public/src/modules/iconSelect.js
+++ b/public/src/modules/iconSelect.js
@@ -323,7 +323,7 @@ define('iconSelect', ['benchpress', 'bootbox'], function (Benchpress, bootbox) {
}
icons.remove();
iconData.forEach((iconData) => {
- iconContainer.append($(``));
+ iconContainer.append($(``));
});
icons = modalEl.find('.nbb-fa-icons i');
changeSelection();
diff --git a/src/categories/index.js b/src/categories/index.js
index 9fc7479a69..3fe5d9d457 100644
--- a/src/categories/index.js
+++ b/src/categories/index.js
@@ -364,6 +364,13 @@ Categories.buildForSelectCategories = function (categories, fields, parentCid) {
const rootCategories = categories.filter(category => category && category.parentCid === parentCid);
+ rootCategories.sort((a, b) => {
+ if (a.order !== b.order) {
+ return a.order - b.order;
+ }
+ return a.cid - b.cid;
+ });
+
rootCategories.forEach(category => recursive(category, categoriesData, '', 0));
const pickFields = [
diff --git a/src/controllers/admin/categories.js b/src/controllers/admin/categories.js
index d901e65f0f..597f8ff55e 100644
--- a/src/controllers/admin/categories.js
+++ b/src/controllers/admin/categories.js
@@ -60,8 +60,9 @@ categoriesController.getAll = async function (req, res) {
}
const fields = [
- 'cid', 'name', 'icon', 'parentCid', 'disabled', 'link', 'order',
- 'color', 'bgColor', 'backgroundImage', 'imageClass', 'subCategoriesPerPage',
+ 'cid', 'name', 'icon', 'parentCid', 'disabled', 'link',
+ 'order', 'color', 'bgColor', 'backgroundImage', 'imageClass',
+ 'subCategoriesPerPage', 'description',
];
const categoriesData = await categories.getCategoriesFields(cids, fields);
const result = await plugins.hooks.fire('filter:admin.categories.get', { categories: categoriesData, fields: fields });
@@ -101,6 +102,7 @@ categoriesController.getAll = async function (req, res) {
breadcrumbs: crumbs,
pagination: pagination.create(page, pageCount, req.query),
categoriesPerPage: meta.config.categoriesPerPage,
+ selectCategoryLabel: '[[admin/manage/categories:jump-to]]',
});
};
diff --git a/src/controllers/admin/settings.js b/src/controllers/admin/settings.js
index e13511816c..210c6ce614 100644
--- a/src/controllers/admin/settings.js
+++ b/src/controllers/admin/settings.js
@@ -18,13 +18,27 @@ const settingsController = module.exports;
settingsController.get = async function (req, res) {
const term = req.params.term || 'general';
- res.render(`admin/settings/${term}`);
+ const payload = {
+ title: `[[admin/menu:settings/${term}]]`,
+ };
+ if (term === 'general') {
+ payload.routes = await helpers.getHomePageRoutes(req.uid);
+ payload.postSharing = await social.getPostSharing();
+ const languageData = await languages.list();
+ languageData.forEach((language) => {
+ language.selected = language.code === meta.config.defaultLang;
+ });
+ payload.languages = languageData;
+ payload.autoDetectLang = meta.config.autoDetectLang;
+ }
+ res.render(`admin/settings/${term}`, payload);
};
settingsController.email = async (req, res) => {
const emails = await emailer.getTemplates(meta.config);
res.render('admin/settings/email', {
+ title: '[[admin/menu:settings/email]]',
emails: emails,
sendable: emails.filter(e => !e.path.includes('_plaintext') && !e.path.includes('partials')).map(tpl => tpl.path),
services: emailer.listServices(),
@@ -38,6 +52,7 @@ settingsController.user = async (req, res) => {
label: `[[notifications:${type}]]`,
}));
res.render('admin/settings/user', {
+ title: '[[admin/menu:settings/user]]',
notificationSettings: notificationSettings,
});
};
@@ -45,6 +60,7 @@ settingsController.user = async (req, res) => {
settingsController.post = async (req, res) => {
const groupData = await groups.getNonPrivilegeGroups('groups:createtime', 0, -1);
res.render('admin/settings/post', {
+ title: '[[admin/menu:settings/post]]',
groupsExemptFromPostQueue: groupData,
});
};
@@ -52,22 +68,11 @@ settingsController.post = async (req, res) => {
settingsController.advanced = async (req, res) => {
const groupData = await groups.getNonPrivilegeGroups('groups:createtime', 0, -1);
res.render('admin/settings/advanced', {
+ title: '[[admin/menu:settings/advanced]]',
groupsExemptFromMaintenanceMode: groupData,
});
};
-settingsController.languages = async function (req, res) {
- const languageData = await languages.list();
- languageData.forEach((language) => {
- language.selected = language.code === meta.config.defaultLang;
- });
-
- res.render('admin/settings/languages', {
- languages: languageData,
- autoDetectLang: meta.config.autoDetectLang,
- });
-};
-
settingsController.navigation = async function (req, res) {
const [admin, allGroups] = await Promise.all([
navigationAdmin.getAdmin(),
@@ -94,23 +99,14 @@ settingsController.navigation = async function (req, res) {
});
admin.navigation = admin.enabled.slice();
-
+ admin.title = '[[admin/menu:settings/navigation]]';
res.render('admin/settings/navigation', admin);
};
-settingsController.homepage = async function (req, res) {
- const routes = await helpers.getHomePageRoutes(req.uid);
- res.render('admin/settings/homepage', { routes: routes });
-};
-
-settingsController.social = async function (req, res) {
- const posts = await social.getPostSharing();
- res.render('admin/settings/social', {
- posts: posts,
- });
-};
-
settingsController.api = async (req, res) => {
const tokens = await api.utils.tokens.list();
- res.render('admin/settings/api', { tokens });
+ res.render('admin/settings/api', {
+ title: '[[admin/menu:settings/api]]',
+ tokens,
+ });
};
diff --git a/src/meta/css.js b/src/meta/css.js
index a51c8d72a8..b667847242 100644
--- a/src/meta/css.js
+++ b/src/meta/css.js
@@ -31,10 +31,8 @@ const buildImports = {
},
admin: function (source) {
return [
- '@import "admin/vars";',
- '@import "bootswatch/dist/materia/variables";',
+ '@import "admin/overrides";',
'@import "bootstrap/scss/bootstrap";',
- '@import "bootswatch/dist/materia/bootswatch";',
'@import "mixins";',
'@import "fontawesome";',
'@import "@adactive/bootstrap-tagsinput/src/bootstrap-tagsinput";',
diff --git a/src/meta/js.js b/src/meta/js.js
index ccba341eaf..065ad2c1f0 100644
--- a/src/meta/js.js
+++ b/src/meta/js.js
@@ -83,6 +83,10 @@ JS.buildModules = async function () {
JS.linkStatics = async function () {
await fs.promises.rm(path.join(__dirname, '../../build/public/plugins'), { recursive: true, force: true });
+
+ plugins.staticDirs['core/inter'] = path.join(basePath, 'node_modules//@fontsource/inter/files');
+ plugins.staticDirs['core/poppins'] = path.join(basePath, 'node_modules//@fontsource/poppins/files');
+
await Promise.all(Object.keys(plugins.staticDirs).map(async (mappedPath) => {
const sourceDir = plugins.staticDirs[mappedPath];
const destDir = path.join(__dirname, '../../build/public/plugins', mappedPath);
diff --git a/src/posts/uploads.js b/src/posts/uploads.js
index 1c23071c5d..c8c12999d5 100644
--- a/src/posts/uploads.js
+++ b/src/posts/uploads.js
@@ -142,6 +142,14 @@ module.exports = function (Posts) {
filePaths = [filePaths];
}
+ if (process.platform === 'win32') {
+ // windows path => 'files\\1685368788211-1-profileimg.jpg'
+ // turn it into => 'files/1685368788211-1-profileimg.jpg'
+ filePaths.forEach((file) => {
+ file.path = file.path.split(path.sep).join(path.posix.sep);
+ });
+ }
+
const keys = filePaths.map(fileObj => `upload:${md5(fileObj.path.replace('-resized', ''))}:pids`);
return await Promise.all(keys.map(k => db.getSortedSetRange(k, 0, -1)));
};
diff --git a/src/routes/admin.js b/src/routes/admin.js
index c7e9c5f060..01e228dabe 100644
--- a/src/routes/admin.js
+++ b/src/routes/admin.js
@@ -35,10 +35,7 @@ module.exports = function (app, name, middleware, controllers) {
helpers.setupAdminPageRoute(app, `/${name}/settings/user`, middlewares, controllers.admin.settings.user);
helpers.setupAdminPageRoute(app, `/${name}/settings/post`, middlewares, controllers.admin.settings.post);
helpers.setupAdminPageRoute(app, `/${name}/settings/advanced`, middlewares, controllers.admin.settings.advanced);
- helpers.setupAdminPageRoute(app, `/${name}/settings/languages`, middlewares, controllers.admin.settings.languages);
helpers.setupAdminPageRoute(app, `/${name}/settings/navigation`, middlewares, controllers.admin.settings.navigation);
- helpers.setupAdminPageRoute(app, `/${name}/settings/homepage`, middlewares, controllers.admin.settings.homepage);
- helpers.setupAdminPageRoute(app, `/${name}/settings/social`, middlewares, controllers.admin.settings.social);
helpers.setupAdminPageRoute(app, `/${name}/settings/api`, middlewares, controllers.admin.settings.api);
helpers.setupAdminPageRoute(app, `/${name}/settings/:term?`, middlewares, controllers.admin.settings.get);
diff --git a/src/social.js b/src/social.js
index c95f2cc3ac..2dd4045024 100644
--- a/src/social.js
+++ b/src/social.js
@@ -3,6 +3,7 @@
const _ = require('lodash');
const plugins = require('./plugins');
const db = require('./database');
+const meta = require('./meta');
const social = module.exports;
@@ -26,9 +27,8 @@ social.getPostSharing = async function () {
},
];
networks = await plugins.hooks.fire('filter:social.posts', networks);
- const activated = await db.getSetMembers('social:posts.activated');
networks.forEach((network) => {
- network.activated = activated.includes(network.id);
+ network.activated = parseInt(meta.config[`post-sharing-${network.id}`], 10) === 1;
});
social.postSharing = networks;
@@ -41,12 +41,16 @@ social.getActivePostSharing = async function () {
};
social.setActivePostSharingNetworks = async function (networkIDs) {
+ // keeping for 1.0.0 upgrade script that uses this function
social.postSharing = null;
- await db.delete('social:posts.activated');
if (!networkIDs.length) {
return;
}
- await db.setAdd('social:posts.activated', networkIDs);
+ const data = {};
+ networkIDs.forEach((id) => {
+ data[`post-sharing-${id}`] = 1;
+ });
+ await db.setObject('config', data);
};
require('./promisify')(social);
diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js
index 1621ef71a0..21165713db 100644
--- a/src/socket.io/admin.js
+++ b/src/socket.io/admin.js
@@ -19,7 +19,6 @@ SocketAdmin.tags = require('./admin/tags');
SocketAdmin.rewards = require('./admin/rewards');
SocketAdmin.navigation = require('./admin/navigation');
SocketAdmin.rooms = require('./admin/rooms');
-SocketAdmin.social = require('./admin/social');
SocketAdmin.themes = require('./admin/themes');
SocketAdmin.plugins = require('./admin/plugins');
SocketAdmin.widgets = require('./admin/widgets');
diff --git a/src/socket.io/admin/social.js b/src/socket.io/admin/social.js
deleted file mode 100644
index 378d736e89..0000000000
--- a/src/socket.io/admin/social.js
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict';
-
-const social = require('../../social');
-
-const SocketSocial = module.exports;
-
-SocketSocial.savePostSharingNetworks = async function (socket, data) {
- await social.setActivePostSharingNetworks(data);
-};
diff --git a/src/upgrades/3.2.0/migrate_post_sharing.js b/src/upgrades/3.2.0/migrate_post_sharing.js
new file mode 100644
index 0000000000..661a9a259e
--- /dev/null
+++ b/src/upgrades/3.2.0/migrate_post_sharing.js
@@ -0,0 +1,19 @@
+'use strict';
+
+const db = require('../../database');
+
+module.exports = {
+ name: 'Migrate post sharing values to config',
+ timestamp: Date.UTC(2023, 4, 23),
+ method: async () => {
+ const activated = await db.getSetMembers('social:posts.activated');
+ if (activated.length) {
+ const data = {};
+ activated.forEach((id) => {
+ data[`post-sharing-${id}`] = 1;
+ });
+ await db.setObject('config', data);
+ await db.delete('social:posts.activated');
+ }
+ },
+};
diff --git a/src/views/admin/advanced/cache.tpl b/src/views/admin/advanced/cache.tpl
index af1c616847..4581b571b1 100644
--- a/src/views/admin/advanced/cache.tpl
+++ b/src/views/admin/advanced/cache.tpl
@@ -1,9 +1,9 @@
-
-
+
+
{{{each caches}}}
-
+
[[admin/advanced/cache:{@key}-cache]]
@@ -52,4 +52,4 @@
-
+
diff --git a/src/views/admin/advanced/database.tpl b/src/views/admin/advanced/database.tpl
index 311ff9deef..4e10d868d7 100644
--- a/src/views/admin/advanced/database.tpl
+++ b/src/views/admin/advanced/database.tpl
@@ -1,146 +1,147 @@
-
-
- {{{ if mongo }}}
-
- {{{ if mongo.serverStatusError }}}
-
- {mongo.serverStatusError}
-
- {{{ end }}}
-
- [[admin/advanced/database:mongo]]
-
-
- [[admin/advanced/database:mongo.version]] {mongo.version}
-
- [[admin/advanced/database:uptime-seconds]] {mongo.uptime}
- [[admin/advanced/database:mongo.storage-engine]] {mongo.storageEngine}
- [[admin/advanced/database:mongo.collections]] {mongo.collections}
- [[admin/advanced/database:mongo.objects]] {mongo.objects}
- [[admin/advanced/database:mongo.avg-object-size]] [[admin/advanced/database:x-b, {mongo.avgObjSize}]]
-
- [[admin/advanced/database:mongo.data-size]] [[admin/advanced/database:x-gb, {mongo.dataSize}]]
- [[admin/advanced/database:mongo.storage-size]] [[admin/advanced/database:x-gb, {mongo.storageSize}]]
- [[admin/advanced/database:mongo.index-size]] [[admin/advanced/database:x-gb, {mongo.indexSize}]]
- {{{ if mongo.fileSize }}}
- [[admin/advanced/database:mongo.file-size]] [[admin/advanced/database:x-gb, {mongo.fileSize}]]
- {{{ end }}}
-
- [[admin/advanced/database:mongo.resident-memory]] [[admin/advanced/database:x-gb, {mongo.mem.resident}]]
- [[admin/advanced/database:mongo.virtual-memory]] [[admin/advanced/database:x-gb, {mongo.mem.virtual}]]
- [[admin/advanced/database:mongo.mapped-memory]] [[admin/advanced/database:x-gb, {mongo.mem.mapped}]]
-
- [[admin/advanced/database:mongo.bytes-in]] [[admin/advanced/database:x-gb, {mongo.network.bytesIn}]]
- [[admin/advanced/database:mongo.bytes-out]] [[admin/advanced/database:x-gb, {mongo.network.bytesOut}]]
- [[admin/advanced/database:mongo.num-requests]] {mongo.network.numRequests}
+
+
+ {{{ if mongo }}}
+
+ {{{ if mongo.serverStatusError }}}
+
+ {mongo.serverStatusError}
+
+ {{{ end }}}
+
+ [[admin/advanced/database:mongo]]
+
+
+ [[admin/advanced/database:mongo.version]] {mongo.version}
+
+ [[admin/advanced/database:uptime-seconds]] {mongo.uptime}
+ [[admin/advanced/database:mongo.storage-engine]] {mongo.storageEngine}
+ [[admin/advanced/database:mongo.collections]] {mongo.collections}
+ [[admin/advanced/database:mongo.objects]] {mongo.objects}
+ [[admin/advanced/database:mongo.avg-object-size]] [[admin/advanced/database:x-b, {mongo.avgObjSize}]]
+
+ [[admin/advanced/database:mongo.data-size]] [[admin/advanced/database:x-gb, {mongo.dataSize}]]
+ [[admin/advanced/database:mongo.storage-size]] [[admin/advanced/database:x-gb, {mongo.storageSize}]]
+ [[admin/advanced/database:mongo.index-size]] [[admin/advanced/database:x-gb, {mongo.indexSize}]]
+ {{{ if mongo.fileSize }}}
+ [[admin/advanced/database:mongo.file-size]] [[admin/advanced/database:x-gb, {mongo.fileSize}]]
+ {{{ end }}}
+
+ [[admin/advanced/database:mongo.resident-memory]] [[admin/advanced/database:x-gb, {mongo.mem.resident}]]
+ [[admin/advanced/database:mongo.virtual-memory]] [[admin/advanced/database:x-gb, {mongo.mem.virtual}]]
+ [[admin/advanced/database:mongo.mapped-memory]] [[admin/advanced/database:x-gb, {mongo.mem.mapped}]]
+
+ [[admin/advanced/database:mongo.bytes-in]] [[admin/advanced/database:x-gb, {mongo.network.bytesIn}]]
+ [[admin/advanced/database:mongo.bytes-out]] [[admin/advanced/database:x-gb, {mongo.network.bytesOut}]]
+ [[admin/advanced/database:mongo.num-requests]] {mongo.network.numRequests}
+
-
- {{{ end }}}
+ {{{ end }}}
- {{{ if redis }}}
-
-
- [[admin/advanced/database:redis]]
-
-
- [[admin/advanced/database:redis.version]] {redis.redis_version}
-
- [[admin/advanced/database:uptime-seconds]] {redis.uptime_in_seconds}
- [[admin/advanced/database:uptime-days]] {redis.uptime_in_days}
-
- [[admin/advanced/database:redis.keys]] {redis.keys}
- [[admin/advanced/database:redis.expires]] {redis.expires}
- [[admin/advanced/database:redis.avg-ttl]] {redis.avg_ttl}
- [[admin/advanced/database:redis.connected-clients]] {redis.connected_clients}
- [[admin/advanced/database:redis.connected-slaves]] {redis.connected_slaves}
- [[admin/advanced/database:redis.blocked-clients]] {redis.blocked_clients}
-
+ {{{ if redis }}}
+
+
+ [[admin/advanced/database:redis]]
+
+
+ [[admin/advanced/database:redis.version]] {redis.redis_version}
+
+ [[admin/advanced/database:uptime-seconds]] {redis.uptime_in_seconds}
+ [[admin/advanced/database:uptime-days]] {redis.uptime_in_days}
+
+ [[admin/advanced/database:redis.keys]] {redis.keys}
+ [[admin/advanced/database:redis.expires]] {redis.expires}
+ [[admin/advanced/database:redis.avg-ttl]] {redis.avg_ttl}
+ [[admin/advanced/database:redis.connected-clients]] {redis.connected_clients}
+ [[admin/advanced/database:redis.connected-slaves]] {redis.connected_slaves}
+ [[admin/advanced/database:redis.blocked-clients]] {redis.blocked_clients}
+
- [[admin/advanced/database:redis.used-memory]] [[admin/advanced/database:x-gb, {redis.used_memory_human}]]
- [[admin/advanced/database:redis.memory-frag-ratio]] {redis.mem_fragmentation_ratio}
-
- [[admin/advanced/database:redis.total-connections-recieved]] {redis.total_connections_received}
- [[admin/advanced/database:redis.total-commands-processed]] {redis.total_commands_processed}
- [[admin/advanced/database:redis.iops]] {redis.instantaneous_ops_per_sec}
+ [[admin/advanced/database:redis.used-memory]] [[admin/advanced/database:x-gb, {redis.used_memory_human}]]
+ [[admin/advanced/database:redis.memory-frag-ratio]] {redis.mem_fragmentation_ratio}
+
+ [[admin/advanced/database:redis.total-connections-recieved]] {redis.total_connections_received}
+ [[admin/advanced/database:redis.total-commands-processed]] {redis.total_commands_processed}
+ [[admin/advanced/database:redis.iops]] {redis.instantaneous_ops_per_sec}
- [[admin/advanced/database:redis.iinput]] [[admin/advanced/database:x-mb, {redis.instantaneous_input}]]
- [[admin/advanced/database:redis.ioutput]] [[admin/advanced/database:x-mb, {redis.instantaneous_output}]]
- [[admin/advanced/database:redis.total-input]] [[admin/advanced/database:x-gb, {redis.total_net_input}]]
- [[admin/advanced/database:redis.total-output]] [[admin/advanced/database:x-gb, {redis.total_net_output}]]
+ [[admin/advanced/database:redis.iinput]] [[admin/advanced/database:x-mb, {redis.instantaneous_input}]]
+ [[admin/advanced/database:redis.ioutput]] [[admin/advanced/database:x-mb, {redis.instantaneous_output}]]
+ [[admin/advanced/database:redis.total-input]] [[admin/advanced/database:x-gb, {redis.total_net_input}]]
+ [[admin/advanced/database:redis.total-output]] [[admin/advanced/database:x-gb, {redis.total_net_output}]]
-
- [[admin/advanced/database:redis.keyspace-hits]] {redis.keyspace_hits}
- [[admin/advanced/database:redis.keyspace-misses]] {redis.keyspace_misses}
+
+ [[admin/advanced/database:redis.keyspace-hits]] {redis.keyspace_hits}
+ [[admin/advanced/database:redis.keyspace-misses]] {redis.keyspace_misses}
+
-
- {{{ end }}}
+ {{{ end }}}
- {{{ if postgres }}}
-
-
- [[admin/advanced/database:postgres]]
-
-
- [[admin/advanced/database:postgres.version]] {postgres.version}
-
- [[admin/advanced/database:uptime-seconds]] {postgres.uptime}
+ {{{ if postgres }}}
+
+
+ [[admin/advanced/database:postgres]]
+
+
+ [[admin/advanced/database:postgres.version]] {postgres.version}
+
+ [[admin/advanced/database:uptime-seconds]] {postgres.uptime}
+
+ {{{ end }}}
- {{{ end }}}
-
-
- {{{ if mongo }}}
-
-
-
- [[admin/advanced/database:mongo.raw-info]]
-
+
+ {{{ if mongo }}}
+
+
+
+ [[admin/advanced/database:mongo.raw-info]]
+
-
-
- {mongo.raw}
+
+
+ {mongo.raw}
+
-
- {{{ end }}}
+ {{{ end }}}
- {{{ if redis }}}
-
-
-
- [[admin/advanced/database:redis.raw-info]]
-
+ {{{ if redis }}}
+
+
+
+ [[admin/advanced/database:redis.raw-info]]
+
-
-
- {redis.raw}
+
+
+ {redis.raw}
+
-
- {{{ end }}}
+ {{{ end }}}
- {{{ if postgres }}}
-
-
-
- [[admin/advanced/database:postgres.raw-info]]
-
+ {{{ if postgres }}}
+
+
+
+ [[admin/advanced/database:postgres.raw-info]]
+
-
-
- {postgres.raw}
+
+
+ {postgres.raw}
+
+ {{{ end }}}
- {{{ end }}}
-
+
\ No newline at end of file
diff --git a/src/views/admin/advanced/errors.tpl b/src/views/admin/advanced/errors.tpl
index bf70584e5a..683b835fee 100644
--- a/src/views/admin/advanced/errors.tpl
+++ b/src/views/admin/advanced/errors.tpl
@@ -1,77 +1,79 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-