Closed samuelandert closed 4 years ago
The lack of opinionated design system in Svelte-land is very much why I started building Designspek. My inspiration and foundation was Svelte Styled System. I'm not a new JS developer, but this is my first complex library — abstraction — that intends to be useable by other people.
I think a tool like Blocks UI is beyond the scope of this library, but would be highly complimentary. At the minimum, a specification ("theme") generator is planned. Right now, I'm just stumbling through learning Svelte, applying this library to projects I'm working on and building a clearer understanding of where Designspek can/should go.
In comparison to Tailwind CSS, Designspek may have parallel practices, however right now its more of a CSS-in-JS solution rather than a style framework. Technically, the 'utility-first' styles of Tailwind can be used alongside Designspek. Or Designspek could create it's own utility-style objects to use in a similar manner as Tailwind.
I honestly haven't gotten that far in thinking. The latest struggles have been focused on finding a best practice for working with SSR and finding a way to pre-calculate styled values. This would mean that Designspek becomes a pre-processed CSS-in-JS solution — a best-of-both-worlds with development and flexibility benefits of CSS-in-JS without the production drawbacks normally inherent to such solutions.
I like your way of thinking and your CSS-in-JS approach and I understand that Blocks UI is beyond the scope of Designspek. I am quite willing to learn and help you as far as a I am capable of. What do you think about, as you suggested, if we create on top of Designspek our own utility first system, which is inspired by tailwind. If you help me getting started in how to implement it with some basic best practices, I happily do the foot work of adopting the tailwind syntax step by step and component by component.
I am grateful for your continued thought and engagement. If I may coax you further in consideration:
Have you used Tailwind directly with Svelte? What shortcomings or barriers have you hit that has you looking to other solutions?
When building your apps or websites are there features you are specifically looking for in a styling system? Priority of those features? (e.g. rapid building, consistency, team-friendly, performance/optimization, etc)
Have you used other CSS-in-JS solutions like for React (Themed-UI, Emotion, Styled Components, etc)?
In your OP, you talk about re-naming aliases, but to be clear, in Designspek these are just "shortcut" aliases that resolve directly to CSS properties. In JS, camelCase is used to write these properties, so most JS conversion to CSS looks like borderRadius
--> border-radius
. Shortcut aliases are simply for rapid-development through less typing:
{ m: 1, px:2 }
resolves to something like:
margin: 1rem; padding-left: 2rem; padding-right: 2rem;
"Classes" in Designspek are just objects of styles. There are natural shortcut aliases that act like utility classes, like the margin/padding shown above or for specific things likes colors declared in the theme (eg primary: '#012345'
), but otherwise you'd declare your own style objects like:
export const Card = {
d: 'block',
pos: 'relative',
zIndex: 1,
bg: 'background',
boxShadow: '0px 3px 6px rgba(0, 0, 0, 0.16), 0px 3px 6px rgba(0, 0, 0, 0.23)',
my: '2rem',
mx: '0.5rem',
p: '1rem 0.75rem'
}
\\ right now you have to use $theme.colors.background, but re-adding theme aliasing is high priority
You could create your own "utility" objects by declaring separate style objects and composing them. You can even keep them in a utilities-styles.js and import wherever needed:
export const containerSpace = {
my: '2rem',
mx: '0.5rem',
}
export const containerPad = {
p: '1rem 0.75rem',
}
export const shadowed = {
boxShadow: '0px 3px 6px rgba(0, 0, 0, 0.16), 0px 3px 6px rgba(0, 0, 0, 0.23)',
}
export const Card = {
d: 'block',
pos: 'relative',
zIndex: 1,
bg: 'background',
...containerSpace
...containerPad
...shadowed
}
export CardHero = {
...Card,
bg: 'primary',
txtAlign: 'center'
}
In this way, I only need to create useful utility/pattern style objects as I need them. I'm both a graphic designer and programmer, so I usually generate my styles/themes in applications like Sketch, Figma, XD, etc. Then I code my style objects by page/view, layout, component, and extract common patterns/re-used styles (utility classes essentially) as needed. Defining my own utility objects means I pre-define consistency. I then do a final "optical" tweaking as things comes together.
A major consideration in Designspek is making those utility/patterns declarable in the theme. For a complex site, I end up have 20-30 at most, but everything else reasonably lives within their layout/element/component files. With JS, I don't care about class naming — it all renders out to something like '.go239232, .go123123' — which is half the battle when working directly with CSS/LESS/SASS, etc.
So yes, one could technically re-create Tailwind using Designspek, but consideration on value created versus just directly using Tailwind is recommended.
If I haven't chased you away and you still desire to discuss further or even collaborate, I'm quite happy to do so. Talking about all these facets facilitates further learning, understanding and clarity on my part!
Wow, thank you for the detailed response, very much appreciated as well. Let me quickly give you an introduction in what has triggered our passion to start working on our open source startup.
Our vision is to enable everyone to build up and quickly test any of their own ideas and platforms in as fast as possible rapid iteration steps, while featuring and committing to the open source paradigm for any industry.
Our mission is to offer an opinionated decentralized fullstack framework and platform builder with an maker friendly Userinterface and integrated easy drag and drop lego-like building blocks in order to enable everyone to build modern opensource multiplatform and resilient serverless (d)apps. A lot of our product inspiration comes from CODA, NodeRed, Figma, Storybooks and the GraphQLEditor.
Currently we are exploring various technologies by building many mini proof of concepts. Our first MVP is an offline first, decentralized and serverless encrypted by default database and schema editor build on ipfs and textile with an typesave ORM-Layer based on graphql with default realtime updates via subscriptions, including some reactive UI/UX sugar-syntax with svelte. So far we have build on top of textiles ThreadsDB a basic CRUD-GUI and our custom graphql adapter and tailwind css styling. We will launch this POC in a couple of days for others to play around with it.
For me this is the first serious developing project and I am learning a lot while just jumping into it.
Have you used Tailwind directly with Svelte? What shortcomings or barriers have you hit that has you looking to other solutions?
On this first POC I was using tailwind.css in a svelte project in order to get moving rapidly. I quite loved the utility first approach and the syntax of tailwind. After using it a while I stumbled upon the following shortcomings:
When building your apps or websites are there features you are specifically looking for in a styling system? Priority of those features? (e.g. rapid building, consistency, team-friendly, performance/optimization, etc)
I think the priority you mentioned is:
In your OP, you talk about re-naming aliases, but to be clear, in Designspek these are just "shortcut" aliases that resolve directly to CSS properties. In JS, camelCase is used to write these properties, so most JS conversion to CSS looks like borderRadius --> border-radius. Shortcut aliases are simply for rapid-development through less typing:
Ok now I understood that and slowly I get my head around it. Thank you. Basically, designspek's shortcuts are just normal css and are not like tailwind utility classes, as they allow any css value to be ingested. As far as I understood you the benefits of tailwinds utility classes or in general system UI is consistency by design through restricting the possibility with scales for each design token.
{ m: 1, px:2 } resolves to something like:
How can I create my own shortcuts / alias?
You could create your own "utility" objects by declaring separate style objects and composing them. You can even keep them in a utilities-styles.js and import wherever needed:
How would I create for example a rounded "utility" object with the following scale: [xs, s, m, l, xl, 2xl etc] or margin and padding with [1,2,3,4,5,6,8,10,12,16], where the scale is f.e. [1=0.25rem, 2=0.5rem, 3 = 0.75rem etc]. I think in the ideal world applying utility classes would look something like the following, where the array will resolve into container based responsiveness rather than the media queries:
export const DIV = { rounded: 'xs', px: [2,4,6,10], py: [1,2,4,8], m: [2, none, 4], bg: green.500, text: primary, shadow: 'xl' }
warning: I'm pushing back on your statements, but it is truly with all due respect and good intention. I've also guilty of herding this conversation into a more conceptual direction.
Our mission is to offer an opinionated decentralized fullstack framework and platform builder with an maker friendly Userinterface and integrated easy drag and drop lego-like building blocks in order to enable everyone to build modern opensource multiplatform and resilient serverless (d)apps.
From this context, your inquiry into Designspek is for the developer experience of yourself/your team. In contrast, your end-user doesn't care about classes and instead that they can build what they want, that it works, and is performant to the UX of their own end-users.
This is none of my business, but after near a decade jumping in and out of startups/crypto/decentralized/FOSS, etc, I can't help but caution you to keep focus on your mission and use what you know best despite any shortcomings. Avoid side-quest at all cost.
• I wanted to store all theming, all utilities, styles and component definitions in the database for easy plug in play reuse and remix for anyone and I didn't find a nice way of doing this with tailwind alone.
I'm not exactly sure what you're attempting, but it feels like there's multiple issues that you're trying solve but all rolled up into one solution. It might be better to break it apart and clarify what exactly you want in comparison to the intentions of the various libraries/frameworks you're looking at.
• tailwind is one big monolith which I felt was not easy to customize, especially integrating it into rollup and webpack is not that easy for beginners.
- RAPID BUILDING with Utility classes in order to get going
Build/bundling setup aside (though Google, et al shows plenty of people using Svelte + Tailwind), purpose of utility-classes-first approach and customization are at procedural odds with each other.
- CONSISTENCY while abstracting common building blocks into reusable styling components with clearly defined interfaces for its accepting parameters.
On Consistency: it is difficult because without strong scoping, specification and adoption, it washes out to subjectivity and burden.
In a parallel train of thought, the pursuit of ideals such as consistency without caution lead to over-engineering, over-abstraction, pre-optimization, and other development pitfalls.
In particular, I am pushing back on the concept of "container queries" as really just being pre-optimizations best reserved for as-needed/edge cases. Something like BlocksUI might very well be that edge case but once again, I argue careful consideration:
My personal conclusion is that the value created by container queries is much smaller than the cost to implement and maintain them. At best used only for edge-cases.
Related thoughts from your presented ideal application:
export const DIV = { rounded: 'xs', px: [2,4,6,10], py: [1,2,4,8], m: [2, none, 4], bg: green.500, text: primary, shadow: 'xl' }
- In the big picture, this is one abstract view of how things ought to be done. If we were all so agreeable, the JS ecosystem would be much narrower. For an abstraction to survive, it needs adoptees to sustain it.
- Context of "container size" vs "device screen size": When I see [1,2,3] and I know it relates to [320px, 768px, 1024px] and I go from style to style, the context remains the same. When that changes to the arbitrary size of a containers and uncertain relationship between their parent containers and how they respond, it becomes a much more difficult context to manage.
- uses many types — defining with strings, numbers, arrays, objects and variables!
- Potential issue — margin array only has 3 items (and extra-finnicky: has both string and number values) — when combined with the context item above, reasoning how things smoothly degrade, errors are handled, etc. there's a lot more coding to be created to handle the additional surface area.
- The finicky-ness items could surely be smoothed by tooling, conventions, docs, etc. but keep in mind the added cost of reasoning, maintenance, adoption, coding the extra tooling, etc.
But to your questions:
How can I create my own shortcuts / alias? How would I create for example a rounded "utility" object with the following scale...
This level of flexibility/customizability isn't currently possible or planned. One of the attempts of this library was to try to keep it as small as possible while adding convenience of theming and CSS shortcuts. Svelte-Styled-System (which is inspired by but doesn't use Styled System) was a bare 1kb compressed. Extending to actually used Styled System plus a larger subset of the CSS API jumped Designspek to 8-9kb compressed. This is still less than the 13-16kb of Emotion/styled-components. As soon as I figure out the best way to parse styles and aliases with less loops and getting rid of Styled System, hopefully the library size will drop back down again and be more performant. This is technically one of the downsides of CSS-in-JS where you have cost of code to process styles + cost of style definitions. Once again, a balance of developer experience vs cost to user experience. Given the slimmer profile provided by the compilation nature of Svelte, it's an affordable cost from my perspective and a moot point if a preprocessing method is established.
• The way you build ui components with tailwind is by using @apply in a separate stylesheet, where (at least for me) it was not easy to integrate javascript variables. I much prefer your approach there, which gives a lot of flexibility, while maintaining consistency.
Is this true in Svelte? Given it's compiling nature I would think at worst you would have to concatenate strings or compose objects. The few example I saw using Tailwind certainly had component and styles together.
I'm closing off this thought exploration for now in lieu of the the stance of Designspek taken in the Scope of Specifications issue #7 .
Thank you kindly for contributing to the thought cultivation of this library.
Alright, good talking to you, thank you very much too
Is your feature request related to a problem? Please describe. As a newby to the world of programming I find it quite hard to get into the abstraction of building a proper and nice designsystem from scratch. And as far I researched in svelte world there is a lack of good reference implementations.
Describe the solution you'd like I quite like the Blocks UI project which is sadly based on react. It would be great if there is just a very basic remake of Blocks in a Svelte REPL. I think for the POC just two different themes and two components, maybe a button with different variations and a header including the button component, are more than enough. (without even drag and drop).
Describe alternatives you've considered I played around with Svelte Styled System, but I don't know how to continue in order to customize and extend the theme and change the aliases (f.e. change the 'borderRadius' to the tailwind syntax 'rounded-' with a custom scale f.e. ["xs","md","lg","full","etc"]
Additional context I would like to bring the tailwind css syntax and theme specs including their nice aliases to the svelte world with the possibility to create and extend it into svelte native UI components. And then build a Blocks UI like design editor user interface to arrange and style the different components.