Svelte-strapi-tutorial VS Tailwind CSS

Compare Svelte-strapi-tutorial vs Tailwind CSS and see what are their differences.

SurveyJS - Open-Source JSON Form Builder to Create Dynamic Forms Right in Your App
With SurveyJS form UI libraries, you can build and style forms in a fully-integrated drag & drop form builder, render them in your JS app, and store form submission data in any backend, inc. PHP, ASP.NET Core, and Node.js.
surveyjs.io
featured
InfluxDB - Power Real-Time Data Analytics at Scale
Get real-time insights from all types of time series data with InfluxDB. Ingest, query, and analyze billions of data points in real-time with unbounded cardinality.
www.influxdata.com
featured
Svelte-strapi-tutorial Tailwind CSS
1 1,286
7 78,889
- 1.6%
10.0 9.4
about 2 years ago 2 days ago
Svelte TypeScript
- MIT License
The number of mentions indicates the total number of mentions that we've tracked plus the number of user suggested alternatives.
Stars - the number of stars that a project has on GitHub. Growth - month over month growth in stars.
Activity is a relative number indicating how actively a project is being developed. Recent commits have higher weight than older ones.
For example, an activity of 9.0 indicates that a project is amongst the top 10% of the most actively developed projects that we are tracking.

Svelte-strapi-tutorial

