I'm currently building <https://resheet.dev>, a no...
# share-your-work
d
I'm currently building https://resheet.dev, a notion-spreadsheet-hybrid. Started because I often ran into limitations with Notion and with spreadsheets. In Notion I wanted to be able to just do some calculations (or even have some embedded spreadsheet). Spreadsheets are nice, but I always ran into limitations. I always thought these could easily be overcome by having a more feature-complete programming language. Because I previously failed very hard by being too ambitious, I tried to keep this project simple. ReSheet runs JavaScript with React because of the vast ecosystem and wide adoption. It was important to me that it's core is simple and extensible: Everything revolves around the concept of a "Block", which can be thought of like a cell in a spreadsheet. Blocks can be nested and you're able to write and then use your custom Block completely in ReSheet itself. As ReSheet itself is just one big Block you can embed ReSheet in itself. Maybe sometime in the future I'll get to work on a Block for visual and interactive programming, but currently I'm trying to get it reliably working and useful in the current state. I'd love to hear your feedback and to answer any questions! (Documentation is still lacking. Currently working on adding some example documents (in ReSheet) to better show what's possible)
❤️ 2
🍰 6
s
I'm wondering why there is a keyboard calibration wizard. Everything else on the web works without calibration.
d
Problem is:
Ctrl+?
for example is a different combination in different keyboard layouts. I wanted to keep the "?" constant, not the physical keys which have to be pressed. The latter would be possible without the wizard. And I didn't want to maintain different shortcut settings for different layouts. So this was the easiest solution I could come up with. 🤷‍♂️ It would be almost possible without, but a tiny detail in the keyboard event handling makes this necessary: On a US layout
Shift+/
is "?" and is reported as
event.key === '?'
, but as soon as I add another modifier, like
Meta+Shift+/
I get
event.key === '/'
I suspect others either just use the physical location to determine the shortcut or they maintain different shortcut mappings for different keyboard layouts.
s
I see. As a user, the latter is what I want anyway. The fact that character mapped to
Shift-'/'
does not equal the character mapped to
Meta-Shift-'/'
is not a mistake and needs not be corrected. As soon as you add another modifier, you're in a different and unrelated group in the keyboard layout, and you can't assume that the
Meta-Shift
group equals the
Shift
group. There's really no such thing as
Control-'?'
. When I see such a key binding, it confuses me, and I think it was made by some American who has a question mark key on their keyboard, and I assume it's not accessible to me. The key binding is really
Control-Shift-'/'
, regardless of whether
Shift-'/'
happens to type a question mark. Keyboard layouts vary in what modifiers need to be pressed. Imagine you have the key binding
Shift-'1'
, and then someone comes with a Czech keyboard, which requires holding
Shift
to type digits, and then the key binding becomes the nonsensical
Shift-Shift-'+'
. Here's an excerpt from a handbook I'm writing in text editor design:
Key bindings should be the actual keys on the keyboard, not the characters the keys type after applying a keyboard layout that may change due to locale and user preference. Control-z should be the same place on the keyboard regardless of whether the keyboard layout causes the z key to type the character z (English), y (German), w (French), Я (Russian) or ; (Dvorak).
d
Regarding your example on Ctrl-z: It is mostly practice that it still is Ctrl-z on a german keyboard, even though it is a different location. Without judging if this was a good design in the first place, I think it's not unreasonable to follow this practice. Your example with the Czech keyboard layout is one of the cases I avoid with this design: Neither do I have
Shift-'/'
nor do I have
Shift-'1'
as a keybinding. Another note: I'm not sure if/where you're speaking of
'/'
as the key in any keyboard layout that generates a
'/'
, or if you mean the key location, that generates a
'/'
on a US layout. If you were only speaking of the former, then your remark about
Control-Shift-'/'
has the same problem as you described in your Czech example: On a german keyboard
'/'
is typed by pressing
Shift-'7'
, so there is no
Shift-'/'
as this would be
Shift-Shift-'/'
. The part about not being clear enough how
Control-'?'
can be typed is indeed something I have to clarify in the app.
I'm also not super-invested in the way I solved this. I may change it in the future. It was just the option that seemed most sensible to me under the circumstances I had. (Which included how much time I want to invest, does it work cross-keyboard-layout, how do I display the shortcut, do I have memorable shortcuts, etc)
s
> It is mostly practice that it still is Ctrl-z on a german keyboard, even though it is a different location. Which is a practice that annoys me every time. Even more so the Vim style directional keys
j
,
k
,
l
,
;
, a variation of which is present in your app. > Your example with the Czech keyboard layout is one of the cases I avoid with this design Even if you never bind the digit keys, you'll still have problems with Russian layouts among others that don't have the letters
a
to
z
. I used to have a keyboard layout where a question mark is typed with the
Alt Gr
modifier, which the calibration wizard does not support at all. > I'm not sure if/where you're speaking of
'/'
as the key in any keyboard layout that generates a
'/'
, or if you mean the key location, that generates a
'/'
on a US layout. I wasn't generalizing this particular example beyond the US layout, so the distinction doesn't matter. When generalizing, my suggestion is to bind keys to actual locations every time.
d
I see, you're right, my approach still has limitations. When I have time, I need to work on that.
d
ReSheet looks great, I like the mix of examples - versatile! & I like the portability via json Will it be feasible to embed sheets: onto a static site, for example?
❤️ 1
d
Yes, it is itself completely static (in the sense that the webserver just serves static files and doesn’t do anything else). In https://github.com/keenbug/ReSheet/tree/main/src/web you can see how it is built at the top level in index.html and index.tsx.
You can also switch what the outermost block should be by changing ToplevelBlock in src/web/index.tsx. So for example you could just have a SheetOf(Note) without the whole pages and sidebar stuff (which is implemented in the DocumentOf block)
d
Cool, close tie to React is interesting. I use Observable JS a lot. You hit a key thing I like a lot about reactivity, and React for complex UI could be neater (yet every time I try to mix reactivity things it gets messier than I can comprehend!). My project is like a spreadsheet: calculang (calculang.dev), but detached from layout/UI: only the abstract calculation part as a core concern. To now though all my examples are using OJS. I think that ReSheet blocks are non-module type, any plans to interoperate with module type/ESM?
I looked at running a calculang model (savings calculator) from resheet and resheet UI elements and got something 😀
🔥 1
d
Nice! Ah yes, I've seen calculang and was intrigued by the concept and really like the examples! I'd love to see more projects here to interoperate and I thought maybe ReSheet could provide some sort of framework for that. (Edit: Removed comment about OJS, because I confused it with something else) I'm not sure what you mean by interoperating with ESM: Do you mean that one could use ReSheet documents (or parts of it) like modules somewhere else? I thought about adding some type of export, so you could generate .mjs files from your document. But I don't have any concrete plans yet. The current workaround could be to write some converter from the saved json documents to mjs. Importing ESM is possible, like you already did. And writing custom blocks and importing them as ESM is also possible, but still need some workarounds. I want to split ReSheet into packages, so you can use the Blocks API as a package to build your own Block. Currently the best way is to create a function, that takes global
resheet
value as an input and uses the ReSheet API from there. So after importing the function in ReSheet you'd call it with
resheet
to get your Block. (A little bit like the module system workarounds predating ESM) So it would look something like that: `@your/block-on-npm`:
Copy code
export default function(resheet) {
  return {
    MyBlock: resheet.core.block.create({
      /* your block definition */
    })
  }
}
in ReSheet:
Copy code
myLib
= (await import('<https://esm.sh/@your/block-on-npm?external=react').default(resheet>)

/myLib.MyBlock
You can also send me a private message any time, I'm happy to help if for example you're trying to build something and the documentation is lacking or some weird errors come up.
d
Thanks Daniel. One ESM import didn't work, maybe something on my localhost but I'll try it again when hosted. Overall seems very interesting for customizable UIs!