You are browsing as a guest. Sign up (or log in) to start making projects!

DrewRat

@DrewRat

Joined June 3rd, 2026

  • 21Devlogs
  • 2Projects
  • 1Ships
  • 15Votes
I like making useful projects on the internet! Currently working on Neptune, just shipped Tungsten!
Open comments for this post

2h 19m 31s logged

IM BACK!!! :steamhappy:

SUPER exciting updates today!!! I just got back from vacation and I have motivation!!

LOGO!!!! :ralsei-nurse:

Neptune has a logo!!! I think it looks really good, I whipped it up in Inkscape in like 20 minutes. You wouldn’t believe what it’s supposed to be!

Self hosting!!! :docker-transparent:

This was supoer easy. Since this uses the same stack as Tungsten (which you should totally go check out also), I was able to copy over the dockerfile and docker-compose with minimal changes. However….

Timezone issues!!! :yayayayayay: Wait…. :husk:

Yep. There are a lot of edge cases I didn’t think of. As soon as the server and client’s timezones are different, things get stupid. Javascript dates are genuinely one of the worst things I have ever used, I’d even go as far as to say it’s worse than java as a language.

Both the ICS calendar import and export, as well as the course times were incorrect by +/- 6 hours (I am in UTC-6, so that explains it)

I spent way, WAY longer than I should’ve trying to fix this. It ended up taking like 2 different changes that affected the database as well. Usually I try to make my git commits clean and well-described, but that didn’t last very long here…

The best part: it still doesn’t work properly! I don’t know why, but the ICS viewer I’ve been using to test reads the file differently than Google Calendar, which thinks my 10am class is at 4am. Not to mention, Google Calendar only updates your subscribed calendars once every like 6 hours!! So every time I make a change to (hopefully) fix it, I have to wait.

Devlog Meta Section

Unfortunately I don’t have much else to show for this update… that was all I worked on for 2 hours. I know. Anyway, I hope to add some more real features very soon!

0
0
5
Open comments for this post

1h 37m 24s logged

Course colors, Course/meeting editing, and more timezone bugs!! :ralsei-blunt:

Wow! A devlog of reasonable length! Surely that means it will be shorter right?
Kinda, I added a lot of things but it was pretty easy!

Calendar colors 🎨

This one was really easy to implement, as the calendar component allows you to specify a border/background color. All I needed to do was add it to the creation modal and boom! I stole the color picker from Filatrack as it’s a good component and I don’t see a reason to make a new one

Unfortunately, these colors will not show up in the iCal subscription as iCal doesn’t support colors.

Course card view modes

The “Today” card at the top can now show you tomorrow and all courses! Once again, super easy to implement, literally just another state and changing what courses are grabbed based on that state.

I also fixed a glaring bug where you’d see courses from every term. I’m not sure how I didn’t consider this, but now you’ll only see courses for the current term!

Editing courses/meetings

This one got a little tricky. The modal is already designed to be used for creation and editing, I just had to implement the latter.

Editing courses is no big deal, however; it just changes what function it uses. Its editing meetings that’s a little tricky. You have to make a separate request to edit the meetings that are in the db, create ones that you’ve added, and delete ones you’ve removed. It ended up being relatively simple, but there’s a couple edge cases that could snag ya.

Timezone bugs :husk: :grr:

I don’t even know how this one happened. I looked at the calendar when I was working on other things and suddenly realized all my courses were 6 hours ahead of where they should be. iCal events worked fine. I didn’t even change anything in this area so I just subtracted the timezone offset when getting the events for the calendar and called it a day.

What’s Next?

I totally lied last time, so this time I’ll be honest: whatever I feel like doing. See ya next time!

0
0
2
Open comments for this post

5h 14m 35s logged

Tasks! Confetti! Colors!! Terms CRUD!!!! :yayayayayay:

I’ve added all sorts of things since last update. Colors for courses,
task CRUD, basic CRUD for terms, confetti, and so many bug fixes!!

Tasks ✅

CRUD is never that hard to implement with this stack, but with tasks,
the UI is more of a beast to handle. I wanted it to be more inline then
creating courses, for example. We’ve already seen the C in CRUD from
last devlog, so here’s the RUD!

