A webapp for democratizing music in public spaces
just do git commits with this template:
<type>(scope): <subject>
example:
fix(styles): padding on buttons
feat(templates): use base template for join.html
possible types are commitizen standard.
uses git-chglog to generate changelogs.
So, we are using preact for this project, as it allows us to do fun reactivity stuff pretty easily. and is much smaller than react + react-dom.
In order to use preact, create a template with this:
{%extends "preactBase.html" %}
{%block title%}title | Shareify{%endblock%}
{%block code %}
{%endblock%}
And you're done, you've made a template using preact!
Now to change the default contents:
preactBase.html
has the function Main
already declared. Those are our two components.
Just add code that redefines the Main
components, and preact will render that component instead of the default.
Instead of using JSX as the html language inside our js code, we use htm which is quite small, and has great integration with preact. To use it, just make a tagged template literal with html
.
Main = () => (html`<p>oooh, html </p>`)
Think of template literals like python's f-strings. where instead of using
{}
to include code, you use${}
.
eg:
{%extends "preactBase.html" %}
{%block title%}A simple demo (clock) | Shareify{%endblock%}
{%block code %}
class Clock extends Component {
constructor() {
super();
this.state = { time: Date.now() };
}
// Lifecycle: Called whenever our component is created
componentDidMount() {
// update time every second
this.timer = setInterval(() => {
this.setState({ time: Date.now() });
}, 1000);
}
// Lifecycle: Called just before our component will be destroyed
componentWillUnmount() {
// stop when not renderable
clearInterval(this.timer);
}
render() {
let time = new Date(this.state.time).toLocaleTimeString();
return html`<span>${time}</span>`;
}
}
main = html`<${Clock}/>`
{%endblock%}
This demo just displays the current time.
Note:
because we are using the "module" type script tag, you have to make sure that you write correct js. That means declaring your variables, y'all. for more info about some best practices, click here.
In regards to variables: use const/let
instead of var
, as const
and let
are block scope, whereas var
is function-scoped (ie. global).
_defineProperty()
is a nice little helper function to let us define properties in browsers that dont support public field declarations. This is literally just copied from a babel build.
How to use:
// instead of:
class Hello extends Component {
state = {
value:""
}
onInput = (ev) => {
this.setState({
value: ev.target.value
})
}
onSubmit = (ev) => {
ev.preventDefault()
this.setState({
name:this.state.value
})
}
render() {}
}
// write:
class Hello extends Component {
constructor() {
super()
_defineProperty(this, "state", {
value: ""
})
_defineProperty(this, "onInput", (ev) => {
this.setState({
value: ev.target.value
})
})
_defineProperty(this, "onSubmit", (ev) => {
ev.preventDefault()
this.setState({
name: this.state.value
})
})
}
render() {}
}
// you might also be able to write:
class Hello extends Component {
constructor() {
super()
this.state = {
value: ""
}
this.onInput = (ev) => {
this.setState({
value: ev.target.value
})
}
this.onSubmit = (ev) => {
ev.preventDefault()
this.setState({
name: this.state.value
})
}
}
render() {}
}
// but i need to check if that works cross-browser. Babel doesnt try to convert the above code, so, uhh, ┐( ̄ヘ ̄)┌,
basically, from what i can tell, doing public fields as in the first example just adds them to the class using the defineProperty
function. So the custom function basically just reimplements the default js behaviour, which makes sense, because it's babel.
all components live inside the components
directory, under individual js files.
for information on how to make them, have a look here
to import a component, add this to the top of the code
block:
{{component_import("Spacer", "WhateverTheFileNameIs", ...)}}
The component name in js should be the same as the filename excluding the extension, not because it affects anything, just because it's nicer.
Then to use a component, include the component like this in your htm template:
html`
<${TheNameOfYourComponent> <//>
`
// or self-closing:
html`
<${TheNameOfYourComponent />
`
name | props | description |
---|---|---|
Spacer |
{text: string} |
takes text and puts it in between two lines. adds y padding. If it can't find text , just displays a line. |
DefaultHeader |
{} |
Shows the header/navbar thingo. |
Link |
{text: string, href: string, hoverColors: array} |
shows an a tag with innerHTML = text, href = href, and hover styling done by hoverColors. hoverColors is set by default to the yellow and black hightlight. |
Note: some components require other components to be loaded, make sure that you load them in your template. Header
and Link
are imported by default.
in order to have the components talk to other parts without having to pass down props, we can use slots.
basically a slot is an element that has some default content, that can then be overwritten by another element somewhere else.
<${Slot} name="foo">
Fallback content
<//>
<${SlotContent} name="foo">
content to replace the other one with.
<//>
Those two elements dont have to be in the same level or anything, they talk to each other using the context api, but you don't need to know how that works.
The header component's nav elements are included in the slot "headerNav"
. this is so you can basically change the contents of it to like, show the room code there.
just run npm i
inside this folder, and it'll install the required packages.
And then run
$ npm run tcss:dev
basically, the dev version of tailwind is pretty massive (2.26MB), but usually you don't need all of the classes provided to you by tailwind. So we have to purge the css of unused classes.
To do this, run
$ npm run tcss:prod
note: i've only tested this with bash. If you have problems with the npm script, basically just run
npm run tcss:dev
with theNODE_ENV
environmental variable set toproduction
. (although, i am using cross-env, so it should work)
PurgeCSS will look for tailwindcss classes in both .html
and .js
files inside of the ./templates
dir. And will look in .js
files inside ./components
. Don't use string concatenation to create class names. Instead dynamically select a complete class name
You shouldn't ever build tailwind for production on your machine. It should be built into the production version when being uploaded to the server. (so, you can run tcss:prod
as a build step basically)