Posts with mentions or reviews of Svelte-strapi-tutorial. We have used some of these posts to build our list of alternatives and similar projects. The last one was on 2022-05-10.
  • How to Create a Blog with SvelteKit and Strapi
    8 projects | dev.to | 10 May 2022
    Title Description Content
    Submit
    label { @apply font-bold block mb-1; } input { @apply bg-white w-full border border-gray-500 rounded outline-none py-2 px-4; } textarea { @apply bg-white w-full border border-gray-500 rounded outline-none py-2 px-4 resize-y; } .submit { @apply bg-blue-500 text-white border-transparent rounded px-4 py-2; }
    Enter fullscreen mode Exit fullscreen mode

    `

    Don't try this out yet, since there's currently no way to determine the Author of the PostPost. We need to code that in Strapi explicitly.

    Let's create custom controllers for the Post content type. Here, we'll make it so that the Author of a post will be the currently logged-in User.

    Edit api/post/controllers/post.js in the Strapi project.

    `

    'use strict';
    /**
     *  post controller
     */
    const { createCoreController } = require('@strapi/strapi').factories;
    const { parseMultipartData, sanitizeEntity } = require("strapi-utils");
    /**
     * Read the documentation (https://docs.strapi.io/developer-docs/latest/development/backend-customization.html#core-controllers)
     * to customize this controller
     */
    module.exports = {
        async create(ctx) {
            let entity;
            if (ctx.is("multipart")) {
                const { data, files } = parseMultipartData(ctx);
                data.author = ctx.state.user.id;
                entity = await strapi.services.post.create(data, { files });
            } else {
                ctx.request.body.author = ctx.state.user.id;
                entity = await strapi.services.post.create(ctx.request.body);
            }
            return sanitizeEntity(entity, { model: strapi.models.post });
        },
        async update(ctx) {
            const { id } = ctx.params;
            let entity;
            const [article] = await strapi.services.post.find({
                id: ctx.params.id,
                "author.id": ctx.state.user.id,
            });
            if (!article) {
                return ctx.unauthorized(`You can't update this entry`);
            }
            if (ctx.is("multipart")) {
                const { data, files } = parseMultipartData(ctx);
                entity = await strapi.services.post.update({ id }, data, {
                    files,
                });
            } else {
                entity = await strapi.services.post.update({ id }, ctx.request.body);
            }
            return sanitizeEntity(entity, { model: strapi.models.post });
        },
        async delete(ctx) {
            const { id } = ctx.params;
            let entity;
            const [article] = await strapi.services.post.find({
                id: ctx.params.id,
                "author.id": ctx.state.user.id,
            });
            if (!article) {
                return ctx.unauthorized(`You can't delete this entry`);
            }
            await strapi.services.post.delete({ id });
            return { ok: true };
        },
    };
    module.exports = createCoreController('api::post.post');
    
    Enter fullscreen mode Exit fullscreen mode

    `

    If you get confused, checkout the Strapi Documentation

    Install strapi-utils with the following command.
    bash
    npm install strapi-utils

    And now, you should be able to create and update posts all from one route. Let's make the update process easier. Change src/routes/blog/[id].svelte to the code below:

    `js


    import type { Load } from '@sveltejs/kit';
    export const load: Load = async ({ params, fetch }) => {

            // Now, we'll fetch the blog post from Strapi
            const res = await fetch(`http://localhost:1337/api/posts/${params.id}?populate=*`);
            // A 404 status means "NOT FOUND"
            if (res.status === 404) {
                // We can create a custom error and return it.
                // SvelteKit will automatically show us an error page that we'll learn to customise later on.
                const error = new Error(`The post with ID ${params.id} was not found`);
                return { status: 404, error };
            } else {
                const response = await res.json();
                return { props: { post: response.data.attributes } };
            }
        };
    
    
            import type { Post } from '$lib/types';
            import { onMount } from 'svelte';
            import { goto } from '$app/navigation';
            import user from '$lib/user';
        export let post: Post;
        let content = post.content;
        onMount(async () => {
            // Install the marked package first!
            // Run this command: npm i marked
            // We're using this style of importing because "marked" uses require, which won't work when we import it with SvelteKit.
            // Check the "How do I use a client-side only library" in the FAQ: https://kit.svelte.dev/faq
            const marked = (await import('marked')).default;
            content = marked(post.content);
        });
        async function deletePost() {
                // TODO
            }
    
    

    {post.title}

    By: {post.author.data.attributes.username}

    {#if $user && post.author.id === $user.id}

    goto('/new?edit=' + post.id)}>Update post Delete post

    {/if}
    {@html content}

    `

    Now, when the Author visits their PostPost, they'll see two buttons to Update and Delete the PostPost, respectively.

    Don't try this out yet, since there's currently no way to determine the Author of the PostPost. We need to code that in Strapi explicitly.
    Let's create custom controllers for the Post content type. Here, we'll make it so that the Author of a post will be the currently logged-in User.
    Edit api/post/controllers/post.js in the Strapi project.

    `

        "use strict";
    
        const { parseMultipartData, sanitizeEntity } = require("strapi-utils");
    
        /**
         * Read the documentation (https://docs.strapi.io/developer-docs/latest/development/backend-customization.html#core-controllers)
         * to customize this controller
         */
    
        module.exports = {
          async create(ctx) {
            let entity;
    
            if (ctx.is("multipart")) {
              const { data, files } = parseMultipartData(ctx);
              data.author = ctx.state.user.id;
              entity = await strapi.services.post.create(data, { files });
            } else {
              ctx.request.body.author = ctx.state.user.id;
              entity = await strapi.services.post.create(ctx.request.body);
            }
    
            return sanitizeEntity(entity, { model: strapi.models.post });
          },
    
          async update(ctx) {
            const { id } = ctx.params;
    
            let entity;
    
            const [article] = await strapi.services.post.find({
              id: ctx.params.id,
              "author.id": ctx.state.user.id,
            });
    
            if (!article) {
              return ctx.unauthorized(`You can't update this entry`);
            }
    
            if (ctx.is("multipart")) {
              const { data, files } = parseMultipartData(ctx);
              entity = await strapi.services.post.update({ id }, data, {
                files,
              });
            } else {
              entity = await strapi.services.post.update({ id }, ctx.request.body);
            }
    
            return sanitizeEntity(entity, { model: strapi.models.post });
          },
        };
    

    `

    If you get confused, checkout the Strapi Documentation

    And now, you should be able to create and update posts all from one route. Let's make the update process easier. Change src/routes/blog/[slug].svelte to the code below:

    `

    
        
            import type { Load } from '@sveltejs/kit';
    
            export const load: Load = async ({ page: { params }, fetch }) => {
                // The params object will contain all of the parameters in the route.
                const { slug } = params;
    
                // Now, we'll fetch the blog post from Strapi
                const res = await fetch('http://localhost:1337/posts/' + slug);
    
                // A 404 status means "NOT FOUND"
                if (res.status === 404) {
                    // We can create a custom error and return it.
                    // SvelteKit will automatically show us an error page that we'll learn to customise later on.
                    const error = new Error(`The post with ID ${slug} was not found`);
                    return { status: 404, error };
                } else {
                    const data = await res.json();
                    return { props: { post: data } };
                }
            };
        
    
        
            import type { Post } from '$lib/types';
            import { onMount } from 'svelte';
            import { goto } from '$app/navigation';
            import user from '$lib/user';
    
            export let post: Post;
            let content = post.content;
    
            onMount(async () => {
                // Install the marked package first!
                // Run this command: npm i marked
    
                // We're using this style of importing because "marked" uses require, which won't work when we import it with SvelteKit.
                // Check the "How do I use a client-side only library" in the FAQ: https://kit.svelte.dev/faq
                const marked = (await import('marked')).default;
                content = marked(post.content);
            });
    
            async function deletePost() {
                // TODO
            }
        
    
        

    {post.title}

    By: {post.author.username}

    {#if $user && post.author.id === $user.id}

    goto('/new?edit=' + post.id)}>Update post Delete post

    {/if}
    {@html content}

    `

    Now, when the Author visits their PostPost, they'll see two buttons to Update and Delete the PostPost, respectively.

    Deleting Posts

    Let's add functionality to the Delete Post button. Edit the deletePost() function in the file we just modified (src/routes/blog/[id].svelte) and change it to this:

    `

        async function deletePost() {
            if (!localStorage.getItem('token')) {
                goto('/login');
                return;
            }
            const res = await fetch('http://localhost:1337/api/posts/' + post.id, {
                method: 'DELETE',
                headers: { Authorization: 'Bearer ' + localStorage.getItem('token') }
            });
            if (res.ok) {
                goto('/');
            } else {
                const data: { message: { messages: { message: string }[] }[] } = await res.json();
                if (data?.message?.[0]?.messages?.[0]?.message) {
                    alert(data.message[0].messages[0].message);
                }
            }
        }
    

    `
    Now, obviously, we don't want anybody to delete a post by someone else. Let's add another method in api/post/controllers/post.js in our Strapi App.

    This is how your code should look now:

    `

    'use strict';
    /**
     *  post controller
     */
    const { createCoreController } = require('@strapi/strapi').factories;
    const { parseMultipartData, sanitizeEntity } = require("strapi-utils");
    /**
     * Read the documentation (https://docs.strapi.io/developer-docs/latest/development/backend-customization.html#core-controllers)
     * to customize this controller
     */
    module.exports = {
        async create(ctx) {
            let entity;
            if (ctx.is("multipart")) {
                const { data, files } = parseMultipartData(ctx);
                data.author = ctx.state.user.id;
                entity = await strapi.services.post.create(data, { files });
            } else {
                ctx.request.body.author = ctx.state.user.id;
                entity = await strapi.services.post.create(ctx.request.body);
            }
            return sanitizeEntity(entity, { model: strapi.models.post });
        },
        async update(ctx) {
            const { id } = ctx.params;
            let entity;
            const [article] = await strapi.services.post.find({
                id: ctx.params.id,
                "author.id": ctx.state.user.id,
            });
            if (!article) {
                return ctx.unauthorized(`You can't update this entry`);
            }
            if (ctx.is("multipart")) {
                const { data, files } = parseMultipartData(ctx);
                entity = await strapi.services.post.update({ id }, data, {
                    files,
                });
            } else {
                entity = await strapi.services.post.update({ id }, ctx.request.body);
            }
            return sanitizeEntity(entity, { model: strapi.models.post });
        },
        async delete(ctx) {
            const { id } = ctx.params;
            let entity;
            const [article] = await strapi.services.post.find({
                id: ctx.params.id,
                "author.id": ctx.state.user.id,
            });
            if (!article) {
                return ctx.unauthorized(`You can't delete this entry`);
            }
            await strapi.services.post.delete({ id });
            return { ok: true };
        },
    };
    module.exports = createCoreController('api::post.post');
    

    `

    And now, the author should be able to delete posts.

    Custom Error Page

    You may have noticed that the 404 page looks terrible. It has almost no styling. With SvelteKit, we're allowed to create a custom error page. So we need to name this file __error.svelte and place it in src/routes.

    `

    
    
        import type { ErrorLoad } from '@sveltejs/kit';
        export type { ErrorLoad } from '@sveltejs/kit';
        export const load: ErrorLoad = ({ error, status }) => {
            return { props: { error, status } };
        };
    
    
        export let error: Error;
        export let status: number;
    
    

    {status}

    {error.message}

    `

    Here's how our error page will look like when you search for a blog post with wrong id.

    The Error Page

    Much better right?

    Now, obviously, we don't want anybody to delete a post by someone else. Let's add another method in
    api/post/controllers/post.js in our Strapi App.
    This is how your code should look now:

    `
    // api/post/controllers/post.js
    "use strict";

        const { parseMultipartData, sanitizeEntity } = require("strapi-utils");
    
        /**
         * Read the documentation (https://docs.strapi.io/developer-docs/latest/development/backend-customization.html#core-controllers)
         * to customize this controller
         */
    
        module.exports = {
          async create(ctx) {
            let entity;
    
            if (ctx.is("multipart")) {
              const { data, files } = parseMultipartData(ctx);
              data.author = ctx.state.user.id;
              entity = await strapi.services.post.create(data, { files });
            } else {
              ctx.request.body.author = ctx.state.user.id;
              entity = await strapi.services.post.create(ctx.request.body);
            }
    
            return sanitizeEntity(entity, { model: strapi.models.post });
          },
    
          async update(ctx) {
            const { id } = ctx.params;
    
            let entity;
    
            const [article] = await strapi.services.post.find({
              id: ctx.params.id,
              "author.id": ctx.state.user.id,
            });
    
            if (!article) {
              return ctx.unauthorized(`You can't update this entry`);
            }
    
            if (ctx.is("multipart")) {
              const { data, files } = parseMultipartData(ctx);
              entity = await strapi.services.post.update({ id }, data, {
                files,
              });
            } else {
              entity = await strapi.services.post.update({ id }, ctx.request.body);
            }
    
            return sanitizeEntity(entity, { model: strapi.models.post });
          },
    
          async delete(ctx) {
            const { id } = ctx.params;
    
            let entity;
    
            const [article] = await strapi.services.post.find({
              id: ctx.params.id,
              "author.id": ctx.state.user.id,
            });
    
            if (!article) {
              return ctx.unauthorized(`You can't delete this entry`);
            }
    
            await strapi.services.post.delete({ id });
    
            return { ok: true };
          },
        };
    

    `

    And now, the author should be able to delete posts.

    Conclusion & Resources

    And there you have it! Your blog website is made with SvelteKit and Strapi. If you got stuck anywhere, be sure to check the SvelteKit Docs, the Strapi Docs, and the source code on Github.

Tailwind CSS

Posts with mentions or reviews of Tailwind CSS. We have used some of these posts to build our list of alternatives and similar projects. The last one was on 2024-05-08.