Everything is handled in a popover rather than a dialog, as it’s a lot
cleaner, and for quickly clicking through tasks, a lot easier.
Unfortunately, the code is a little messy here as I copied basically the
same thing like 3 times. I will probably fix this later?

Anyway, pressing “edit” in the popover allows you to edit the title (and
thus the due date, priority, URL, and course), as well as the URL in a
separate input and a note for the task, which couldn’t be auto-filled
from the title bar. How I’ve made it, these two inputs are handled
separately from the rest of the task editing, and when you finish
editing it, it sends two requests to edit the task: one for the URL and
note, and one for everything else. This led to a race condition, only on
the client side, that would cause the URL and note request to override
the other one, reverting to the previous state. This was an easy fix
however, just allowing the dispatch function to edit things with a
partial object instead of requiring the full one.

Confetti

Completing tasks rewards you with confetti! Super simple to implement
with the react-confetti library, but it ended up being a little stupid
to manage the state properly so it only went off when you clicked.

Terms

Terms CRUD was simple, however. Since there’s so little to them already,
it was simple to make a spot to edit and delete them. I decided to put
it in the settings page as that’s the most convenient spot.

Bug fixes

Other than the ones mentioned above, here are some more bugs I fixed:

  • Terms not starting/ending at 12:00am
  • in _ (time unit) matcher used current time instead of 11:59pm
  • Task sorting was wrong
  • Term popover could clip out of the screen on smaller devices
  • Term timezone issues :grr:

Next

I’ve got a huge list still. Here’s a non-exhaustive one:

  • More due date matchers (day-of-week, month names)
  • Study tools, such as a pomodoro timer and flashcards
  • Making the whole website a PWA, including notifications

I’m not excited about the latter or the former, but the 2nd one I think
I’ll do next, just because it sounds fun to make.

0
0
1
Open comments for this post

5h 31m 4s logged

I spent way too long implementing these features :nay:

I couldn’t tell you what’s taking so much longer compared to Tungsten, but things are getting done!

To-do creation

I made a basic flow for creating to-do items (it doesn’t create them yet, I got an optical migraine and had to take a nap), but it has some really cool features!

When you create one, all you get is one input as to not clutter things up. What’s cool is you can input a bunch of different things to auto-set some values!

There’s 4 different matchers for due dates, that match the following (parenthesis are optional fields):

  • “Tomorrow ((at) time)”
  • “(in) [time] [units] (ago)”
  • “MM/DD(/YYYY) (time)”
  • “HH(:MM)(am/pm)”
    For the ones where time is optional, it defaults to 11:59pm.

This is a heavy oversimplification as the regex selectors are super long and complicated. Weirdly enough, I kind of enjoy writing regex? It’s a fun problem solving problem.

You can also auto-fill associated course, priority, and a URL! To associate a course, you simply type “SUB123”, with your courses subject and number, and it will find it for you. Priority is simply “!X”, where X is the priority of this task. It goes all the way to 99 if it’s that important!

Meeting Exclusions

Buzzword buzzword. You can now remove specific events from the calendar, like if there isn’t class that day. This took way longer than it should’ve to implement, as FullCalendar is stupid and doesn’t implement exclusion dates in their recurrence implementation, only through RRule. That took some wrangling cause the docs on it are a little stupid, and the library threw some stupid errors but it works now. There’s a new column in the database to store these as well.

Timezone Issues :husk: :husk: :husk: :husk: :husk:

I hate javascript dates. I hate javascript dates. I hate javascript dates. I hate javascript dates. I hate javascript dates. I hate javascript dates. I hate javascript dates. I hate javascript dates.

Somehow, it is simultaneously the most overengineered piece of garbage ever and the least developed part of the language. Many basic features are a complete afterthought, and most of the time, you’re having to some stupid crap just to add time onto a date.

Anyway, after I implemented meeting exclusions, I suddenly noticed the one 10am class I had in the calendar was now at 4am… yeah. You wouldn’t believe what my timezone offset is. -6.

Sooo I fought that for a while, and as it turns out, FullCalendar tries to help, but really fails miraculously and makes things worse. For example, it “accounted for daylight savings” by moving events back an hour after it ended. That made me very glad that’s not actually how the world works, but it had me questioning it for a second.

