Compare commits
4 Commits
2c78017019
...
c3d90140b7
| Author | SHA1 | Date | |
|---|---|---|---|
| c3d90140b7 | |||
| a9c1a3a8fe | |||
| 6350e23692 | |||
| 9a7b54c343 |
@@ -1,7 +1,6 @@
|
||||
backend:
|
||||
name: gitea
|
||||
repo: bennolor/hugoblog # Path to your Gitea repository
|
||||
branch: master
|
||||
app_id: 10f0fe83-402c-4beb-b732-386fc394b4b5 # The Client ID provided by Gitea
|
||||
api_root: https://gitea.benno-lorenz.com/api/v1 # API URL of your Gitea instance
|
||||
base_url: https://gitea.benno-lorenz.com # Root URL of your Gitea instance
|
||||
@@ -10,7 +9,7 @@ media_folder: "static/images/uploads" # Media files will be stored here
|
||||
public_folder: "/images/uploads" # The src attribute for uploaded media
|
||||
|
||||
collections:
|
||||
- name: "posts" # Used in routes, e.g., /admin/collections/blog
|
||||
- name: "blogposts" # Used in routes, e.g., /admin/collections/blog
|
||||
label: "Blog Posts" # Used in the UI
|
||||
folder: "content/posts" # The path to the folder where the documents are stored
|
||||
create: true # Allow users to create new documents in this collection
|
||||
@@ -35,11 +34,43 @@ collections:
|
||||
- { label: "Date", name: "date", widget: "datetime" }
|
||||
- { label: "Draft", name: "draft", widget: "boolean", default: true }
|
||||
|
||||
- { label: "Cover Image", name: "image", widget: "prefixed-image", required : false }
|
||||
- { label: "Cover Image", name: "image", widget: "image", required : false }
|
||||
- { label: "Cover Style", name: "cover_style", widget: "select", options: ["basic", "big", "background", "thumbAndBackground"], default: "default" }
|
||||
|
||||
|
||||
|
||||
- { label: "images", name: "images", widget: "image", multiple: true }
|
||||
- { label: "Body", name: "body", widget: "markdown" }
|
||||
|
||||
########################
|
||||
# POSTS COLLECTION
|
||||
########################
|
||||
- name: "posts"
|
||||
label: "Posts"
|
||||
folder: "content/posts"
|
||||
path: "{{year}}-{{month}}-{{day}}-{{title}}/index"
|
||||
media_folder: ""
|
||||
public_folder: ""
|
||||
create: true
|
||||
slug: "index"
|
||||
# Nested can be used for deeper than 2 layers of folders
|
||||
# nested:
|
||||
# depth: 100 # max depth to show in the collection tree
|
||||
# summary: '{{title}}' # optional summary for a tree node, defaults to the inferred title field
|
||||
editor:
|
||||
preview: false
|
||||
fields:
|
||||
# - { label: "Layout", name: "layout", widget: "hidden", default: "post" }
|
||||
- { label: "Title", name: "title", widget: "string" }
|
||||
- { label: "Summary", name: "summary", widget: "string" }
|
||||
# - { label: "Description", name: "description", widget: "string" }
|
||||
- {
|
||||
label: "Authors",
|
||||
name: "authors",
|
||||
widget: "select",
|
||||
multiple: true,
|
||||
options: ["bob", "jane", "peter", "kate"],
|
||||
}
|
||||
- { label: "Date", name: "date", widget: "datetime" }
|
||||
- { label: "Draft", name: "draft", widget: "boolean", default: true }
|
||||
- { label: "Cover Image", name: "image", widget: "image" }
|
||||
- { label: "Body", name: "body", widget: "markdown" }
|
||||
|
||||
@@ -15,128 +15,8 @@
|
||||
<body>
|
||||
<!-- Include the script that builds the page and powers Decap CMS -->
|
||||
<script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
|
||||
<script>
|
||||
// Register the proper prefixed image widget
|
||||
CMS.registerWidget("prefixed-image", {
|
||||
// Control component (what editors interact with)
|
||||
control: createClass({
|
||||
handleChange: function(e) {
|
||||
const file = e.target.files[0];
|
||||
if (!file) return;
|
||||
|
||||
// Add prefix to filename
|
||||
const prefix = "feature-";
|
||||
const fileName = file.name.startsWith(prefix) ? file.name : prefix + file.name;
|
||||
const newFile = new File([file], fileName, { type: file.type });
|
||||
|
||||
// Upload the file with the new name
|
||||
this.props.mediaPersist([newFile]).then(urls => {
|
||||
if (urls && urls.length > 0) {
|
||||
this.props.onChange(urls[0]);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const value = this.props.value;
|
||||
return h('div', {},
|
||||
h('input', {
|
||||
type: 'file',
|
||||
accept: 'image/*',
|
||||
onChange: this.handleChange
|
||||
}),
|
||||
value && h('img', {
|
||||
src: value,
|
||||
alt: '',
|
||||
style: { maxWidth: '200px', marginTop: '10px' }
|
||||
})
|
||||
);
|
||||
}
|
||||
}),
|
||||
|
||||
// Preview component (how it appears in the preview pane)
|
||||
preview: createClass({
|
||||
render: function() {
|
||||
return this.props.value ?
|
||||
h('img', {
|
||||
src: this.props.value,
|
||||
alt: '',
|
||||
style: { maxWidth: '100%' }
|
||||
}) : null;
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Register the OSM shortcode as an editor component
|
||||
window.CMS.registerEditorComponent({
|
||||
id: "osm",
|
||||
label: "OpenStreetMap",
|
||||
fields: [
|
||||
{ name: "lat", label: "Latitude", widget: "string" },
|
||||
{ name: "lon", label: "Longitude", widget: "string" },
|
||||
{ name: "zoom", label: "Zoom", widget: "number", default: 15, required: false },
|
||||
{ name: "height", label: "Height (e.g. 400px)", widget: "string", default: "400px", required: false }
|
||||
],
|
||||
pattern: /{{<\s*osm\s+lat="([^"]+)"\s+lon="([^"]+)"(?:\s+zoom="([^"]+)")?(?:\s+height="([^"]+)")?\s*>}}/,
|
||||
fromBlock: function (match) {
|
||||
return {
|
||||
lat: match[1],
|
||||
lon: match[2],
|
||||
zoom: match[3] || "15",
|
||||
height: match[4] || "400px"
|
||||
};
|
||||
},
|
||||
toBlock: function (obj) {
|
||||
let params = `lat="${obj.lat}" lon="${obj.lon}"`;
|
||||
if (obj.zoom) params += ` zoom="${obj.zoom}"`;
|
||||
if (obj.height) params += ` height="${obj.height}"`;
|
||||
return `{{< osm ${params} >}}`;
|
||||
},
|
||||
toPreview: function (obj) {
|
||||
// Simple preview (not interactive)
|
||||
return `<div style="border:1px solid #ccc;padding:1em;">
|
||||
<strong>OpenStreetMap Widget</strong><br>
|
||||
Lat: ${obj.lat}, Lon: ${obj.lon}, Zoom: ${obj.zoom || 15}, Height: ${obj.height || "400px"}
|
||||
</div>`;
|
||||
}
|
||||
});
|
||||
|
||||
// Register the carousel shortcode as an editor component
|
||||
window.CMS.registerEditorComponent({
|
||||
id: "carousel",
|
||||
label: "Image Carousel",
|
||||
fields: [
|
||||
{ name: "images", label: "Images (comma-separated filenames or URLs)", widget: "string" },
|
||||
{ name: "aspectRatio", label: "Aspect Ratio (e.g. 16-9)", widget: "string", required: false },
|
||||
{ name: "interval", label: "Interval (ms)", widget: "number", required: false }
|
||||
],
|
||||
pattern: /{{<\s*carousel\s+images="([^"]+)"(?:\s+aspectRatio="([^"]+)")?(?:\s+interval="([^"]+)")?\s*>}}/,
|
||||
fromBlock: function (match) {
|
||||
return {
|
||||
images: match[1],
|
||||
aspectRatio: match[2] || "",
|
||||
interval: match[3] || ""
|
||||
};
|
||||
},
|
||||
toBlock: function (obj) {
|
||||
let params = `images="${obj.images}"`;
|
||||
if (obj.aspectRatio) params += ` aspectRatio="${obj.aspectRatio}"`;
|
||||
if (obj.interval) params += ` interval="${obj.interval}"`;
|
||||
return `{{< carousel ${params} >}}`;
|
||||
},
|
||||
toPreview: function (obj) {
|
||||
// Simple preview (not interactive)
|
||||
return `<div style="border:1px solid #ccc;padding:1em;">
|
||||
<strong>Image Carousel</strong><br>
|
||||
Images: ${obj.images}<br>
|
||||
Aspect Ratio: ${obj.aspectRatio || "16-9"}<br>
|
||||
Interval: ${obj.interval || "2000"} ms
|
||||
</div>`;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user