Git Product home page Git Product logo

sifetti's Introduction

Sifetti

Sifetti is a simple note-taking app with one core philosophy: organization is simpler when you don't use folders!

Instead, you tag notes, allowing you to accomplish a wide variety of views by filtering for certain tags. If you had ever found yourself wishing you could put the same document into two different folders, Sifetti basically allows you to do just that.

Example

For example, let's say you are writing a fictional novel, and so far you have notes on four concepts:

  • Frodo Baggins, a hobbit with an epic destiny
  • The Shire, peaceful homeland of the hobbits
  • Sauron, an evil warlord
  • Mordor, a volcanic wasteland from which Sauron rules

Two of these are characters, and two of these are locations. Naturally, then, it feels like Frodo and Sauron should go in the characters folder, and The Shire and Mordor should go in the locations folder.

But if you want to look at all your files related to The Shire, which might include Frodo since that's where he lives, what do you do?

Sifetti's philosophy is to use tags instead.

  • Frodo Baggins - character, the shire
  • The Shire - location, the shire
  • Sauron - character, mordor
  • Mordor - location, mordor

Sifetti allows you to filter by tags, so you can look at all your characters at once, all your locaations at once, or all notes related to Mordor at once. You can even make more specific queries, such as all characters related to Mordor (which in this case is just Sauron).

The Value

Folder-based organization is perhaps the most prevelant way digital documents are organized. And yet, there are many domains for which that really isn't the natural way to organize things.

  • If you have a library of photos, do you create folders based on location, time period, or who's in the image?
  • When coding, there's been a long-standing debate about whether folders are organized by feature or by architectural layer. What if you could do both at the same time?
  • Maybe you are learning several different things. Tags can help visualize some of the connections between topics that otherwise felt entirely distinct.

Now of course, tagging is not a new concept. Many technologies use tags or labels already (such as Trello, Github, but Google Drive), but they are usually tied to a more specific domain as well (what if I don't need Trello's columns, for instance?).

Sifetti offers tagging as the first-order method of organizing notes and designed to be general enough to fit a variety of needs.

Codebase

Sifetti is built on SvelteKit. For authentication and data storage, it uses Supabase.

Design System

Sifetti uses a component-based design system; that is, the interface is made consistent by the use of standardized design Svelte components with a limited surface area of strongly-typed props.

For example, the Button component allows the developer to define color, size, and spacing as props of the component as opposed to raw CSS. As these props are strongly typed with Typescript, buttons throughout the site can be made consistent.

Design components are in /src/lib/design.

Strengths of this approach:

  • The options for a component are discoverable and well document in code
  • Changing the design component propogates to its usage throughout the site
  • Behaviour and aesthetics are packaged together, easing the use of the design system

Weaknesses of this approach:

  • It is sometimes unclear whether a design component is appropriate or a custom div using the CSS variables should be used
  • Tends to create a deep hierarchy of non-semantic divs as design components are nested
  • Behavioural and aesthetics are packaged together, meaning less modularity

API

Routes behind /api compose a Backend for Frontend (BFF) REST API. Although Supabase can be used directly in client code, it was deliberately chosen for Supabase (and any other services) to be accessed behind the BFF layer for a few reasons:

  • Create the protential for rendering more server-side
  • Create the opportunity for a true API that could be used in custom software
  • Have more fine-grained control around the security of authorization
    • Supabase uses LocalStorage for storing tokens, which is not always as secure as using pure HTTP cookies, for example

Where is GraphQL?

GraphQL is not needed on every project. At the moment the scale of Sifetti is small enough to not warrant the need for introducing such a significant chunk of architecture when vanilla HTTP and REST can be used.

Providers

Providers are an abstraction around the things Supabase is used for (auth and storage), providing an action-focused interface agnostic of the underlying technology. Besides providing a way to swap or consolidate vendors, providers also facilitate covalent testing and pave a potential future for running Sifetti purely locally on a filesystem.

Covalent Testing

Covalent Testing is a strategy for testing with dependencies that minimizes the downsides of using pure stubs without sacrificing some of the benefits. More specifically:

  • Stubs are often used in testing to simulate dependencies without needing to connect to said dependencies directly.
    • This speeds up tests substantially, as connecting to true databases or services generally incurs some latency.
    • This makes tests more reliable, as the success of the tests no longer depend on the success of a service that is out of control of the developer (aka, it makes the test more unit-like)
    • They allow developers to simulate failure conditions without actually inducing said conditions on the true dependencies
  • Stubs do have a few tradeoffs, though.
    • It is possible to stub a service in such a way that the stub no longer accurately reflects the reality of how that service behaves.
    • A change to the interface of the stubbed service often propogates to all of the stubs.
    • While these tradeoffs can be partially mitigated by testing the stubs themselves, that's not a common practice.