What’s next???

I’m tired. I don’t know, whatever I get around to implementing tomorrow. Good night!

0
0
1
Open comments for this post

5h 56m 8s logged

I FORGOT TO DEVLOG

I added like 10 million things, I went on tangents that took forever, I forgot to make git commits, I forgot to devlog :aarya_sob:

Calendar Syncing

I’ve really wanted to experiment with this for a while. The in-app calendar can now fetch events from any ICS URL!! It simply fetches the URL you give it, and displays those events alongside your courses. I made them green for now, but they’ll be configurable later!

Additionally, the app exposes an API route that generates an ICS file for all your courses! This way you can easily export your course calendar to other sources like Google Calendar, so you don’t have to input them manually! :yayayayayay:

This took WAY longer than it should’ve, as I was using a website to view the result of the ICS file, and I couldn’t get recurring events to, y’know, recur. I then realized that this was a problem with the viewer I was using, and not my code. I plugged in the URL to the calendar component I’m using and it worked just fine.

To-do list

I did some work on the to-do lists. Primarily, just displaying them and showing relative due dates. They can each have priority, an attached course, an extra description, etc. I’ll be creating the creation flow for them soon as well.

Course Creation Flow

Speaking of creation flows… the one for courses is mostly done! I just have to make it so you can add and select terms. I spent a lot of time getting this one right, as I wanted it to be a smooth, easy experience. I think I nailed it, but let me know how I did!

Next

That’s about all I did this devlog, alongside a million tiny bug fixes. Up next will be finishing the to-do list, that is, if I don’t get distracted.

0
0
1
Open comments for this post

4h 41m 27s logged

New Project!! :yayayayayayayayay:

I’ve wanted to build something like this for quite a while, but just didn’t know where to really start. But here we are!

I wanted to build a web app that helps with school- tracking classes, assignments, etc. This has shifted into being an app for college students, as, well, I graduated.

How to Begin

Beginning this project was a struggle. There’s so many features I want to add so I didn’t even know where to start. I decided to make a quick to-do list to lay everything I wanted out.

Then, I went for the database schema. This is already 10x more complex than my last project, Tungsten, but I decided upon the same stack for this project, as it’s self-hosted, just like Tungsten.

A philosophy I’ve been building with a lot recently is UI first, functionality later, which helped immensely with getting started. However, I need some data!

Well that’s easy. I can just use my college class roster! I already have my classes scheduled and can input them temporaily through another typescript file. (The image you see is NOT the same data. The example data file is gitignored.)

The UI

There’s a couple pieces right now. The “Your Day” section shows all your classes that day and (soon) to-do items.

The calendar shows all your classes for the week, as well as tasks and other events from Google Calendar (soon). This also syncs your classes and tasks back to Google Calendar as well.

The calendar component took a while to find. Originally, I was going to make my own, but as it turns out, that is really hard. Calendars are just really complex to build.
Luckily, I found a library called Full Calendar that does all the hard work. I styled it and made a function to convert my database schema to events, and voila!

The database

Speaking of database schemas… let’s talk about it!

Each user has “Terms”, which is how most colleges split up years. A term (or semester) is typically just one season with a start and end date. That’s how the databse does it too!

Each term has all the courses you’re taking in it. Each course has a name, number, and subject.

Here’s the tricky part: many courses in most colleges have different days and times they meet, sometimes with different professors or different locations.
The database tracks this too! There’s a table called meeting, which describes all the days for a specific meeting time, location, or professor. For example:

  • Class A meets on Tuesdays and Thursdays at 9:00am.
    • This class has one meeting in the db.
  • Class B meets on Mondays and Wednesdays at 1:00pm, but meets at 12:00pm on Fridays.
    • This class has two meetings: MW @ 1, F @ 12.

This works really well and translates to calendar events very nicely as well.

Up Next

The to-do list is next on the list! After that, I’ll work on the google calendar integration as well.

0
0
1
Ship

