{"id":24383848,"url":"https://github.com/cpluspatch/web-business","last_synced_at":"2025-04-11T01:12:40.612Z","repository":{"id":181347438,"uuid":"666623181","full_name":"CPlusPatch/web-business","owner":"CPlusPatch","description":"A customizable CMS written in Vue with a dynamic block system","archived":false,"fork":false,"pushed_at":"2023-11-16T19:33:25.000Z","size":12628,"stargazers_count":6,"open_issues_count":8,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-04-11T01:12:34.182Z","etag":null,"topics":["cms","nuxt","typescript","vue"],"latest_commit_sha":null,"homepage":"https://cpluspatch.com","language":"Vue","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CPlusPatch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-15T03:12:00.000Z","updated_at":"2024-04-02T17:21:51.000Z","dependencies_parsed_at":"2024-12-06T17:39:51.386Z","dependency_job_id":null,"html_url":"https://github.com/CPlusPatch/web-business","commit_stats":null,"previous_names":["cpluspatch/web-business"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CPlusPatch%2Fweb-business","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CPlusPatch%2Fweb-business/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CPlusPatch%2Fweb-business/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CPlusPatch%2Fweb-business/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CPlusPatch","download_url":"https://codeload.github.com/CPlusPatch/web-business/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248322571,"owners_count":21084337,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cms","nuxt","typescript","vue"],"created_at":"2025-01-19T10:16:19.265Z","updated_at":"2025-04-11T01:12:40.594Z","avatar_url":"https://github.com/CPlusPatch.png","language":"Vue","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CPlusPatch CMS\n\nA fast, sleek and beautiful website + full content management system developed with NuxtJS.\n\nIt is designed to be minimal but efficient, secure and lightweight.\n\nCPlusPatch CMS is a customizable system for making blogs and personal pages with a dynamic Vue-based templating engine. This is a project in **beta**, and as such should be treated as unstable.\n\n\u003cimg src=\"assets/readme/devices-editor.webp\" /\u003e\n\u003cimg src=\"assets/readme/cms.webp\" /\u003e\n\u003cimg src=\"assets/readme/admin-panel.webp\" /\u003e\n\u003cimg src=\"assets/readme/cms-editor.png\" /\u003e\n\u003cimg src=\"assets/readme/login-page.webp\" /\u003e\n## Requirements\n\n- A system that can run Node.js (Linux is HEAVILY recommended), or Docker on Linux\n- An S3 or S3 compatible bucket (for example, Cloudflare R2)\n\n## Downloading and running\n\nYou may use the `docker-compose.yml` file included in this repository to bootstrap a working environment very fast.\n\nAlternatively, download and install manually:\n\n```bash\ngit clone https://codeberg.org/CPlusPatch/web-business.git\ncd web-business\npnpm install\n```\n\nThen, fill out .env with credentials for the S3 or S3-compatible bucket (such as Cloudflare R2, which I am using) and for PostgreSQL.\n\n```bash\ncp .env.example .env\n```\n\nFor the CDN URL, do not include a trailing slash at the end.\n\nDon't forget to rename `config/config.example.toml` to `config.toml`!\n\n## Building manually\n\n```bash\npnpm build # Bundles project into JS files\n\n# EITHER\npnpm preview # For testing\npm2 start ecosystem.config.js # For production deployment with PM2\n```\n\n## Administration\n\n### Adding new users (for now)\n\n**NOTE: These instructions are temporary, an admin panel for adding users is coming soon**\n\nYou may use the following JS scripts to generate a hashed password with Node's `crypto` library:\n\n```js\nimport { randomBytes, pbkdf2 } from \"crypto\";\n\nexport function createSalt(length = 128) {\n\treturn randomBytes(length).toString(\"base64\");\n}\n\nexport function createPasswordHash(\n\tpassword,\n\tsalt = \"\",\n\titerations = 10000\n) {\n\treturn new Promise((resolve, reject) =\u003e {\n\t\tpbkdf2(password, salt, iterations, 100, \"sha256\", (err, derivedKey) =\u003e {\n\t\t\tif (err) return reject(err);\n\t\t\treturn resolve(`${derivedKey.toString(\"hex\")}:${salt}`);\n\t\t});\n\t});\n}\n```\n\nTo use it, run `createSalt` to generate a random salt, then run `createPasswordHash(\"your password here\", salt)` to generate a new salted password.\n\nPasswords are stored as `hash:salt` in the database, and `createPasswordHash` outputs this format.\n\nTo continue, you will need some kind of PostgreSQL browser and a working instance of the web app: more administration tools are coming soon.\n\nOpen to the `user` table, and insert the following row:\n```\n┌────────────┬───────────────────┬───────────────┬──────────────────────┐\n│  username  │   display_name    │ oauthAccounts │       password       │\n├────────────┼───────────────────┼───────────────┼──────────────────────┤\n│ A username │ New display name  │ []            │ \u003cpassword hash here\u003e │\n└────────────┴───────────────────┴───────────────┴──────────────────────┘\n```\n\nAll the other fields may be left blank or will be generated automatically. If the user needs to be an admin, that is a creator of posts, insert this row instead:\n\n```\n┌────────────┬───────────────────┬───────────────┬──────────────────────┬───────┐\n│  username  │   display_name    │ oauthAccounts │       password       │ role  │\n├────────────┼───────────────────┼───────────────┼──────────────────────┼───────┤\n│ A username │ New display name  │ []            │ \u003cpassword hash here\u003e │ admin │\n└────────────┴───────────────────┴───────────────┴──────────────────────┴───────┘\n\n```\n\nYou can save and login with your new credentials now.\n\n## Scripts for development\n\n### Images\n\nConvert all JPEG images to WebP (uses ImageMagick)\n```bash\nmagick mogrify -format webp *.jpeg\n```\nConvert all JPEG images to WebP (uses ImageMagick)\n\nResize all images to 250x250 (when adding languages to `/public/static/languages/`)\n```bash\nmogrify -path . -auto-orient -thumbnail 250x *.png\n```\n\n## Writing custom templates\n\nTo add custom templates to the CMS block system, open the `templates/` directory, then create two files inside a category folder: `TemplateName.vue` and `TemplateName.json`. You may also create new folders, the location doesn't matter as long as it's inside `templates/`.\n\nInside the `.vue` file you may write a new Vue component. You will need to add this block of code:\n\n```vue\n\u003cscript setup lang=\"ts\"\u003e\ndefineProps\u003c{\n\teditable: boolean;\n\t// You may add arbitrary props here\n}\u003e();\n\u003c/script\u003e\n```\nYou may use TypeScript and all classes provided by [https://unocss.dev/](UnoCSS), as well as NuxtJS 3.6 utilities and any package that is included in `package.json` (such as `nuxt-img`).\n\nHere is an example for a big hero header:\n\n```vue\n\u003cscript setup lang=\"ts\"\u003e\ndefineProps\u003c{\n\timageMain?: string;\n\teditable: boolean;\n}\u003e();\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n\t\u003c!-- Main hero --\u003e\n\t\u003cdiv class=\"relative px-4 mx-auto max-w-7xl w-full sm:px-6\"\u003e\n\t\t\u003cnuxt-img\n\t\t\tpreload\n\t\t\t:width=\"1920\"\n\t\t\t:height=\"1080\"\n\t\t\tsizes=\"lg:1920px md:700px sm:400px\"\n\t\t\tclass=\"rounded-lg aspect-video shadow-lg w-full duration-150\"\n\t\t\t:src=\"\n\t\t\t\timageMain === '' ? 'https://placehold.co/1920x1080' : imageMain\n\t\t\t\"\n\t\t\talt=\"VSCode screenshot\" /\u003e\n\t\u003c/div\u003e\n\u003c/template\u003e\n\n```\n\nIt is recommended that you look at other files inside `templates` to get a hang of the syntax.\n\n### Syntax for the metadata\n\nOnce your component is written, you may add your template metadata to `TemplateName.json`, like this:\n\n```json\n{\n\t\"category\": \"heroes\",\n\t\"name\": \"BigHero\",\n\t\"displayName\": \"Big Banner\",\n\t\"description\": \"Big banner for showing off an image\",\n\t\"inputs\": {\n\t\t\"image-main\": \"string\"\n\t},\n\t\"defaults\": {\n\t\t\"image-main\": \"\"\n\t}\n}\n```\n\nThis will allow you to auto-generate the configuration panel for your component.\n\nThe syntax for `inputs` goes as follow:\n\n**Input types**\n```json\n\"inputs\": {\n\t\"header-image\": \"image\",\n\t\"large-text\": \"paragraph\",\n\t\"text-input\": \"string\",\n\t\"invert-order\": \"boolean\",\n}\n```\n\n**Arrays**\n\nArrays can be declared with an array of a single object, which will be the type of all objects in the array. You can nest arrays inside arrays at will.\n```json\n\"inputs\": {\n\t\"grid\": [\n\t\t{\n\t\t\t\"id\": \"string\",\n\t\t\t\"tags\": [\n\t\t\t\t{\n\t\t\t\t\t\"id\": \"string\",\n\t\t\t\t\t\"name\": \"string\",\n\t\t\t\t\t\"color\": \"string\",\n\t\t\t\t\t\"text-color\": \"string\"\n\t\t\t\t}\n\t\t\t],\n\t\t\t\"description\": \"string\",\n\t\t\t\"name\": \"string\",\n\t\t\t\"href\": \"string\"\n\t\t}\n\t]\n},\n```\n\n\u003e **Note**: These `input` attributes will be passed to the Vue component as props, so their name will be converted to camelCase (e.g. `image-main` will be converted to `imageMain`)\n\n\n## Attributions\n\nI will add more attributions when I find the image sources (mostly logos)\n\nEvan You, https://github.com/yyx990803, CC BY 4.0 \n\u003chttps://creativecommons.org/licenses/by/4.0\u003e, via Wikimedia Commons, for the VueJS logo\n\n## Internals\n\nData is stored inside a PostgreSQL database.\n\nWhen uploading images, they are converted to WebP inside the browser itself before upload.\n\n---\nLicensed under GPLv3. Made with 💕","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcpluspatch%2Fweb-business","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcpluspatch%2Fweb-business","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcpluspatch%2Fweb-business/lists"}