פרוייקט ראשון ב־Svelte עם Vite

כשאני יוצר פרוייקטים תכנותיים חדשים, לפעמים אני צריך ללמוד ולהכיר איך עושים את זה לראשונה ובפעם השניה צריך להיזכר. הפוסט הזה נועד כדי לעזור לי להיזכר במה שעבד לי, כדי שלא אצטרך להתעכב ביצירת התשתית על מנת שאוכל להתרכז ביצירה עצמה.

היום אני הולך לשלוף פרוייקט משותף שלי ושל חבר שהמון זמן נמצא בבוידם הרעיונות והספיק להעלות אבק, למרות שהוא רעיון שאני סופר מתרגש ממנו וברגע שאנקה את האבק אזכר כמה הוא נוצץ. זה אני, אבל אני מניח שתמצאו אותו מאוד אמביוולנטי. אסביר מיד למה.

זה הולך להיות תוסף לכרום שבעצם הולך להזכיר לך בכל רגע שאתה פותח טאב חדש, בן כמה אתה, בצורה ויזואלית, כדי להמחיש לך שהחיים מתקצרים בכל יום. המטרה היא כמובן חיובית ואמורה להניע לפעולה, להלחיץ, אבל למען החיוביות שבכך, לחיות ולנצל את המיטב שבחיים ולא להיפך.

אני מניח שכל אחד יגיב אחרת לפרוייקט מהסוג הזה וזה בסדר גמור, טבעי למדי. הנושא של מוות הוא לא נושא שכיף להתעסק בו, אבל בואו, הוא גם בלתי נמנע.

אמרתי שהוא נושא שלא כיף להתעסק בו.

האמנם? אגלה בהמשך, כאשר הפרוייקט יהיה פתוח לציבור…


אתחיל ביצירת הפרויקט החדש. בשביל זה אני רוצה להשתמש ב־Svelte. למדתי לאחרונה אותו ומאוד אהבתי, אבל לא יצא לי לנסות לבנות פרויקט שלם איתו. זה בעצם חלופה מינימליסטית (וראוי לציין שגם גאונית) ל־Vue או React. אני מוצא אותה מאוד טבעית ונוחה לשימוש, למרות שיצא לי לבנות בה דברים רק ב־"ארגז המשחקים".

אחי הכיר לי Compiler מאוד נחמד שנקרא Vite שניסיתי אותו מעט והוא עושה עבודת תכנות סופר חלקה עבור המפתח. לשמחתי הוא עובד עם Svelte, אז אריץ את הפרויקט איתו.

אריץ את הפקודה ליצירת פרוייקט Vite חדש:

npm init vite@latest

ארצה לאתגר את עצמי, אז אשתמש ב־TypeScript.

עכשיו כדי להתקין, צריך להריץ:

npm i

דבר נוסף הוא שאני אוהב להשתמש ב־SCSS, אז אתקין אותו גם בעזרת הפקודה הבאה:

npm install svelte-preprocess sass --save-dev

ועכשיו אפשר להשתמש ב־SCSS בתוך קבצי Svelte. נחמד! הנה דוגמה:

<style lang="scss">
  $purple: purple;

  h1 {
    color: $purple;
  }
</style>

אבל תכלס עדיף להשתמש ב־Global CSS Variable כדי שיהיה לי קל להשתמש ב־Variables בכל ה־Components הפנימיים שאבנה.

<style lang="scss">
  :root {
    color: var(--purple);
    --purple: #482f5e;
    --pink: #ffa8d1;
    --blue: #97d5e6;
    --black: #241f29;
    --border: #d7cad0;
  }
</style>

טוב, מאז הפעם האחרונה שכתבתי את הפוסט, המשכתי לבנות את התוסף כי זה פשוט זרם חלק כמו חמאה, עבדתי בערך 5 שעות ברוטו שכללו בתוכן גם כמה הפסקות בין לבין ששיחקתי במחשב. למעשה, הגעתי לתוצאה ממש יותר מהר ממה שציפיתי.

הייתכן ומצאתי את ה־Framework המועדף עליי, אפילו יותר מ־React? הלם.

רק הזמן ידע.

ולהלן התוצאה:

(והדף הזה, שכולל את התוכן, העיצוב, האנימציות וההתנהגות, סה"כ 253 שורות קוד. מה?! זה כלום!)

אשתף אתכם, כדי שתאמינו לי.

<script lang="ts">
  import { store } from "./stores/BirthdayStore";
  const { day, month, year, now, birthdate, age, week } = store;
  import Logo from "./Components/Logo.svelte";

  const decades = 12;
  const WEEKS_PER_YEAR = 52;

  import { settingsStore } from "./stores/SettingsStore";
  const { currentPage } = settingsStore;
</script>

<div class="container">
  <div class="inside">
    <header>
      <h1>YOUR LIVING YEARS IN WEEKS</h1>
      <a href="#datepicker" on:click={() => ($currentPage = "datepicker")}
        ><Logo /></a
      >
    </header>

    <div class="lifespan">
      {#each [...Array(decades).keys()] as decade}
        <div class="decade">
          <h3>{decade === 0 ? "0-9" : `'${decade}0s`}</h3>
          <div class="years">
            {#each [...Array(10).keys()] as year}
              <div class="year">
                <span
                  class="age"
                  class:passed={year + decade * 10 < $age}
                  class:current={year + decade * 10 === $age}
                >
                  <!-- {decade === 0 ? "0" : ""} -->
                  {year + decade * 10}</span
                >
                <div class="weeks">
                  {#each [...Array(WEEKS_PER_YEAR).keys()] as _week}
                    <div
                      class="week"
                      class:first={decade === 0 && year === 0}
                      class:week-passed={_week < $week}
                      class:current-week={_week === $week}
                      class:passed={year + decade * 10 < $age ||
                        (_week < $week && year + decade * 10 === $age)}
                      class:next={_week === $week &&
                        year + decade * 10 === $age}
                      data-week={_week + 1}
                    >
                      <div class="popper">
                        <div class="inside">
                          Week {_week + 1}/{WEEKS_PER_YEAR} of your {year +
                            decade * 10}'s year
                        </div>
                      </div>
                    </div>
                    {#if _week % 4 === 3}<div class="break" />{/if}
                  {/each}
                </div>
              </div>
            {/each}
          </div>
        </div>
      {/each}
    </div>
  </div>
</div>

<style lang="scss">
  .container {
    text-align: center;
    padding: 1em;
    .inside {
      display: inline-flex;
      flex-flow: column;
      align-items: center;
    }
  }
  header {
    display: inline-flex;
    justify-content: space-between;
    margin-bottom: 1.5em;
    align-items: flex-end;
    width: 100%;
    h1 {
      color: var(--pink);
      text-align: center;
      font-size: 2.5em;
      line-height: 1;
      margin: 0;
    }
  }
  @keyframes blinkColor {
    from {
      color: var(--pink);
    }
    to {
      color: var(--purple);
    }
  }
  .lifespan {
    display: inline-flex;
    /* border-radius: 1em;
    border: 2px solid var(--pink);
    padding: 1em 2em; */
    .decade {
      /* width: 100%; */
      &:not(:last-child) {
        margin-inline-end: 0.6em;
      }
      h3 {
        text-align: center;
        margin: 0;
        white-space: nowrap;
        margin-bottom: 1em;
      }
      .years {
        display: flex;
        justify-content: center;
        /* justify-content: space-between; */
        .year {
          position: relative;
          span.age {
            width: 2em;
            left: -0.45em;
            text-align: center;
            font-size: 0.36em;
            position: absolute;
            top: -1.5em;
            font-weight: 700;
            color: var(--pink);
            &.passed {
              color: var(--purple);
            }
            &.current {
              animation: blinkColor 500ms ease-in-out infinite alternate;
            }
          }
          /* &:hover {
            span.age {
              color: var(--border);
            }
          } */
          .weeks {
            .week {
              position: relative;
              .popper {
                display: none;
                position: absolute;
                left: 50%;
                bottom: 50%;
                transform: translateX(-50%) translateY(-50%);
                padding: 0.2em 0.6em;
                border-radius: 1em;
                pointer-events: none;
                background: white;
                color: var(--purple);
                border: 2px var(--purple) solid;
                white-space: nowrap;
                font-size: 0.5em;
                z-index: 1;
              }
              &:hover {
                .popper {
                  display: block;
                }
              }
              &.first {
                &:before {
                  line-height: 0.95;
                  width: 2em;
                  left: -2.5em;
                  font-size: 0.5em;
                  color: var(--pink);
                  font-weight: bold;
                  text-align: end;
                  position: absolute;
                  content: attr(data-week);
                }
                &.week-passed {
                  &:before {
                    color: var(--purple);
                  }
                }
                &.current-week {
                  &:before {
                    animation: blinkColor 500ms ease-in-out infinite alternate;
                  }
                }
              }
              &.passed {
                background: var(--purple);
              }
              &.next {
                /* background: var(--blue); */
                animation: blink 500ms ease-in-out infinite alternate;
                @keyframes blink {
                  from {
                    background: var(--pink);
                  }
                  to {
                    background: var(--purple);
                  }
                }
                position: relative;
                &:before {
                  content: "";
                  position: absolute;
                  top: 0;
                  left: 0;
                  right: 0;
                  bottom: 0;
                  width: 100%;
                  height: 100%;
                  /* background: red; */
                  border-radius: 100%;
                  outline: 1em var(--pink) solid;
                  z-index: 1;
                  animation: glow 2000ms ease-in-out infinite -0.5s;
                  opacity: 0;
                  @keyframes glow {
                    from {
                      outline-width: 0em;
                      opacity: 1;
                    }
                    to {
                      outline-width: 2em;
                      opacity: 0;
                    }
                  }
                }
              }
              border-radius: 1em;
              /* min-width: 100%; */
              width: 0.45em;
              margin: 0.15em 0.15em 0 0;
              background: var(--pink);
              &:after {
                display: block;
                content: "";
                padding-bottom: 100%;
              }
            }
            .break {
              height: 0.3em;
            }
          }
        }
      }
    }
  }
</style>

הערה קטנה לעצמי: אני חושב שאנסה בפעמים הבאות את Svelte-kit אשר יודע גם להתמודד עם Routing. במקרה של התוסף, לא הייתי צריך Routing אז Svelte הספיק כשלעצמו.


השלב הבא הוא להגיש את הפרוייקט הזה לחנות התוספים של כרום.

או להוסיף עוד כמה פיצ'רים לפני כן.

עוד לא החלטתי!

דברים שאני כותב

6 מחשבות על “פרוייקט ראשון ב־Svelte עם Vite

  1. מוזר לי שאדם שכותב קוד, ונראה ששולט בכמה שפות ופלטפורמות, יש לו בחיים עוד דברים מעניינים חוץ מלכתוב קוד

    מקווה שהסברתי את עצמי, לא בטוח.

    אה, ונהניתי מהיצירות שלך.

      1. איך בכלל יש לך זמן?
        אני גם כן מתכנת והייתי מת לעשות עוד דברים אבל אין לי זמן!!!
        אתה שכיר של מישהו?

        1. עצמאי, מהסיבה הפשוטה שאני מעדיף לנהל לעצמי את הזמן

          אני מאמין שאם יש רצון יש דרך

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

פוסט בהפתעה?