Tungsten is a simple, self-hosted WYSIWYG Markdown editor. It serves as an open-source alternative to Obsidian. It's got many features, including highlighted code blocks, KaTeX editing, and much more!
To try the demo, open the website and click "Try the Demo"!

  • 15 devlogs
  • 34h
  • 17.84x multiplier
  • 613 Stardust
Try project → See source code →
Open comments for this post

1h 11m 9s logged

Shipping time!!! :yayayayayay:

VOTERS: OPEN THE WEBSITE AND CLICK “Try the Demo”!!!!!

Did some quick bug fixes with the demo and we’re ready for launch! Specifically, making new files was completely broken for some reason, and I added the stardance logo to the README. Additionally, the readme is also fetched from github so I can update it on the fly if necessary.

Error handling

This was last on the list (for some reason), but all network errors are handled with a toast at the top of the screen, which makes it much clearer for everyone what went wrong.

0
0
4
Open comments for this post

2h 7m 22s logged

Themes, more bugs squashed! :steamhappy:

All the themes are based on the Catppuccin color palettes because they are wonderful, and allowed me to focus on other things instead of making a color palette. And it looks phenomenal!

The theme switcher is painfully simple. React’s Context API is so underrated. It saves your theme in localstorage and loads it every time you open the page!

File name restrictions

This one was a little tricky to get correct. I had to go through a bunch of the old logic in the sidebar to ensure that no file names collided, and if they did, make sure that state doesn’t get pushed.

Additionally, I had to make creating files look at the rest of the files in the folder and append a 1, 2, 3, etc. to “New File” so the names didn’t collide as soon as you created them.

I was going to put these same restrictions on the server and realized that would take forever with little benefit, as if you break the client to send requests like that, then you’re going to break it. It doesn’t even break that badly, the files work perfectly fine, it’s really just links. After all, these are self-hosted instances, so if you forge some stupid requests I could not care less.

Link handling

Speaking of links, cross page links are functional again! I procrastinated this one too much but I just needed to make a new helper function, nodeFromPath. It takes an array of strings, being the path to a node, and give you the node (or undefined) that path leads to. I just love working with trees so much, recursive functions are my favorite :clueless:

0
0
3
Open comments for this post

4h 26m 4s logged

Self hosting, GitHub actions, SO MANY BUGS!!! :yay:

Yay!!! Big updates!!! Almost ready to ship!!! (optimistically)

Self hosting

This is a big one. It also took me forever. But self hosting is fully functional through Docker!

Not displayed is the 5 hours it took me to actually learn Docker… I have used it before but I haven’t actually learned what I was doing. Containers, images, volumes, compose, blah blag. But, it’s worth it because self-hosting is now just one or two commands away.

A lot of the hours listed on this devlog is writing + refining the SELFHOST.md file! It’s a detailed document that describes Tungsten’s stack and how to host it on your hardware. Soon I hope to bring this to an actual website like the landing page for Tungsten.

GitHub actions

This is slightly less interesting, but gh actions are set up! It’ll test building the full project, then push a docker image, and do a quick codeql check. I copied most of this from Filatrack, I’ll be honest, but what can I say? It works great!

Bugs

I tried uploading an image while I was testing stuff and realized that Next.JS limits the body size of server actions quite a lot. Luckily there was an option to change it, and now you can change it to what you want!

Also, the state of which files were unsaved got messed up somehow. When you clicked between an unsaved tab and a saved tab, the saved one would become unsaved! Quick fix but was pretty funny.

What’s Next

Well, my todo list is only getting fuller as the days go on. I pretty much add one or two things for every one I cross off. But all I’ve got left is to fix cross-page links (I broke them last devlog), file name restrictions (like a real filesystem), an options page, and proper error handling. After that (and whatever else I add), we’ll ship!

0
0
5
Open comments for this post

3h 8m 13s logged

Landing page, demo mode (for you!) MANY bug fixes! :yayayayayay:

The landing page is pretty simple. I’m not an artist by any means, so this will do. It’s mostly for you voters/reviewers to get an overview and try the demo!

The demo is super simple. It’s a simple env flag that will change the landing page to what you see now. The demo button simply tries to log you in to the user “[email protected]” with password “demodemo”. This is the only user that will exist in the database, so it will just log in to that. All the server actions have their behavior changed in the demo to not make any changes to the database as well, so whatever you do isn’t saved.

