diff --git a/package.json b/package.json index 3577b0881..09b44bd52 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "postinstall": "patch-package --patch-dir ts/patches" }, "dependencies": { + "@floating-ui/dom": "^0.3.0", "@fluent/bundle": "^0.17.0", "@mdi/svg": "^6.1.95", "@popperjs/core": "^2.9.2", diff --git a/sass/BUILD.bazel b/sass/BUILD.bazel index 82db2fa88..2e5ac043c 100644 --- a/sass/BUILD.bazel +++ b/sass/BUILD.bazel @@ -75,6 +75,14 @@ sass_library( visibility = ["//visibility:public"], ) +sass_library( + name = "elevation_lib", + srcs = [ + "elevation.scss", + ], + visibility = ["//visibility:public"], +) + exports_files( ["_vars.scss"], visibility = ["//visibility:public"], diff --git a/sass/elevation.scss b/sass/elevation.scss new file mode 100644 index 000000000..b543844c6 --- /dev/null +++ b/sass/elevation.scss @@ -0,0 +1,80 @@ +// Heavily inspired by https://github.com/material-components/material-components-web/tree/master/packages/mdc-elevation +@use "sass:map"; +@use "sass:list"; + +/** + * The maps correspond to dp levels: + * 0: 0dp + * 1: 1dp + * 2: 2dp + * 3: 3dp + * 4: 4dp + * 5: 6dp + * 6: 8dp + * 7: 12dp + * 8: 16dp + * 9: 24dp + */ + +$umbra-map: ( + 0: "0px 0px 0px 0px", + 1: "0px 2px 1px -1px", + 2: "0px 3px 1px -2px", + 3: "0px 3px 3px -2px", + 4: "0px 2px 4px -1px", + 5: "0px 3px 5px -1px", + 6: "0px 5px 5px -3px", + 7: "0px 7px 8px -4px", + 8: "0px 8px 10px -5px", + 9: "0px 11px 15px -7px", +); + +$penumbra-map: ( + 0: "0px 0px 0px 0px", + 1: "0px 1px 1px 0px", + 2: "0px 2px 2px 0px", + 3: "0px 3px 4px 0px", + 4: "0px 4px 5px 0px", + 5: "0px 6px 10px 0px", + 6: "0px 8px 10px 1px", + 7: "0px 12px 17px 2px", + 8: "0px 16px 24px 2px", + 9: "0px 24px 38px 3px", +); + +$ambient-map: ( + 0: "0px 0px 0px 0px", + 1: "0px 1px 3px 0px", + 2: "0px 1px 5px 0px", + 3: "0px 1px 8px 0px", + 4: "0px 1px 10px 0px", + 5: "0px 1px 18px 0px", + 6: "0px 3px 14px 2px", + 7: "0px 5px 22px 4px", + 8: "0px 6px 30px 5px", + 9: "0px 9px 46px 8px", +); + +$umbra-opacity: 0.2; +$penumbra-opacity: 0.14; +$ambient-opacity: 0.12; + +@function box-shadow($level, $opacity-boost: 0, $color: black) { + $umbra-z-value: map.get($umbra-map, $level); + $penumbra-z-value: map.get($penumbra-map, $level); + $ambient-z-value: map.get($ambient-map, $level); + + $umbra-color: rgba($color, $umbra-opacity + $opacity-boost); + $penumbra-color: rgba($color, $penumbra-opacity + $opacity-boost); + $ambient-color: rgba($color, $ambient-opacity + $opacity-boost); + + @return ( + #{"#{$umbra-z-value} #{$umbra-color}"}, + #{"#{$penumbra-z-value} #{$penumbra-color}"}, + #{$ambient-z-value} $ambient-color + ); +} + +@mixin elevation($level, $other: ()) { + box-shadow: list.join(box-shadow($level), $other); +} diff --git a/ts/components/BUILD.bazel b/ts/components/BUILD.bazel index f75360f0a..fd34c73f6 100644 --- a/ts/components/BUILD.bazel +++ b/ts/components/BUILD.bazel @@ -8,6 +8,7 @@ _ts_deps = [ "//ts/sveltelib", "@npm//@popperjs/core", "@npm//@types/bootstrap", + "@npm//@floating-ui/dom", "@npm//bootstrap", "@npm//svelte", ] @@ -40,6 +41,7 @@ svelte_check( "//sass:button_mixins_lib", "//sass:scrollbar_lib", "//sass:breakpoints_lib", + "//sass:elevation_lib", "//sass/bootstrap", "@npm//@types/bootstrap", "//ts/lib:lib_pkg", diff --git a/ts/components/Popover.svelte b/ts/components/Popover.svelte new file mode 100644 index 000000000..d4f00514e --- /dev/null +++ b/ts/components/Popover.svelte @@ -0,0 +1,39 @@ + + + +
+ +
+ + diff --git a/ts/components/WithFloating.svelte b/ts/components/WithFloating.svelte new file mode 100644 index 000000000..1e5094e4f --- /dev/null +++ b/ts/components/WithFloating.svelte @@ -0,0 +1,107 @@ + + + +
+ +
+ +