See: Mocks aren't Stubs

The core principle behind covalent testing is to create a fast, in-memory test double of the underlying service which behaves as much as needed like the dependency without actually being the dependency. Rather than use the dependency in tests, the test double is used instead; assuming the double and the real dependency behave exactly the same, then using the double in tests is literally as good as using the real dependency, except better because the double is faster and offers more control to the developer.

So the key question is this: how do you ensure the double and real deal actually behave the same? The answer is to write a single suite of tests that runs against both versions. Since the suite of tests is the same for both, and tests ensure the behaviour is as intended, then this allows the double and real dependency to be substitutionally equivalent. That the tests is shared represents the covalency of the strategy.

For an example of this in action, see /test/lib/notes/provider.

Development

A .env file is required for anything requiring integration with Supabase (mainly integrated tests).

  • npm install - install dependencies
  • npm run dev - run the app locally
  • IN_MEMORY_LATENCY=400 npm run dev - simulate network latency
  • npm run test:all - run all tests
  • npm t some/filepath - run the tests under a specific filepath

Vision

Architecture and design decisions are driven primarily by the vision for the product. Eventually, I could imagine Sifetti becoming more than just the personal notetaking app that it is:

  • Perhaps a team can collaborate live with the same set of notes on the cloud
  • Perhaps a board could actually be used as a wiki of sorts for a piece of culture
  • Perhaps Sifetti could serve as an abstraction over a folder in a filesystem on someone's computer

sifetti's People

Contributors

auroratide avatar

Watchers

James Cloos avatar  avatar

sifetti's Issues

I want to keep editing if I flip between different tabs

It is very annoying to switch back to a Sifetti tab only to find the editing is over and you have to double click again to edit, presumably losing your spot.

Tech notes

Right now, the editing session ends on blur, but for now it should be based on the save button, or if the page is left.

Disabled New Tag button informs what is wrong

When the New Tag button is disabled, it means that tag cannot be created. It should indicate somewhere why this is the case.

Ideas:

  • As a title, so if the button is hovered it reveals what's up
  • As a label under the filter in red

Public Demo

There should be a public demo available without needing to log in to demonstrate what Sifetti does and how it works.

The demo should basically include as much functionality as possible:

  • Creating/applying tags
  • Editing notes
  • Filtering

But none of the data is persistent.

Dark Mode

Dark mode is very popular and should always at minimum be provided as a toggleable preference.

Basic Markdown Keyboard Shortcuts

Some formatting keyboard shortcuts are fairly standard. Such shortcuts are incredibly useful for quickly applying formatting to text that is already written, or to text you are about to write.

Shortcuts to include:

  • Bold: Cmd/Ctrl + B
  • Italic: Cmd/Ctrl + I
  • Underline: Cmd/Ctrl + U
  • Link: Cmd/Ctrl + K

How to use this:

  • When something is highlighted and the shortcut is issued, the markdown is applied to the highlighted section.
  • When nothing is highlighted and the shortcut is issued, the markdown is placed where the cursor is, with the cursor in the location of where the text should go
  • When within a formatting string of the same type as the shortcut being issued, the cursor is brought to the outside of the region

NVDA gets stuck on profile page navigating to notes

When I navigate using NVDA on the profile page to a note page, it inexplicably gets stuck on the profile page while the rest of the page visibly loads (reads "My Profile" over and over again). It's like it doesn't understand that we're on a new page now.

The broader behaviour should be that when we navigate with a screen reader from one page to another that the cursor lands at the very top, and ideally there would be a Skip Navigation link up there.

Negative Tag Filter

It may be useful to see all pages NOT tagged with a certain label.

Interaction idea: click once to apply the tag (checkmark), then again to negate it (x or minus), and then a third time to neutralize it.

Autocomplete Links

Notes have very wonky URLs that cannot be guessed nor memorized. This makes it rather difficult to link to my other notes from within a note if all I know is the title.

It should be possible to autocomplete the link syntax if I know the title of the note.

Idea 1: Normal Link Syntax

When I type:

[some name](TITLE)

Then a dropdown of some sort appears listing the possible options. If one is selected, then the proper URL is filled in.

Idea 2: Custom Syntax

There's the possibility of custom syntax, like {@link title}. However, this might be prone to problems if the linked note is renamed.

Idea 3: Shorthand link syntax

When I type:

/notes

Then a dropdown of some sort appears listing the possible options. The end result is simply:

His brother is /notes/some-id-here.

But the parser converts this into: "His brother is Jacob Schmidt".

Cancelling Note Creation

After creating a new note, I might change my mind and decide I don't really need a new note yet. However, once the Create button is pressed, a new note is created and saved to the database regardless of whether content gets saved to it. This results in a lingering Untitled note.

If I do not write any content/title into the newly created note, then it shouldn't be created. I could cancel:

  • Leaving the page
  • Pressing the browser's Back button (or using keyboard navigation)
  • Pressing a Cancel button in the action area (?)

Table of Contents

It would be nice if a note either had a table of contents in the sidebar, or if it were an optional tag to place, like <table-of-contents></table-of-contents>.

Attachments

I should be able to attach files, such as pictures, to a note and then be able to reference said attachment in the note itself. Incredibly useful for people who maybe want to post concept art of a character they are documenting.

One thing to keep in mind are limits:

  • The size of a single file
  • The total capacity for any single person/space

No double-spaces in tags

Tags should have at minimum the following restrictions:

  • Cannot start or end with a space
  • Cannot contain two or more consecutive spaces
  • Cannot contain tabs, new lines, or carriage returns

Case-Sensitive Tags were surprising - Filtering should be insensitive

At the moment, tags are case-sensitive, so "Character" and "character" are considered distinct. This was surprising, though upon consideration it was felt case-sensitivity might be more enabling. For example, "Curiosity" and "curiosity" could be distinct tags, one for the Mars rover and one for the concept.

One idea to mitigate confusion and reduce mistakes is to let filtering be case insensitive. So, if a person has "Curiosity" and "curiosity" as distinct tags, then filtering for "curiosity" would show both options.

Refresh Token Automatically

At the moment, when the token expires, it expires and the person has to log in again.

For as long as the person is active, the login should persist. Two strategies for this:

  • On a regular interval, ping the server for a new token using the refresh token.
  • When an action is performed or a page is visited, refresh the token.

Sorting Notes

One of the big goals of Sifetti is to make it trivially easy to find what you're looking for, and part of that is having a predictable way of sorting notes.

Possible sorting schemes include (along with their inverses):

  • Alphabetical
  • Recently Edited

It is not clear how to remove a tag

Currently, a tag is removed by first clicking the "+" button and then using the Add/Remove dialog. It is not clear that the "+" button logically leads to the ability to remove tags.

It's been suggested to make the tags clickable immediately, presenting a list of options such as "remove".

Markdown Syntax Hints

For those unfamiliar with markdown, this will be incredibly useful. It should be very accessible (visible everywhere? a labelled aside?)

  • Headers
  • Textual format (bold, italic, strikethrough, underline)
  • Links
  • Lists
  • Quotes
  • Code

Spaces for high-level note grouping

A space is a collection of notes that are so categorically distinct from other collections of notes such that they should not occupy the same list, nor share the same tags. That is, I may maintain notes for two different worldbuilding projects, and even though I can theoretically maintain separation with a single tag, it would be much better of the respective notes were in their own spaces because notes from one will never relate to notes from the other.

Arguably, this is a "folder", but it is a proper use of one.

Spaces serve two big purposes:

  • Allow someone to have multiple exclusive sets of notes
  • Allow multiple people to share the same space (that is, decouple notes from owners)

Page performace is slow on note pages

While working on a note page, I noticed scrolling was jittery and not smooth. These are the most important pages on the site, so performance must be as good as possible.

Investigation

A super quick investigation led me to three suspects:

  • SvelteKit's prefetch mousemove event, which always exists and constantly triggers even when not used
  • The Drop Shadow filter, which is used to emulate elevation of fettiboxes
  • The Clip Path property, which creates the fettibox shape.

I believe the Drop Shadow has the most significant impact of the three, as removing it from the page makes the page feel noticeably more responsive, whereas the same was not true for clip path. I haven't attempted dislodging prefetch.

Possible Solution

Drop the note page fettibox to the Ground elevation to get rid of the giant drop shadow. Additionally, I think "ground" currently does have a drop shadow but it's all 0; it should probably just be none or empty.

Non-guid URI

The guid in the URI is kind of non-aesthetic. It would be nice if instead it were an alphanumeric string, and ideally shorter.

Math Syntax in the Markdown Editor

I just ran into a document I was copying and pasting that had some math stuff in it. It would be nice if math could be introduced into the markdown syntax.

At minimum, this can be achieved with a web component since vanilla HTML is allowed in markdown syntax (double check what DOM Purify does with this though).

Use a Permanent Cookie