Bug fixes

As you can see in the second image, I fixed many things that were bugging me. Namely, the URL bar. That’s how files would be selected, but it caused some really stupid state issues that caused a multitude of bugs and like 2 hours of headaches. That’s gone, and so is autosaving. Everything is now more performant as well!

0
0
3
Open comments for this post

1h 24m 28s logged

Super not interesting update!!

The editor now has a raw and read only view! The raw view lets you edit the raw markdown, and read only does exactly what you think it does.

I ended up rewriting the logic for saving/loading in the editor, because it got extremely messy and was breaking down with all the features I’ve been adding. You won’t notice anything different, but it’s much more reliable!

0
0
1
Open comments for this post

53m 32s logged

Bug fixes, tables and a logo! :yay:

We’re getting close to release. I’ve got a couple features I’d like to add and we’ll get going.

Firstly, the logo! I made it myself of a reference image of actual tungsten, cause it’s a cool element. I based the style around the Obsidian logo, with distinct sections each with their own gradients to simulate lighting. My take on this uses all straight lines, as that’s part of the design of the UI. This is my first time really making SVG art, I think it looks pretty decent! :yay:

Next, tables! :table: and an upgraded menu bar!

Surprisingly, tables were one of the easiest plugins to add. All my CSS work from like a week ago carried over here and it looks great. There might be some changes I do later on however.

And a bunch of unrelated bug fixes that had to be done, as always.

0
0
3
Open comments for this post

2h 40m 40s logged

Cross file links!

Links to different files work great! There’s a small dialog to edit the link and whatnot and it’ll take you to the specified page!!

As much as I want to use wikilinks for this, that would require a custom plugin I don’t know how to make (I don’t even know if it’s really possible with MDXEditor). I’m gonna leave it at this for now, as the create link dialog works great for making them.

I had to make some pretty major changes to how selecting files works, however. If you look at the URL bar, it now shows the selected file in it. That is now what determines the selected file, which I’ve been meaning to do for a while and makes links infinitely easier.

0
0
3
Open comments for this post

2h 17m 46s logged

Big updates today!!! Math and images!!

Math was probably the hardest thing to add due to the lack of extensibility of the MDXEditor component I’m using. The plugin system is overly complex and makes zero sense since there is hardly any documentation on how to actually use it. Luckily, there is a jsxPlugin that lets the user make custom jsx components of your choosing.

The other hard part was finding a suitable editor for the job. After much googling, I found MathLive, which is a currently unmaintained editor that does exactly what I need it to. Internally it uses KaTeX, which is what I was looking for.

Now the problem arises: combining these libraries. This wasn’t easy; it took a lot of trial and error, as the documentation is limited. But the final result is incredibly worth it.

A couple bugs still exist; notably, pressing the left or right arrow into the math editor does not focus your cursor in it; and similarly for moving out of it. I have no clue how to fix these, MDXEditor is not helpful in the slightest. A minor bug I can fix however is the autosaver not saving if only the MathEditor has changed.

Images

This one was so much easier! There’s a built in plugin for it. It even handles image resizing! I just have to handle uploading images to the server. I decided to make a table in the database that simply stores filenames and their associated users, just so you can’t access other user’s images. When you upload a file, it gives the editor a link to api/image/random-uuid.png. The api route checks the user id against the database and gives you the image in response.

Possibly the dumbest thing ever is the fact that the image plugin limits the minimum size of the image at 100x100px. I don’t like this however cause I want to be able to put emojis in my markdown files, with possible support for later uploading custom emojis and using them in the editor. There is no customizing this value, it is hardcoded in the library. Luckily, pnpm natively supports patching node modules, and that’s exactly what I did. The minimum size is now 10x10!

0
0
1
Open comments for this post

2h 7m 49s logged

Creating, renaming, and deleting files/folders!

This one took a hot minute but it works really great! It’s so much better than using a modal to do everything!

I didn’t actually know this but the tree component has support for creating files like this out of the box, it’s just not listed in any documentation so it took me a bit to find. It actually starts by creating a file named “New File”, then just immediately renaming it, which is a much cleaner solution than what I was planning :yay:

Renaming is painfully simple, as it handles a bunch of the work too but it’s actually a completely different component it changes to when you start renaming, which ended up being so much easier to work with.

I ran into one of the stupidest bugs ever while implementing renaming. The best way to describe it is “When renaming a file, if it is the open tab, whenever it autosaves it will reset the rename input cause it rerenders.” But basically, the autosaver would save the selected file, causing everything that uses useEditor to rerender, including the sidebar, which makes it re-render the input component for renaming, which resets the text to it’s initialName. It wasn’t hard to fix, I just made the autosaver not save if the content hasn’t changed, which I’ve been meaning to do anyway.

For now, that is most of the hard features done :yayayayayay: the last hurdle that I’m not excited to implement is links between pages. I have no clue how that will work, especially with the component I’m using. But that’s next!

0
0
3
Open comments for this post

2h 16m 42s logged

Code blocks!!! Now without major lag!!

A very annoying bug with a solution I can’t believe I missed. Basically, to get large code blocks to work, MDXEditor gives you a codeMirrorPlugin. This plugin lets you pass a list of languages to have in the selector and to have syntax highlighting support for (codemirror provides a very large data set of them, luckily). The problem was, this list was very large and caused lag when typing.

I ended up asking the discussions page and (after an unhelpful AI response), we figured out my onChange handler setting a content state that the markdown editor used was causing the whole thing to re-render every time you typed, and with the large language array, causing a lot of lag. You’ll notice in the video the language selector in the toolbar.

So it was a very, very simple fix. I even went through and implemented auto-saving instead (every 5 seconds). It even stops you from leaving if it hasn’t saved yet!

I also fixed a whole slew of scrolling issues with long markdown files. It was the stupidest thing ever and I’m not proud of the fix, but it works now.

0
0
2
Open comments for this post

1h 5m 3s logged

Little more work before the end of the day! (well, it’s past midnight so I guess not)

Large code blocks work and are horribly laggy, will be fixing very soon. They are a pain to style properly since MDXEditor is heavily opinionated and makes everything hard to style.

You can now drag and drop tabs! I only had to install a second library for DnD to make it work! (Drag and drop is the worst thing. Ever.) I love making my bundle size 10% larger with bloated libraries :nyaboomzoom:

0
0
1
Open comments for this post

3h 54m 12s logged

The sidebar is fully functional!! You can drag and drop all your files and folders around, nest them as much as you want, and it will retain all of this information in the database. It only took a database rework and many hours of my life :3cnuke:
Let’s talk about it…

So. The database was originally structured with file and folder tables. Both of them had parentId fields and folders had children. Unfortunately this complicated the code more when I tried implementing this as I had to get all the files and folders and combine them into one array. I looked up the proper way to do this because I clearly was not doing it correctly, and switched to just one table, nodes. This simplified just about everything, and this made me split off the file contents as another table as well. I was meaning to do that anyway just to save on memory, as otherwise all the content of every file would be in memory all the time.

Now this node table has all the same fields as before. How do I render this tree? I looked around for good libraries (there’s almost none), and found react-arborist. Looked great, had alright documentation. I started implementing it, and realized I needed to implement the control functions for moving the elements. That’s easy, I said. It wasn’t :husk:

After like an hour it still was just not working. It was really close but was being weird. I looked up the proper way to do it with this library and apparently there’s a class that has a move function that does all the work for you. And yep. It works. For some reason it turned folders back into files but ended up being an easy fix.

So that was a mess but here we are. It works flawlessly. Now I’ve got to implement context menus in this mess, including creating files in folders, etc.

0
0
2
Open comments for this post

1h 12m 19s logged

You can now save files! The dot indicator works similarly to basically every IDE ever and has surprisingly complicated logic with the close button as well.

The Markdown editor I’m using is kinda a pain, but a lot better than making one from scratch. I had to implement the key listener on the div container for it. Soon I’ll implement the key listener on the whole page with a special handler that components can listen to.

The only reason I even implemented the save system is to make it easier on the database. Without saving, it would write to the database every key press. I like this style better anyway, I think it’s pretty cool that it feels like an IDE!

0
0
1
Loading more…

Followers

Loading…