mirror of
https://github.com/jgthms/bulma.git
synced 2024-12-12 13:28:30 +00:00
Create Slider
This commit is contained in:
parent
7d92a2b872
commit
4a165737df
6
docs/_react/bulma-customizer/package-lock.json
generated
6
docs/_react/bulma-customizer/package-lock.json
generated
@ -8,6 +8,7 @@
|
||||
"name": "bulma-customizer",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"classnames": "^2.5.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
@ -1560,6 +1561,11 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/classnames": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
|
@ -10,6 +10,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"classnames": "^2.5.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
|
@ -3,8 +3,22 @@ import "../../../../css/bulma.css";
|
||||
import "./App.css";
|
||||
import Slider from "./components/Slider";
|
||||
|
||||
const KEYS = ["scheme-h", "primary-h", "primary-s", "primary-l"];
|
||||
// const COLORS = ["primary", "link", "info", "success", "warning", "danger"];
|
||||
|
||||
const KEYS = [
|
||||
"scheme-h",
|
||||
"primary-h",
|
||||
"primary-s",
|
||||
"primary-l",
|
||||
"skeleton-lines-gap",
|
||||
];
|
||||
const UNITS = ["deg", "rem", "em", "%"];
|
||||
const SUFFIX_TO_KIND = {
|
||||
"-h": "hue",
|
||||
"-s": "saturation",
|
||||
"-l": "lightness",
|
||||
"-gap": "gap",
|
||||
};
|
||||
|
||||
function App() {
|
||||
const [vars, setVars] = useState([]);
|
||||
@ -14,11 +28,15 @@ function App() {
|
||||
|
||||
const cssvars = KEYS.map((key) => {
|
||||
const original = rootStyle.getPropertyValue(`--bulma-${key}`);
|
||||
const suffix = Object.keys(SUFFIX_TO_KIND).find((kind) =>
|
||||
key.endsWith(kind),
|
||||
);
|
||||
const unit = UNITS.find((unit) => original.endsWith(unit)) || "";
|
||||
const value = unit !== "" ? original.split(unit)[0] : original;
|
||||
|
||||
return {
|
||||
id: key,
|
||||
kind: SUFFIX_TO_KIND[suffix] || "any",
|
||||
original,
|
||||
unit,
|
||||
start: Number(value),
|
||||
@ -35,11 +53,18 @@ function App() {
|
||||
<div className="card">
|
||||
<div className="card-content">
|
||||
{vars.map((v) => {
|
||||
const { id, original, unit, start } = v;
|
||||
const { id, kind, original, unit, start } = v;
|
||||
|
||||
return (
|
||||
<div key={id} className="block">
|
||||
<Slider id={id} original={original} start={start} unit={unit} />
|
||||
<code>{id}</code>
|
||||
<Slider
|
||||
id={id}
|
||||
kind={kind}
|
||||
original={original}
|
||||
start={start}
|
||||
unit={unit}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
80
docs/_react/bulma-customizer/src/components/Picker.jsx
Normal file
80
docs/_react/bulma-customizer/src/components/Picker.jsx
Normal file
@ -0,0 +1,80 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import classNames from "classnames";
|
||||
|
||||
import cn from "./Slider.module.css";
|
||||
|
||||
const RANGES = {
|
||||
deg: [0, 360, 1],
|
||||
"%": [0, 100, 1],
|
||||
};
|
||||
|
||||
function Picker({ id, kind, start, unit }) {
|
||||
const [value, setValue] = useState(start);
|
||||
|
||||
let min = 0;
|
||||
let max = 360;
|
||||
let step = 1;
|
||||
|
||||
if (unit in RANGES) {
|
||||
[min, max, step] = RANGES[unit];
|
||||
}
|
||||
|
||||
const handleChange = (event) => {
|
||||
setValue(event.target.value);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setValue(start);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const computedValue = `${value}${unit}`;
|
||||
|
||||
if (value === start) {
|
||||
document.documentElement.style.removeProperty(`--bulma-${id}`);
|
||||
} else {
|
||||
document.documentElement.style.setProperty(
|
||||
`--bulma-${id}`,
|
||||
computedValue,
|
||||
);
|
||||
}
|
||||
}, [id, start, unit, value]);
|
||||
|
||||
const mainCN = classNames({
|
||||
[cn.main]: true,
|
||||
[cn[kind]]: kind,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={mainCN}>
|
||||
<code>{id}</code>
|
||||
|
||||
<input
|
||||
type="range"
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<code>
|
||||
{value}
|
||||
{unit}
|
||||
</code>
|
||||
<button className="button is-small" onClick={handleReset}>
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Picker.propTypes = {
|
||||
id: PropTypes.string,
|
||||
kind: PropTypes.string,
|
||||
original: PropTypes.string,
|
||||
start: PropTypes.number,
|
||||
unit: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Picker;
|
@ -1,28 +1,40 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import classNames from "classnames";
|
||||
|
||||
import cn from "./Slider.module.css";
|
||||
|
||||
const RANGES = {
|
||||
deg: [0, 360, 1],
|
||||
"%": [0, 100, 1],
|
||||
hue: [0, 360, 1],
|
||||
saturation: [0, 100, 1],
|
||||
lightness: [0, 100, 1],
|
||||
gap: [0, 100, 1],
|
||||
any: [0, 100, 1],
|
||||
};
|
||||
|
||||
function Slider({ id, start, unit }) {
|
||||
function Slider({ id, kind, start, unit }) {
|
||||
const [value, setValue] = useState(start);
|
||||
const [isMoving, setMoving] = useState(false);
|
||||
const [x, setX] = useState(0);
|
||||
const sliderRef = useRef(null);
|
||||
const handleRef = useRef(null);
|
||||
|
||||
let min = 0;
|
||||
let max = 360;
|
||||
let step = 1;
|
||||
const [min, max, step] = RANGES[kind];
|
||||
|
||||
if (unit in RANGES) {
|
||||
[min, max, step] = RANGES[unit];
|
||||
}
|
||||
|
||||
const handleChange = (event) => {
|
||||
setValue(event.target.value);
|
||||
const handleMouseDown = (event) => {
|
||||
setMoving(true);
|
||||
const slider = sliderRef.current;
|
||||
const sliderRect = slider.getBoundingClientRect();
|
||||
const target = event.clientX - sliderRect.left;
|
||||
setX(target);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setValue(start);
|
||||
const docMouseLeave = () => {
|
||||
setMoving(false);
|
||||
};
|
||||
|
||||
const docMouseUp = () => {
|
||||
setMoving(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -38,30 +50,74 @@ function Slider({ id, start, unit }) {
|
||||
}
|
||||
}, [id, start, unit, value]);
|
||||
|
||||
useEffect(() => {
|
||||
const docMouseMove = (event) => {
|
||||
if (!isMoving || !sliderRef.current || !handleRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const slider = sliderRef.current;
|
||||
const sliderRect = slider.getBoundingClientRect();
|
||||
let target = event.clientX - sliderRect.left;
|
||||
|
||||
if (target < 0) {
|
||||
target = 0;
|
||||
} else if (target > sliderRect.width) {
|
||||
target = sliderRect.width;
|
||||
}
|
||||
|
||||
setX(target);
|
||||
};
|
||||
|
||||
window.addEventListener("mousemove", docMouseMove);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("mousemove", docMouseMove);
|
||||
};
|
||||
}, [isMoving, min, max, x]);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("mouseleave", docMouseLeave);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("mouseleave", docMouseLeave);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("mouseup", docMouseUp);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("mouseup", docMouseUp);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const mainCN = classNames({
|
||||
[cn.main]: true,
|
||||
[cn.moving]: isMoving,
|
||||
});
|
||||
|
||||
const backgroundCN = classNames({
|
||||
[cn.background]: true,
|
||||
[cn[kind]]: true,
|
||||
});
|
||||
|
||||
const handleStyle = {
|
||||
transform: `translateX(${x}px)`,
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<code>{id}</code>
|
||||
<input
|
||||
type="range"
|
||||
min={min}
|
||||
max={max}
|
||||
step={step}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<code>
|
||||
{value}
|
||||
{unit}
|
||||
</code>
|
||||
<button className="button is-small" onClick={handleReset}>
|
||||
Reset
|
||||
</button>
|
||||
<div className={mainCN} ref={sliderRef} onMouseDown={handleMouseDown}>
|
||||
<div className={backgroundCN}>
|
||||
<span ref={handleRef} className={cn.handle} style={handleStyle} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Slider.propTypes = {
|
||||
id: PropTypes.string,
|
||||
kind: PropTypes.string,
|
||||
original: PropTypes.string,
|
||||
start: PropTypes.number,
|
||||
unit: PropTypes.string,
|
||||
|
@ -0,0 +1,50 @@
|
||||
.main {
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
padding: 0.375rem 0;
|
||||
box-shadow: 0 0 0 1px green;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.moving {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.handle {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
box-shadow:
|
||||
rgba(0, 0, 0, 0.15) 0 0 0 1px,
|
||||
rgba(0, 0, 0, 0.05) 0 10px 10px -5px;
|
||||
height: 1.25rem;
|
||||
width: 1.25rem;
|
||||
border-radius: 9999px;
|
||||
position: absolute;
|
||||
top: 0rem;
|
||||
cursor: grab;
|
||||
border: 0.25rem solid white;
|
||||
left: -0.625rem;
|
||||
}
|
||||
|
||||
.moving .handle,
|
||||
.handle:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.background {
|
||||
border-radius: 0.125rem;
|
||||
background-color: white;
|
||||
height: 0.5rem;
|
||||
}
|
||||
|
||||
.hue {
|
||||
background-image: linear-gradient(
|
||||
to right,
|
||||
rgb(255, 0, 0),
|
||||
rgb(255, 255, 0),
|
||||
rgb(0, 255, 0),
|
||||
rgb(0, 255, 255),
|
||||
rgb(0, 0, 255),
|
||||
rgb(255, 0, 255),
|
||||
rgb(255, 0, 0)
|
||||
);
|
||||
}
|
@ -1,7 +1,16 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
build: {
|
||||
outDir: "../../assets/javascript/bulma-customizer",
|
||||
rollupOptions: {
|
||||
output: {
|
||||
assetFileNames: "[name].css",
|
||||
entryFileNames: "[name].js",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [react()],
|
||||
})
|
||||
});
|
||||
|
1
docs/assets/javascript/bulma-customizer/index.css
Normal file
1
docs/assets/javascript/bulma-customizer/index.css
Normal file
File diff suppressed because one or more lines are too long
14
docs/assets/javascript/bulma-customizer/index.html
Normal file
14
docs/assets/javascript/bulma-customizer/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + React</title>
|
||||
<script type="module" crossorigin src="/index.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/index.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
40
docs/assets/javascript/bulma-customizer/index.js
Normal file
40
docs/assets/javascript/bulma-customizer/index.js
Normal file
File diff suppressed because one or more lines are too long
16
docs/customizer.html
Normal file
16
docs/customizer.html
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
layout: default
|
||||
theme: customizer
|
||||
route: customizer
|
||||
---
|
||||
{% include global/header.html %}
|
||||
|
||||
{%
|
||||
include docs/hero.html
|
||||
title="The Bulma Customizer"
|
||||
subtitle="Gorgeous websites built with Bulma."
|
||||
%}
|
||||
|
||||
<div id="root"></div>
|
||||
|
||||
<script src="{{ site.url }}/assets/javascript/bulma-customizer/index.js"></script>
|
@ -31,9 +31,9 @@ breadcrumb:
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<p class="title is-5">Use the <strong>HTML5 doctype</strong></p>
|
||||
{% highlight html %}
|
||||
<!doctype html>
|
||||
{% endhighlight %}
|
||||
{%- highlight html -%}
|
||||
<!DOCTYPE html>
|
||||
{%- endhighlight -%}
|
||||
</div>
|
||||
</article>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user