At the moment a session cookie is used. But this cookie dies when refreshing in incognito mode. Also the cookie dies if the browser is closed, etc.

Supabase provides an expiry, so use that.

Tag Colors

Right now all tags are the same color. It would be nice if I could specify colors for them, so that I can visually categorize tags and see at a glance what kinds of things notes may be.

How?
One possible mechanism would be to allow right-clicking on a tag in order to edit it's various aspects.

Accessibility Concern
Addressing colorblindness is necessary. Ideally this would be a personal setting.

Line breaks not showing from markdown

When I have markdown code like this:

This is a line.
And so is this one.

The intent is clearly that these are two different lines, but not separated by a paragraph's worth of margin. I would expect HTML like this:

<p>This is a line.<br />And so is this one.</p>

But instead the <br /> is not rendered.

Long Tag Names do not break

If a tag has a very long unbreakable name, it can cause elements of the UI to leak offscreen. This is especially evident on mobile and a tag name like "veryverylongtagnamethatdoesnotbreak".

The UI should handle this responsibly, possibly by breaking that long tag name.

Context-Awareness for Initial Cursor Position

At the moment, there are two ways to begin editing a document: by pressing the Edit button, or by double tapping the content area. For both of these actions, there is a sense of "the cursor should go here" when the editor appears. At the moment, the cursor just appears in an undefined location, which is especially frustrating because it means needing to scroll through code to find what you want to edit.

  • When clicking Edit, the cursor should appear near where the edit button is. For instance, if the edit button is at the end (at the moment, it is), then the cursor should be placed at the end. If there were an edit button near the beginning at the top of the screen, then the cursor would be placed there.
  • When double tapping, presumably the person is double-tapping something in particular. Wherever that location is, the cursor should appear there, and the screen should focus on that area.

Relationship Tags

A relationship tag is a special type of tag that relates two cards together. For example, a character Greg can be an employee to a workplace E-Cargo. A relationship tag "employee" would be assigned to Greg with E-Cargo defined as the relating note.

This allows possible views like "Employees of E-Cargo", or "All Employees in general", or "All things related to Greg".

This feature is what would truly distinguish Sifetti from competing ideas.


Without relationship tags, this can be accomplished with clever use of ordinary tags. For instance, "employee" and "e-cargo" could be tags on Greg. Relationship tags prevent the need to create tags in place of notes, in essence reducing the duplication of data. Furthermore, relationships are a very useful way of thinking about different concepts.


Much needs to be thought through in terms of how one would specify, define, and use relationship tags, especially in the presence of ordinary tags.

Invalid URL error in production

For a brief period of about 5 minutes, trying to access Sifetti led to this error:

{"errorType":"TypeError","errorMessage":"Invalid URL: /","trace":[
"TypeError [ERR_INVALID_URL]: Invalid URL: /",
"    at new NodeError (internal/errors.js:322:7)",
"    at onParseError (internal/url.js:270:9)",
"    at new URL (internal/url.js:346:5)",
"    at new Request (/var/task/.netlify/shims.js:5918:16)",
"    at to_request (/var/task/.netlify/handler.js:67:9)",
"    at Runtime.handler (/var/task/.netlify/handler.js:23:37)",
"    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)"
]}

Filter by Title

If I know the title of the note, I should be able to search for that title directly.

  • Case insensitive
  • Title need not be exact (ie. if I remember the middle of the title, that should be sufficient)

Account Names

Generally, people prefer to be known by their name than their email. During signup, people should be able to specify a unique name; additionally, such a name should be modifiable from a profile page.

Uniqueness

The name should be unique for two reasons:

  • The name can be used instead of email to sign in
  • A person's public profile page may eventually be accessible via a route like /people/profile-name.

Case Sensitivity

The account name should be case sensitive, and yet for the sake of uniqueness case _in_sensitive. That is, if someone wants to go by "PowerRanger", then what should be displayed as their name is "PowerRanger". However, if someone else tries to sign up as "powerranger", the name will already be taken.

The purpose of this is to alleviate confusion between similar usernames, and to make sign in easier (the person need not remember the exact casing of their name).

Restrictions

  • At least one character
  • The first character is alphanumeric
  • Only -, _, and Space are allowed as special characters
  • The maximum length is 64 characters
  • Spaces should not appear consecutively
  • The last character is not a space

The "Add Tag" button when there are no tags is confusing

On a new note, the "Add Tag" button is just an isolated + button. This has been confusing for people, as it is not clear what this button is plussing.

Ideas:

  • Explicitly say "Edit Tags"
  • Change it to a "+" button once some tags exist

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.