DEV Community

Joel Jaison
Joel Jaison

Posted on

TODO-APP using SVELTE

project preview

Step 1: Set Up Your Environment

Before you start coding, you need to set up your development environment. First, make sure you have Node.js installed on your machine. You can download Node.js from the official website: https://nodejs.org/en/download/.

Once Node.js is installed, you can use the Node Package Manager (npm) to install the Svelte CLI. Open a command prompt or terminal and run the following command:

npm install -g svelte-cli
This command installs the Svelte CLI globally on your machine, which allows you to create new Svelte projects and run development servers.


Step 2: Create a New Svelte Project

Once the Svelte CLI is installed, you can use it to create a new Svelte project. Navigate to the directory where you want to create your project and run the following command:

svelte create my-todo-list
Replace "my-todo-list" with the name of your project. This command creates a new Svelte project with the default template.


Step 3: Create the Layout Component

In Svelte, components are the building blocks of your application. You can think of a component as a reusable piece of code that encapsulates its own logic and user interface.

The first component we need to create is the layout component. This component will define the overall structure of our application, such as the header, footer, and navigation.

Create a new file called Layout.svelte in the src/components directory and add the following code:

<script>
    import './styles.css';
</script>

<div class="app">
    <main>
        <slot />
    </main>
</div>
Enter fullscreen mode Exit fullscreen mode

Step 4: Update the style.css and include assets

update the style.css with this code

body {
    margin: 0;
    padding:0;
    background: url(../lib/images/pexels-andrew-neel-2312369.jpg);
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center;
    min-height: 100vh;
}

*{
    margin: 0;
    padding:0;
    box-sizing: border-box;
}

.app{
    background: rgba(21, 21, 21, 0.47);
    z-index: 999;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}
Enter fullscreen mode Exit fullscreen mode

include assests in a image folder inside the lib folder.

Step 5: Create a +page.svelte inside routes

inside the the file include this code

<script>
    import Icon from '$lib/images/add.png';
    let todos = [];
    let tag = 'work';
    const tagsToEmoji = {
        work: '๐Ÿ’ผ',
        study: '๐Ÿ“š',
        read:'๐Ÿ“–',
        write:'โœ๐Ÿผ',
        draw: '๐ŸŽจ',
        exercise:'๐Ÿƒ',
        hobby: '๐ŸŽฎ',
        swimming: '๐ŸŠ'
    };
    let task = '';
    let filter = 'all';
    function addTask() {
        todos = [
            {
                task: task,
                status: 'pending',
                tag: tag
            },
            ...todos
        ];
        task = '';
    }
    function markComplete(i) {
        todos[i].status = 'completed';
        todos = [...todos];
    }
    function removeTask(i) {
        todos.splice(i, 1);
        todos = [...todos];
    }
</script>

<svelte:head>
    <title>Home</title>
    <meta name="description" content="Svelte demo app" />
</svelte:head>

