-
-
Notifications
You must be signed in to change notification settings - Fork 180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
example/darkmode: add darkmode example #185
Open
matthewmueller
wants to merge
1
commit into
main
Choose a base branch
from
darkmode
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package controller | ||
|
||
import ( | ||
"net/http" | ||
) | ||
|
||
type Controller struct { | ||
Writer http.ResponseWriter | ||
} | ||
|
||
func (c *Controller) Index() {} | ||
|
||
func (c *Controller) Create(theme string) { | ||
http.SetCookie(c.Writer, &http.Cookie{ | ||
Name: "theme", | ||
Value: theme, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules/ | ||
bud/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module github.com/livebud/bud/example/darkmode | ||
|
||
go 1.18 | ||
|
||
require ( | ||
github.com/livebud/bud v0.0.0 | ||
) | ||
|
||
replace ( | ||
github.com/livebud/bud => /Users/m/dev/src/github.com/livebud/bud | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= | ||
github.com/ajg/form v1.5.2-0.20200323032839-9aeb3cf462e1 h1:8Qzi+0Uch1VJvdrOhJ8U8FqoPLbUdETPgMqGJ6DSMSQ= | ||
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= | ||
github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= | ||
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= | ||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= | ||
github.com/evanw/esbuild v0.14.11 h1:bw50N4v70Dqf/B6Wn+3BM6BVttz4A6tHn8m8Ydj9vxk= | ||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= | ||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= | ||
github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ= | ||
github.com/gitchander/permutation v0.0.0-20201214100618-1f3e7285f953 h1:+rJDfq6waeB1BncyEfuFL1N3U7t3aahrAjPqcKLpMys= | ||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= | ||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||
github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= | ||
github.com/matthewmueller/diff v0.0.0-20220104030700-cb2fe910d90c h1:yjGBNrCIE7IghJAwrFcyDzwzwJKf0oRPeOHx60wfkmA= | ||
github.com/matthewmueller/gotext v0.0.0-20210424201144-265ed61725ac h1:SjopLdUF96kdJU8ynYmGVHoJmngpwFHRvR5p2plBXG4= | ||
github.com/matthewmueller/text v0.0.0-20210424201111-ec1e4af8dfe8 h1:XTmVlF7P9bpSNkLFlxpNlhig0kaVJ5mO4D3yK2CYjmM= | ||
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= | ||
github.com/pointlander/compress v1.1.1-0.20190518213731-ff44bd196cc3 h1:hUmXhbljNFtrH5hzV9kiRoddZ5nfPTq3K0Sb2hYYiqE= | ||
github.com/pointlander/jetset v1.0.1-0.20190518214125-eee7eff80bd4 h1:RHHRCZeaNyBXdYPMjZNH8/XHDBH38TZzw8izrW7dmBE= | ||
github.com/pointlander/peg v1.0.1 h1:mgA/GQE8TeS9MdkU6Xn6iEzBmQUQCNuWD7rHCK6Mjs0= | ||
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= | ||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI= | ||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= | ||
github.com/timewasted/go-accept-headers v0.0.0-20130320203746-c78f304b1b09 h1:QVxbx5l/0pzciWYOynixQMtUhPYC3YKD6EcUlOsgGqw= | ||
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= | ||
go.kuoruan.net/v8go-polyfills v0.5.0 h1:wd2WxsFIXWK/FcrpITw6BOo8Rn24xMmd4qoHofgg8hc= | ||
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= | ||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= | ||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= | ||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= | ||
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8= | ||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= | ||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= | ||
rogchap.com/v8go v0.7.0 h1:kgjbiO4zE5itA962ze6Hqmbs4HgZbGzmueCXsZtremg= | ||
src.techknowlogick.com/xgo v1.4.1-0.20220413212431-091a0a22b814 h1:/oIyHjKnlyQ3yFzxq7uin83l6h0sHXT7Z+9TpP9wr8s= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/** | ||
* Export all by default | ||
* Based on: https://github.com/component/cookie | ||
*/ | ||
|
||
export default { all, get, set } | ||
|
||
/** | ||
* Cookie type | ||
*/ | ||
|
||
type Cookies = { | ||
[cookie: string]: string | ||
} | ||
|
||
/** | ||
* Set options | ||
*/ | ||
|
||
type Options = { | ||
maxage?: number | ||
expires?: Date | ||
domain?: string | ||
path?: string | ||
secure?: boolean | ||
} | ||
|
||
/** | ||
* Set cookie `name` to `value`. | ||
*/ | ||
|
||
function set(name: string, value: string | null, options?: Options) { | ||
options = options || {} | ||
var str = encode(name) + '=' + encode(String(value)) | ||
|
||
if (null == value) { | ||
options.maxage = -1 | ||
} | ||
|
||
if (options.maxage) { | ||
options.expires = new Date(+new Date() + options.maxage) | ||
} | ||
|
||
if (options.path) str += '; path=' + options.path | ||
if (options.domain) str += '; domain=' + options.domain | ||
if (options.expires) str += '; expires=' + options.expires.toUTCString() | ||
if (options.secure) str += '; secure' | ||
|
||
document.cookie = str | ||
} | ||
|
||
/** | ||
* Return all cookies. | ||
* | ||
* This is isomorphic and may be called | ||
* from the server-side though it will | ||
* return nothing. | ||
*/ | ||
|
||
function all(): Cookies { | ||
var str | ||
try { | ||
str = document.cookie | ||
} catch (err) { | ||
console.log(err) | ||
return {} | ||
} | ||
return parse(str) | ||
} | ||
|
||
/** | ||
* Get cookie `name`. | ||
*/ | ||
|
||
function get(name: string): string | undefined { | ||
return all()[name] | ||
} | ||
|
||
/** | ||
* Parse cookie `str`. | ||
*/ | ||
|
||
function parse(str: string): Cookies { | ||
var obj = <Cookies>{} | ||
var pairs = str.split(/ *; */) | ||
for (var i = 0; i < pairs.length; ++i) { | ||
var pair = pairs[i] | ||
var eqidx = pair.indexOf('=') | ||
if (eqidx === -1) { | ||
eqidx = pair.length | ||
} | ||
var name = decode(pair.substr(0, eqidx)) | ||
// +1 because we don't want the = | ||
var value = decode(pair.substr(eqidx + 1)) | ||
if (!name || !value) { | ||
continue | ||
} | ||
obj[name] = value | ||
} | ||
return obj | ||
} | ||
|
||
/** | ||
* Encode. | ||
*/ | ||
|
||
function encode(value: string): string | undefined { | ||
try { | ||
return encodeURIComponent(value) | ||
} catch (e) { | ||
return | ||
} | ||
} | ||
|
||
/** | ||
* Decode. | ||
*/ | ||
|
||
function decode(value: string): string | undefined { | ||
try { | ||
return decodeURIComponent(value) | ||
} catch (e) { | ||
return | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"name": "darkmode", | ||
"private": true, | ||
"dependencies": { | ||
"livebud": "latest", | ||
"svelte": "3.47.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<script> | ||
import cookie from "../module/cookie" | ||
// TODO: fix SSR flickering. cookie.get(...) uses document.cookie under the | ||
// hood. `document.cookie` should be accessible by V8 on the server-side. | ||
// We'll need to take care exposing APIs though. We shouldn't try to polyfill | ||
// the DOM on the server. | ||
const theme = cookie.get("theme") | ||
function submit(e) { | ||
this.form.submit() | ||
} | ||
</script> | ||
|
||
<div class={theme || "light"}> | ||
<h1>Change Theme</h1> | ||
<form action="/" method="post"> | ||
<select name="theme" on:change={submit}> | ||
<option value="light" selected={theme === "light"}>Light</option> | ||
<option value="dark" selected={theme === "dark"}>Dark</option> | ||
</select> | ||
</form> | ||
</div> | ||
|
||
<style> | ||
.light { | ||
--var-color: black; | ||
--var-bgcolor: whiteSmoke; | ||
} | ||
.dark { | ||
--var-color: whiteSmoke; | ||
--var-bgcolor: black; | ||
} | ||
h1 { | ||
color: var(--var-color); | ||
background: var(--var-bgcolor); | ||
} | ||
</style> |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an over-simplification of a feature I recently fixed in Bud. See this PR for details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting - so a controller (or its dependencies) may depend on
http.ResponseWriter
and*http.Request
and they'll be injected in on a per-request basis?That's a neat way of keeping the action methods limited to request params.
I wonder if this comes with extra allocation cost or dependency construction churn though - for example, if I'm modeling my database as a dependency I probably wouldn't want it reconnecting with every request. Or does it only reconstruct dependencies as needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the database client is able to be passed in once through all requests.
There's a concept called in the DI framework called hoisting that's able to externalize dependencies that don't depend on specific other dependencies. Hoisting just means, mark those dependencies as something you need to pass into the provider as well.
In the case of controllers, dependencies that depend on *http.Request or http.ResponseWriter are not hoistable, they need to be re-initialized every request. Every other dependency is.
It looks like this in the generated code:
Where
i.Client
andi.Logger
don't depend on the request, so they're passed in rather than initialized by the DI provider. Session on the other hand does depend on the request, so it's initialized per request.There's definitely an allocation cost though. Even without hoisting, we load the controller every time. If you're doing something expensive in your controller.Load() that would slow things down per request. Thinking about it now, I could see that being quite surprising. Actually, this may point in favor of passing request-scoped dependencies in.
I was indeed trying to avoid mixing dependencies with the API signature, but I think DI is smart enough at this point to be able to filter those keys out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome, thanks for the explanation.
That sounds nice. Do you mean something like this?:
To me this feels pretty intuitive since as you said they're 'request scoped' just like the params are, but I guess you'd need some way for Bud (and maybe the developer) to disambiguate dependencies from params. 🤔
Or maybe you don't? I may be off my rocker here but one way of looking at it is that params are a just another type of dependency that load their values from the
*http.Request
.Whether that's a line you want to blur is another question though regarding UX.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was my thought process at the time, but I'm definitely leaning more towards something like what you wrote now:
Which makes more intuitive sense because the lifecycle is more clear and doesn't suffer
controller.Load()
being potentially expensive. Bigger fish to fry right now, but I'll get back to this one before 1.0!Persisted here: #211