<div class="container">
    <div class="todo">
        <div class="form">
            <input
                type="text"
                bind:value={task}
                on:keydown={(e) => {
                    if (e.key === 'Enter') {
                        addTask();
                    }
                }}
            />

            <button on:click={addTask}>
                <img src={Icon} alt="" srcset="" />
            </button>
            <select bind:value={tag}>
                <option value="work">Work</option>
                <option value="study">Study</option>
                <option value="draw">Drawing</option>
                <option value="read">Reading</option>
                <option value="hobby">Hobby</option>
                <option value="swimming">Swimming</option>
                <option value="exercise">Exercise</option>
                <option value="write">Writing</option>
            </select>
        </div>
        <div class="filters">
            <button
                class={filter == 'all' ? 'active' : ''}
                on:click={() => {
                    filter = 'all';
                }}
            >
                All
            </button>
            <button
                class={filter == 'completed' ? 'active' : ''}
                on:click={() => {
                    filter = 'completed';
                }}
            >
                Completed
            </button>
            <button
                class={filter == 'incomplete' ? 'active' : ''}
                on:click={() => {
                    filter = 'incomplete';
                }}
            >
                Incomplete
            </button>
        </div>
        <div class={todos.length > 0 ? 'tasks' : ''}>
            {#each todos as todo, i}
                {#if filter == 'all'}
                    <div class="task">
                        <div class={todo.status == 'completed' ? 'active-ul' : ''}>
                            {todo.task}
                        </div>
                        <span>{tagsToEmoji[todo.tag]}</span>                        
                        <button
                            class={todo.status == 'completed' ? 'active' : ''}
                            on:click={() => {
                                markComplete(i);
                            }}
                        >
                            &#10004;
                        </button>
                        <button
                            on:click={() => {
                                removeTask(i);
                            }}
                        >
                            &#10006;
                        </button>
                    </div>
                {:else if filter == 'completed'}
                    {#if todo.status == 'completed'}
                        <div class="task">
                            <div>
                                {todo.task}
                            </div>
                            <button
                                on:click={() => {
                                    removeTask(i);
                                }}
                            >
                                &#10006;
                            </button>
                        </div>
                    {/if}
                {:else if todo.status == 'pending'}
                    <div class="task">
                        <div>
                            {todo.task}
                        </div>
                        <button
                            class={todo.status == 'completed' ? 'active' : ''}
                            on:click={() => {
                                markComplete(i);
                            }}
                        >
                            &#10004;
                        </button>
                    </div>
                {/if}
            {/each}
        </div>
    </div>
</div>

<style>
    .todo {
        padding: 20px;
        opacity: 0.8;
        width: 70vw;
        height: auto;
        border-radius: 20px;
        background: white;
    }

    .todo > div {
        margin: 20px 0px;
    }

    .todo .form {
        display: flex;
        align-items: center;
        justify-content: space-around;
        height: fit-content;
        border: 1px solid grey ;
        border-radius: 15px;
        padding: 5px;
    }

    img {
        height: 20px;
        object-fit: cover;
    }

    input,
    button {
        background: transparent;
        border: none;
    }

    input {
        border-top-left-radius: 8px;
        border-right: none;
        height: 35px;
        width: calc(70vw);
        padding: 2px;
        font-size: 22px;
    }

    input:focus {
        outline: none;
    }
    .form button {
        border-left: none;
        height: 35px;
        border-top-right-radius: 8px;
        padding: 2px;
        cursor: pointer;
    }

    .tasks {
        border: 1px solid grey;
        border-top-right-radius: 20px;

        border-top-left-radius: 20px;
        padding: 20px 5px;
    }

    .task {
        border-top: 1px solid grey;
        word-wrap: break-word;
        font-size: 20px;
        display: flex;
        align-items: center;
        padding: 10px;
    }
    .task span {
        margin-left: 5px;
        margin-right: 8px;
    }

    .todo .tasks > .task > button {
        width: 25px;
        height: 25px;
        border: 1px solid #000000;
        color: #000000;
        border-radius: 50%;
        margin: 0px 5px;
        cursor: pointer;

    }
    .todo .tasks > .task > button.active {
        background: #020202;
        color: #f5f5f5;
    }
    .todo .filters {
        display: flex;
        justify-content: space-between;
    }
    .todo .filters > button {
        min-width: 150px;
        padding: 10px 8px;
        border-bottom: 1px solid #000000ce;
        cursor: pointer;
        font-size: 20px;
    }
    .todo .filters > button.active {
        background: #000000;
        color: #f5f5f5;
    }
    select{
        padding: 10px;
        margin: 3px;
        font-size: 20px;
    }
    .active-ul{
        text-decoration: line-through;
    }
</style>

Enter fullscreen mode Exit fullscreen mode

You can update the style as you wish , If you feel discomfort with the way of structure of the code , Try to read the sevlte documentation to know about how to include style script and html combined in a single file .

explanation for the script section :-

Let's break down the different parts:

  • import Icon from '$lib/images/add.png';: This line imports an image from the src/lib/images directory. This image will be used as an icon for the "Add" button in the component's UI.

  • let todos = [];: This creates an empty array called todos. This array will store the to-do items that the user adds.

  • let tag = 'work';: This sets the initial value of the tag variable to 'work'. This variable is used to store the selected tag for a new to-do item.

  • const tagsToEmoji = {...};: This creates an object called tagsToEmoji that maps each tag name to an emoji that represents that tag.

  • let task = '';: This initializes the task variable to an empty string. This variable will store the text of a new to-do item that the user enters.

  • let filter = 'all';: This initializes the filter variable to 'all'. This variable is used to filter the displayed to-do items based on their status (completed or pending).

  • function addTask() {...}: This function is called when the user clicks the "Add" button to create a new to-do item. It creates a new object with the text of the task, the selected tag, and a status of "pending", and adds it to the beginning of the todos array. It then clears the task variable so the user can enter a new task.

  • function markComplete(i) {...}: This function is called when the user clicks the "Complete" button on a to-do item. It changes the status property of the specified to-do item to "completed", and updates the todos array with the new status.

  • function removeTask(i) {...}: This function is called when the user clicks the "Remove" button on a to-do item. It removes the specified to-do item from the todos array, and updates the array to reflect the change.

Step 6: Save and run development server

npm run dev

get the code on https://github.com/JoelJaison394/Todo_App-sevlte.git

Top comments (0)