html-flip-book-react 0.0.0-alpha.1 → 0.0.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FlipBook.d.ts +26 -0
- package/dist/FlipBook.d.ts.map +1 -0
- package/dist/assets/html-flip-book.css +1 -0
- package/dist/flip-book.js +47 -1405
- package/dist/flip-book.js.map +1 -1
- package/dist/toolbar/FirstPageButton.d.ts +9 -0
- package/dist/toolbar/FirstPageButton.d.ts.map +1 -0
- package/dist/toolbar/FullscreenButton.d.ts +11 -0
- package/dist/toolbar/FullscreenButton.d.ts.map +1 -0
- package/dist/toolbar/LastPageButton.d.ts +9 -0
- package/dist/toolbar/LastPageButton.d.ts.map +1 -0
- package/dist/toolbar/NextButton.d.ts +9 -0
- package/dist/toolbar/NextButton.d.ts.map +1 -0
- package/dist/toolbar/PageIndicator.d.ts +9 -0
- package/dist/toolbar/PageIndicator.d.ts.map +1 -0
- package/dist/toolbar/PrevButton.d.ts +9 -0
- package/dist/toolbar/PrevButton.d.ts.map +1 -0
- package/dist/toolbar/Toolbar.d.ts +13 -0
- package/dist/toolbar/Toolbar.d.ts.map +1 -0
- package/dist/toolbar/ToolbarButton.d.ts +13 -0
- package/dist/toolbar/ToolbarButton.d.ts.map +1 -0
- package/dist/toolbar/ToolbarContext.d.ts +15 -0
- package/dist/toolbar/ToolbarContext.d.ts.map +1 -0
- package/dist/toolbar/index.d.ts +19 -0
- package/dist/toolbar/index.d.ts.map +1 -0
- package/dist/toolbar/index.js +174 -0
- package/dist/toolbar/index.js.map +1 -0
- package/package.json +45 -43
- package/dist/flip-book.d.ts +0 -14
- package/dist/flip-book.d.ts.map +0 -1
- package/example/.vscode/settings.json +0 -3
- package/example/README.md +0 -47
- package/example/assets/pages_data/en/assets/cover.jpg +0 -0
- package/example/assets/pages_data/en/assets/sql-command.png +0 -0
- package/example/assets/pages_data/en/content/000-introduction.md +0 -85
- package/example/assets/pages_data/en/content/001-databases.md +0 -39
- package/example/assets/pages_data/en/content/002-install-mysql.md +0 -162
- package/example/assets/pages_data/en/content/003-creating-tables.md +0 -304
- package/example/assets/pages_data/en/content/004-basic-syntax.md +0 -145
- package/example/assets/pages_data/en/content/005-select.md +0 -359
- package/example/assets/pages_data/en/content/006-where.md +0 -225
- package/example/assets/pages_data/en/content/007-order-and-group-by.md +0 -142
- package/example/assets/pages_data/en/content/008-insert.md +0 -86
- package/example/assets/pages_data/en/content/009-update.md +0 -92
- package/example/assets/pages_data/en/content/010-delete.md +0 -28
- package/example/assets/pages_data/en/content/011-join.md +0 -297
- package/example/assets/pages_data/en/content/012-sql-command-categories.md +0 -121
- package/example/assets/pages_data/en/content/013-sub-queries.md +0 -112
- package/example/assets/pages_data/en/content/014-unions.md +0 -124
- package/example/assets/pages_data/en/content/015-Keys-in-a-Relational Database.md +0 -51
- package/example/assets/pages_data/en/content/016-Logical-operator-keywords.md +0 -17
- package/example/assets/pages_data/en/content/017-having-clause_aggregate-functions.md +0 -184
- package/example/assets/pages_data/en/content/018-essential-mysql-functions.md +0 -190
- package/example/assets/pages_data/en/content/019-triggers-in-sql.md +0 -133
- package/example/assets/pages_data/en/content/020-TCL-commands.md +0 -154
- package/example/assets/pages_data/en/content/021-DCL-commands.md +0 -126
- package/example/assets/pages_data/en/content/100-mysqldump.md +0 -109
- package/example/assets/pages_data/en/content/101-learn-materialize.md +0 -267
- package/example/assets/pages_data/en/content/999-conclusion.md +0 -24
- package/example/assets/pages_data/he/4.txt +0 -2
- package/example/assets/pages_data/he/5.txt +0 -4
- package/example/assets/pages_data/he/6.txt +0 -4
- package/example/index.html +0 -21
- package/example/package-lock.json +0 -5324
- package/example/package.json +0 -39
- package/example/src/App.css +0 -52
- package/example/src/App.tsx +0 -25
- package/example/src/EnBook.tsx +0 -55
- package/example/src/HeBook.tsx +0 -44
- package/example/src/index.tsx +0 -12
- package/example/vite-env.d.ts +0 -1
- package/example/vite.config.js +0 -84
- package/src/FlipBook.tsx +0 -45
- package/vite.config.js +0 -66
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { jsx as n } from "react/jsx-runtime";
|
|
2
|
+
import { createContext as v, useContext as x, useState as i, useCallback as P, useEffect as k } from "react";
|
|
3
|
+
const u = ({
|
|
4
|
+
onClick: e,
|
|
5
|
+
ariaLabel: t,
|
|
6
|
+
disabled: l = !1,
|
|
7
|
+
children: r,
|
|
8
|
+
className: a = "",
|
|
9
|
+
title: o
|
|
10
|
+
}) => /* @__PURE__ */ n(
|
|
11
|
+
"button",
|
|
12
|
+
{
|
|
13
|
+
type: "button",
|
|
14
|
+
onClick: e,
|
|
15
|
+
"aria-label": t,
|
|
16
|
+
disabled: l,
|
|
17
|
+
title: o ?? t,
|
|
18
|
+
className: `flipbook-toolbar-button ${a}`.trim(),
|
|
19
|
+
children: r
|
|
20
|
+
}
|
|
21
|
+
), h = v(null);
|
|
22
|
+
function b() {
|
|
23
|
+
const e = x(h);
|
|
24
|
+
if (!e)
|
|
25
|
+
throw new Error("Toolbar components must be used within a Toolbar");
|
|
26
|
+
return e;
|
|
27
|
+
}
|
|
28
|
+
const N = ({ children: e, className: t }) => {
|
|
29
|
+
const { flipBookRef: l, isFirstPage: r } = b();
|
|
30
|
+
return /* @__PURE__ */ n(
|
|
31
|
+
u,
|
|
32
|
+
{
|
|
33
|
+
onClick: () => {
|
|
34
|
+
l.current?.jumpToPage(0);
|
|
35
|
+
},
|
|
36
|
+
ariaLabel: "First page",
|
|
37
|
+
disabled: r,
|
|
38
|
+
className: `flipbook-toolbar-first ${t ?? ""}`.trim(),
|
|
39
|
+
children: e ?? "⏮"
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
}, T = ({
|
|
43
|
+
targetRef: e,
|
|
44
|
+
enterIcon: t,
|
|
45
|
+
exitIcon: l,
|
|
46
|
+
className: r
|
|
47
|
+
}) => {
|
|
48
|
+
const [a, o] = i(!1), s = P(() => {
|
|
49
|
+
o(!!document.fullscreenElement);
|
|
50
|
+
}, []);
|
|
51
|
+
k(() => (document.addEventListener("fullscreenchange", s), () => {
|
|
52
|
+
document.removeEventListener("fullscreenchange", s);
|
|
53
|
+
}), [s]);
|
|
54
|
+
const g = async () => {
|
|
55
|
+
try {
|
|
56
|
+
a ? await document.exitFullscreen() : await (e?.current ?? document.documentElement).requestFullscreen();
|
|
57
|
+
} catch (d) {
|
|
58
|
+
console.warn("Fullscreen request failed:", d);
|
|
59
|
+
}
|
|
60
|
+
}, f = a ? "Exit fullscreen" : "Enter fullscreen", p = a ? l ?? "⛶" : t ?? "⛶";
|
|
61
|
+
return /* @__PURE__ */ n(
|
|
62
|
+
u,
|
|
63
|
+
{
|
|
64
|
+
onClick: g,
|
|
65
|
+
ariaLabel: f,
|
|
66
|
+
className: `flipbook-toolbar-fullscreen ${a ? "flipbook-toolbar-fullscreen--active" : ""} ${r ?? ""}`.trim(),
|
|
67
|
+
children: p
|
|
68
|
+
}
|
|
69
|
+
);
|
|
70
|
+
}, $ = ({ children: e, className: t }) => {
|
|
71
|
+
const { flipBookRef: l, isLastPage: r, totalPages: a } = b();
|
|
72
|
+
return /* @__PURE__ */ n(
|
|
73
|
+
u,
|
|
74
|
+
{
|
|
75
|
+
onClick: () => {
|
|
76
|
+
l.current?.jumpToPage(a - 1);
|
|
77
|
+
},
|
|
78
|
+
ariaLabel: "Last page",
|
|
79
|
+
disabled: r,
|
|
80
|
+
className: `flipbook-toolbar-last ${t ?? ""}`.trim(),
|
|
81
|
+
children: e ?? "⏭"
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}, B = ({ children: e, className: t }) => {
|
|
85
|
+
const { flipBookRef: l, isLastPage: r, direction: a } = b();
|
|
86
|
+
return /* @__PURE__ */ n(
|
|
87
|
+
u,
|
|
88
|
+
{
|
|
89
|
+
onClick: () => {
|
|
90
|
+
l.current?.flipNext();
|
|
91
|
+
},
|
|
92
|
+
ariaLabel: a === "rtl" ? "Previous page" : "Next page",
|
|
93
|
+
disabled: r,
|
|
94
|
+
className: `flipbook-toolbar-next ${t ?? ""}`.trim(),
|
|
95
|
+
children: e ?? "›"
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
}, E = ({
|
|
99
|
+
format: e = "{current} / {total}",
|
|
100
|
+
className: t
|
|
101
|
+
}) => {
|
|
102
|
+
const { currentPage: l, totalPages: r } = b(), a = l + 1, o = e.replace("{current}", a.toString()).replace("{total}", r.toString());
|
|
103
|
+
return /* @__PURE__ */ n(
|
|
104
|
+
"span",
|
|
105
|
+
{
|
|
106
|
+
className: `flipbook-toolbar-indicator ${t ?? ""}`.trim(),
|
|
107
|
+
"aria-live": "polite",
|
|
108
|
+
"aria-atomic": "true",
|
|
109
|
+
children: o
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
}, I = ({ children: e, className: t }) => {
|
|
113
|
+
const { flipBookRef: l, isFirstPage: r, direction: a } = b();
|
|
114
|
+
return /* @__PURE__ */ n(
|
|
115
|
+
u,
|
|
116
|
+
{
|
|
117
|
+
onClick: () => {
|
|
118
|
+
l.current?.flipPrev();
|
|
119
|
+
},
|
|
120
|
+
ariaLabel: a === "rtl" ? "Next page" : "Previous page",
|
|
121
|
+
disabled: r,
|
|
122
|
+
className: `flipbook-toolbar-prev ${t ?? ""}`.trim(),
|
|
123
|
+
children: e ?? "‹"
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
}, w = ({
|
|
127
|
+
flipBookRef: e,
|
|
128
|
+
direction: t = "ltr",
|
|
129
|
+
className: l = "",
|
|
130
|
+
children: r
|
|
131
|
+
}) => {
|
|
132
|
+
const [a, o] = i(0), [s, g] = i(0), [f, p] = i(!0), [d, C] = i(!1), m = P(() => {
|
|
133
|
+
const c = e.current;
|
|
134
|
+
c && (o(c.getCurrentPageIndex()), g(c.getTotalPages()), p(c.isFirstPage()), C(c.isLastPage()));
|
|
135
|
+
}, [e]);
|
|
136
|
+
return k(() => {
|
|
137
|
+
m();
|
|
138
|
+
const c = setInterval(m, 100);
|
|
139
|
+
return () => clearInterval(c);
|
|
140
|
+
}, [m]), /* @__PURE__ */ n(
|
|
141
|
+
h.Provider,
|
|
142
|
+
{
|
|
143
|
+
value: {
|
|
144
|
+
flipBookRef: e,
|
|
145
|
+
direction: t,
|
|
146
|
+
currentPage: a,
|
|
147
|
+
totalPages: s,
|
|
148
|
+
isFirstPage: f,
|
|
149
|
+
isLastPage: d
|
|
150
|
+
},
|
|
151
|
+
children: /* @__PURE__ */ n(
|
|
152
|
+
"div",
|
|
153
|
+
{
|
|
154
|
+
className: `flipbook-toolbar ${t === "rtl" ? "flipbook-toolbar--rtl" : ""} ${l}`.trim(),
|
|
155
|
+
role: "toolbar",
|
|
156
|
+
"aria-label": "FlipBook navigation",
|
|
157
|
+
children: r
|
|
158
|
+
}
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
};
|
|
163
|
+
export {
|
|
164
|
+
N as FirstPageButton,
|
|
165
|
+
T as FullscreenButton,
|
|
166
|
+
$ as LastPageButton,
|
|
167
|
+
B as NextButton,
|
|
168
|
+
E as PageIndicator,
|
|
169
|
+
I as PrevButton,
|
|
170
|
+
w as Toolbar,
|
|
171
|
+
u as ToolbarButton,
|
|
172
|
+
b as useToolbar
|
|
173
|
+
};
|
|
174
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/toolbar/ToolbarButton.tsx","../../src/toolbar/ToolbarContext.tsx","../../src/toolbar/FirstPageButton.tsx","../../src/toolbar/FullscreenButton.tsx","../../src/toolbar/LastPageButton.tsx","../../src/toolbar/NextButton.tsx","../../src/toolbar/PageIndicator.tsx","../../src/toolbar/PrevButton.tsx","../../src/toolbar/Toolbar.tsx"],"sourcesContent":["import type React from \"react\";\n\ninterface ToolbarButtonProps {\n\t/** Click handler */\n\tonClick: () => void;\n\t/** Accessible label for the button */\n\tariaLabel: string;\n\t/** Whether the button is disabled */\n\tdisabled?: boolean;\n\t/** Button content (icon or text) */\n\tchildren: React.ReactNode;\n\t/** Additional CSS class name */\n\tclassName?: string;\n\t/** Title tooltip */\n\ttitle?: string;\n}\n\n/**\n * Base button component for toolbar actions.\n */\nconst ToolbarButton: React.FC<ToolbarButtonProps> = ({\n\tonClick,\n\tariaLabel,\n\tdisabled = false,\n\tchildren,\n\tclassName = \"\",\n\ttitle,\n}) => {\n\treturn (\n\t\t<button\n\t\t\ttype=\"button\"\n\t\t\tonClick={onClick}\n\t\t\taria-label={ariaLabel}\n\t\t\tdisabled={disabled}\n\t\t\ttitle={title ?? ariaLabel}\n\t\t\tclassName={`flipbook-toolbar-button ${className}`.trim()}\n\t\t>\n\t\t\t{children}\n\t\t</button>\n\t);\n};\n\nexport { ToolbarButton };\nexport type { ToolbarButtonProps };\n","import type React from \"react\";\nimport { createContext, useContext } from \"react\";\nimport type { FlipBookHandle } from \"../FlipBook\";\n\ninterface ToolbarContextValue {\n\tflipBookRef: React.RefObject<FlipBookHandle | null>;\n\tdirection: \"ltr\" | \"rtl\";\n\tcurrentPage: number;\n\ttotalPages: number;\n\tisFirstPage: boolean;\n\tisLastPage: boolean;\n}\n\nconst ToolbarContext = createContext<ToolbarContextValue | null>(null);\n\nexport function useToolbar(): ToolbarContextValue {\n\tconst context = useContext(ToolbarContext);\n\tif (!context) {\n\t\tthrow new Error(\"Toolbar components must be used within a Toolbar\");\n\t}\n\treturn context;\n}\n\nexport { ToolbarContext };\nexport type { ToolbarContextValue };\n","import type React from \"react\";\nimport { ToolbarButton } from \"./ToolbarButton\";\nimport { useToolbar } from \"./ToolbarContext\";\n\ninterface FirstPageButtonProps {\n\t/** Custom content (icon or text). Defaults to \"⏮\" */\n\tchildren?: React.ReactNode;\n\t/** Additional CSS class name */\n\tclassName?: string;\n}\n\n/**\n * Button to navigate to the first page.\n */\nconst FirstPageButton: React.FC<FirstPageButtonProps> = ({ children, className }) => {\n\tconst { flipBookRef, isFirstPage } = useToolbar();\n\n\tconst handleClick = () => {\n\t\tflipBookRef.current?.jumpToPage(0);\n\t};\n\n\treturn (\n\t\t<ToolbarButton\n\t\t\tonClick={handleClick}\n\t\t\tariaLabel=\"First page\"\n\t\t\tdisabled={isFirstPage}\n\t\t\tclassName={`flipbook-toolbar-first ${className ?? \"\"}`.trim()}\n\t\t>\n\t\t\t{children ?? \"⏮\"}\n\t\t</ToolbarButton>\n\t);\n};\n\nexport { FirstPageButton };\nexport type { FirstPageButtonProps };\n","import type React from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport { ToolbarButton } from \"./ToolbarButton\";\n\ninterface FullscreenButtonProps {\n\t/** Target element to make fullscreen. If not provided, uses document.documentElement */\n\ttargetRef?: React.RefObject<HTMLElement | null>;\n\t/** Custom content for enter fullscreen. Defaults to \"⛶\" */\n\tenterIcon?: React.ReactNode;\n\t/** Custom content for exit fullscreen. Defaults to \"⛶\" */\n\texitIcon?: React.ReactNode;\n\t/** Additional CSS class name */\n\tclassName?: string;\n}\n\n/**\n * Button to toggle fullscreen mode.\n */\nconst FullscreenButton: React.FC<FullscreenButtonProps> = ({\n\ttargetRef,\n\tenterIcon,\n\texitIcon,\n\tclassName,\n}) => {\n\tconst [isFullscreen, setIsFullscreen] = useState(false);\n\n\t// Check fullscreen state\n\tconst updateFullscreenState = useCallback(() => {\n\t\tsetIsFullscreen(!!document.fullscreenElement);\n\t}, []);\n\n\tuseEffect(() => {\n\t\tdocument.addEventListener(\"fullscreenchange\", updateFullscreenState);\n\t\treturn () => {\n\t\t\tdocument.removeEventListener(\"fullscreenchange\", updateFullscreenState);\n\t\t};\n\t}, [updateFullscreenState]);\n\n\tconst handleClick = async () => {\n\t\ttry {\n\t\t\tif (isFullscreen) {\n\t\t\t\tawait document.exitFullscreen();\n\t\t\t} else {\n\t\t\t\tconst target = targetRef?.current ?? document.documentElement;\n\t\t\t\tawait target.requestFullscreen();\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.warn(\"Fullscreen request failed:\", error);\n\t\t}\n\t};\n\n\tconst label = isFullscreen ? \"Exit fullscreen\" : \"Enter fullscreen\";\n\tconst icon = isFullscreen ? (exitIcon ?? \"⛶\") : (enterIcon ?? \"⛶\");\n\n\treturn (\n\t\t<ToolbarButton\n\t\t\tonClick={handleClick}\n\t\t\tariaLabel={label}\n\t\t\tclassName={`flipbook-toolbar-fullscreen ${isFullscreen ? \"flipbook-toolbar-fullscreen--active\" : \"\"} ${className ?? \"\"}`.trim()}\n\t\t>\n\t\t\t{icon}\n\t\t</ToolbarButton>\n\t);\n};\n\nexport { FullscreenButton };\nexport type { FullscreenButtonProps };\n","import type React from \"react\";\nimport { ToolbarButton } from \"./ToolbarButton\";\nimport { useToolbar } from \"./ToolbarContext\";\n\ninterface LastPageButtonProps {\n\t/** Custom content (icon or text). Defaults to \"⏭\" */\n\tchildren?: React.ReactNode;\n\t/** Additional CSS class name */\n\tclassName?: string;\n}\n\n/**\n * Button to navigate to the last page.\n */\nconst LastPageButton: React.FC<LastPageButtonProps> = ({ children, className }) => {\n\tconst { flipBookRef, isLastPage, totalPages } = useToolbar();\n\n\tconst handleClick = () => {\n\t\tflipBookRef.current?.jumpToPage(totalPages - 1);\n\t};\n\n\treturn (\n\t\t<ToolbarButton\n\t\t\tonClick={handleClick}\n\t\t\tariaLabel=\"Last page\"\n\t\t\tdisabled={isLastPage}\n\t\t\tclassName={`flipbook-toolbar-last ${className ?? \"\"}`.trim()}\n\t\t>\n\t\t\t{children ?? \"⏭\"}\n\t\t</ToolbarButton>\n\t);\n};\n\nexport { LastPageButton };\nexport type { LastPageButtonProps };\n","import type React from \"react\";\nimport { ToolbarButton } from \"./ToolbarButton\";\nimport { useToolbar } from \"./ToolbarContext\";\n\ninterface NextButtonProps {\n\t/** Custom content (icon or text). Defaults to \"›\" */\n\tchildren?: React.ReactNode;\n\t/** Additional CSS class name */\n\tclassName?: string;\n}\n\n/**\n * Button to navigate to the next page.\n */\nconst NextButton: React.FC<NextButtonProps> = ({ children, className }) => {\n\tconst { flipBookRef, isLastPage, direction } = useToolbar();\n\n\tconst handleClick = () => {\n\t\tflipBookRef.current?.flipNext();\n\t};\n\n\t// In RTL, the visual \"next\" is actually previous in reading order\n\tconst label = direction === \"rtl\" ? \"Previous page\" : \"Next page\";\n\n\treturn (\n\t\t<ToolbarButton\n\t\t\tonClick={handleClick}\n\t\t\tariaLabel={label}\n\t\t\tdisabled={isLastPage}\n\t\t\tclassName={`flipbook-toolbar-next ${className ?? \"\"}`.trim()}\n\t\t>\n\t\t\t{children ?? \"›\"}\n\t\t</ToolbarButton>\n\t);\n};\n\nexport { NextButton };\nexport type { NextButtonProps };\n","import type React from \"react\";\nimport { useToolbar } from \"./ToolbarContext\";\n\ninterface PageIndicatorProps {\n\t/** Format string with {current} and {total} placeholders. Defaults to \"{current} / {total}\" */\n\tformat?: string;\n\t/** Additional CSS class name */\n\tclassName?: string;\n}\n\n/**\n * Displays the current page position (e.g., \"3 / 10\").\n */\nconst PageIndicator: React.FC<PageIndicatorProps> = ({\n\tformat = \"{current} / {total}\",\n\tclassName,\n}) => {\n\tconst { currentPage, totalPages } = useToolbar();\n\n\t// Display 1-based page numbers for users\n\tconst displayPage = currentPage + 1;\n\n\tconst text = format\n\t\t.replace(\"{current}\", displayPage.toString())\n\t\t.replace(\"{total}\", totalPages.toString());\n\n\treturn (\n\t\t<span\n\t\t\tclassName={`flipbook-toolbar-indicator ${className ?? \"\"}`.trim()}\n\t\t\taria-live=\"polite\"\n\t\t\taria-atomic=\"true\"\n\t\t>\n\t\t\t{text}\n\t\t</span>\n\t);\n};\n\nexport { PageIndicator };\nexport type { PageIndicatorProps };\n","import type React from \"react\";\nimport { ToolbarButton } from \"./ToolbarButton\";\nimport { useToolbar } from \"./ToolbarContext\";\n\ninterface PrevButtonProps {\n\t/** Custom content (icon or text). Defaults to \"‹\" */\n\tchildren?: React.ReactNode;\n\t/** Additional CSS class name */\n\tclassName?: string;\n}\n\n/**\n * Button to navigate to the previous page.\n */\nconst PrevButton: React.FC<PrevButtonProps> = ({ children, className }) => {\n\tconst { flipBookRef, isFirstPage, direction } = useToolbar();\n\n\tconst handleClick = () => {\n\t\tflipBookRef.current?.flipPrev();\n\t};\n\n\t// In RTL, the visual \"previous\" is actually next in reading order\n\tconst label = direction === \"rtl\" ? \"Next page\" : \"Previous page\";\n\n\treturn (\n\t\t<ToolbarButton\n\t\t\tonClick={handleClick}\n\t\t\tariaLabel={label}\n\t\t\tdisabled={isFirstPage}\n\t\t\tclassName={`flipbook-toolbar-prev ${className ?? \"\"}`.trim()}\n\t\t>\n\t\t\t{children ?? \"‹\"}\n\t\t</ToolbarButton>\n\t);\n};\n\nexport { PrevButton };\nexport type { PrevButtonProps };\n","import type React from \"react\";\nimport { useCallback, useEffect, useState } from \"react\";\nimport type { FlipBookHandle } from \"../FlipBook\";\nimport { ToolbarContext } from \"./ToolbarContext\";\nimport \"./Toolbar.css\";\n\ninterface ToolbarProps {\n\t/** Ref to the FlipBook component for programmatic control */\n\tflipBookRef: React.RefObject<FlipBookHandle | null>;\n\t/** Text direction for button layout. Defaults to \"ltr\" */\n\tdirection?: \"ltr\" | \"rtl\";\n\t/** Additional CSS class name */\n\tclassName?: string;\n\t/** Toolbar children (buttons, indicators, etc.) */\n\tchildren: React.ReactNode;\n}\n\n/**\n * Container component for FlipBook toolbar controls.\n * Provides context to child components for accessing FlipBook methods.\n */\nconst Toolbar: React.FC<ToolbarProps> = ({\n\tflipBookRef,\n\tdirection = \"ltr\",\n\tclassName = \"\",\n\tchildren,\n}) => {\n\tconst [currentPage, setCurrentPage] = useState(0);\n\tconst [totalPages, setTotalPages] = useState(0);\n\tconst [isFirstPage, setIsFirstPage] = useState(true);\n\tconst [isLastPage, setIsLastPage] = useState(false);\n\n\t// Update state from FlipBook ref\n\tconst updateState = useCallback(() => {\n\t\tconst fb = flipBookRef.current;\n\t\tif (fb) {\n\t\t\tsetCurrentPage(fb.getCurrentPageIndex());\n\t\t\tsetTotalPages(fb.getTotalPages());\n\t\t\tsetIsFirstPage(fb.isFirstPage());\n\t\t\tsetIsLastPage(fb.isLastPage());\n\t\t}\n\t}, [flipBookRef]);\n\n\t// Initial state update and periodic polling\n\t// TODO: Replace with event-based updates when FlipBook emits page change events\n\tuseEffect(() => {\n\t\tupdateState();\n\t\tconst interval = setInterval(updateState, 100);\n\t\treturn () => clearInterval(interval);\n\t}, [updateState]);\n\n\treturn (\n\t\t<ToolbarContext.Provider\n\t\t\tvalue={{\n\t\t\t\tflipBookRef,\n\t\t\t\tdirection,\n\t\t\t\tcurrentPage,\n\t\t\t\ttotalPages,\n\t\t\t\tisFirstPage,\n\t\t\t\tisLastPage,\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={`flipbook-toolbar ${direction === \"rtl\" ? \"flipbook-toolbar--rtl\" : \"\"} ${className}`.trim()}\n\t\t\t\trole=\"toolbar\"\n\t\t\t\taria-label=\"FlipBook navigation\"\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</ToolbarContext.Provider>\n\t);\n};\n\nexport { Toolbar };\nexport type { ToolbarProps };\n"],"names":["ToolbarButton","onClick","ariaLabel","disabled","children","className","title","jsx","ToolbarContext","createContext","useToolbar","context","useContext","FirstPageButton","flipBookRef","isFirstPage","FullscreenButton","targetRef","enterIcon","exitIcon","isFullscreen","setIsFullscreen","useState","updateFullscreenState","useCallback","useEffect","handleClick","error","label","icon","LastPageButton","isLastPage","totalPages","NextButton","direction","PageIndicator","format","currentPage","displayPage","text","PrevButton","Toolbar","setCurrentPage","setTotalPages","setIsFirstPage","setIsLastPage","updateState","fb","interval"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,45 +1,47 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
2
|
+
"name": "html-flip-book-react",
|
|
3
|
+
"description": "Flip Book React Component",
|
|
4
|
+
"version": "0.0.0-alpha.9",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "DoradSoft",
|
|
7
|
+
"main": "./dist/flip-book.js",
|
|
8
|
+
"types": "./dist/flip-book.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/flip-book.js",
|
|
12
|
+
"types": "./dist/flip-book.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"./toolbar": {
|
|
15
|
+
"import": "./dist/toolbar/index.js",
|
|
16
|
+
"types": "./dist/toolbar/index.d.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"homepage": "https://github.com/doradsoft/html-flip-book",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/doradsoft/html-flip-book.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/doradsoft/html-flip-book/issues"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"book",
|
|
32
|
+
"flip-book",
|
|
33
|
+
"react"
|
|
34
|
+
],
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"react": "^18.0.0",
|
|
38
|
+
"react-dom": "^18.0.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"html-flip-book-vanilla": "0.0.0-alpha.9"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/react": "^19.2.8",
|
|
45
|
+
"@types/react-dom": "^19.2.3"
|
|
46
|
+
}
|
|
45
47
|
}
|
package/dist/flip-book.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { default as React } from 'react';
|
|
2
|
-
import { PageSemantics } from 'html-flip-book-base';
|
|
3
|
-
|
|
4
|
-
interface FlipBookWrapperProps {
|
|
5
|
-
pages: React.ReactNode[];
|
|
6
|
-
className: string;
|
|
7
|
-
pageSemantics?: PageSemantics;
|
|
8
|
-
debug?: boolean;
|
|
9
|
-
direction?: 'rtl' | 'ltr';
|
|
10
|
-
}
|
|
11
|
-
declare const FlipBookReact: React.FC<FlipBookWrapperProps>;
|
|
12
|
-
export { FlipBookReact as FlipBook };
|
|
13
|
-
export type { PageSemantics };
|
|
14
|
-
//# sourceMappingURL=FlipBook.d.ts.map
|
package/dist/flip-book.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FlipBook.d.ts","sourceRoot":"","sources":["../src/FlipBook.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAA;AAChD,OAAO,EAA4B,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAE7E,UAAU,oBAAoB;IAC5B,KAAK,EAAE,KAAK,CAAC,SAAS,EAAE,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;CAE1B;AAED,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA6BjD,CAAA;AAED,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,CAAA;AACpC,YAAY,EAAE,aAAa,EAAE,CAAA"}
|
package/example/README.md
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# scaffold-react-esm-vite
|
|
2
|
-
|
|
3
|
-
Scaffold for React project implementing ESM by using Vite build tool.
|
|
4
|
-
|
|
5
|
-
## Description
|
|
6
|
-
|
|
7
|
-
This is a base project for creating React applications with ECMAScript Modules (ESM). It's built using Vite and a variety of modern tools and packages.
|
|
8
|
-
|
|
9
|
-
## Installation
|
|
10
|
-
|
|
11
|
-
First, clone the project. Then, use the package manager [npm](https://www.npmjs.com/) to install all dependencies for the project.
|
|
12
|
-
|
|
13
|
-
## Getting started
|
|
14
|
-
|
|
15
|
-
To start the project, you will be using NPM scripts.
|
|
16
|
-
Start the project in development mode:
|
|
17
|
-
|
|
18
|
-
```shell
|
|
19
|
-
npm run dev
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Building the Project
|
|
23
|
-
|
|
24
|
-
To create a build of the project, use the following NPM script:
|
|
25
|
-
|
|
26
|
-
```shell
|
|
27
|
-
# Development mode
|
|
28
|
-
npm run build
|
|
29
|
-
# Production mode
|
|
30
|
-
npm run build -- --mode production
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Running Tests
|
|
34
|
-
|
|
35
|
-
The project uses vitest for testing. Run the following NPM script to execute the tests:
|
|
36
|
-
|
|
37
|
-
```shell
|
|
38
|
-
npm run test
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Author
|
|
42
|
-
|
|
43
|
-
Joan Lloret <juallom@gmail.com>
|
|
44
|
-
|
|
45
|
-
## License
|
|
46
|
-
|
|
47
|
-
This project is licenced under the ISC License.
|
|
Binary file
|
|
Binary file
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# About the book
|
|
2
|
-
|
|
3
|
-
* **This version was published on October 13 2021**
|
|
4
|
-
|
|
5
|
-
This is an open-source introduction to SQL guide that will help you learn the basics of SQL and start using relational databases for your SysOps, DevOps, and Dev projects. No matter if you are a DevOps/SysOps engineer, developer, or just a Linux enthusiast, you will most likely have to use SQL at some point in your career.
|
|
6
|
-
|
|
7
|
-
The guide is suitable for anyone working as a developer, system administrator, or a DevOps engineer and wants to learn the basics of SQL.
|
|
8
|
-
|
|
9
|
-
## About the author
|
|
10
|
-
|
|
11
|
-
My name is Bobby Iliev, and I have been working as a Linux DevOps Engineer since 2014. I am an avid Linux lover and supporter of the open-source movement philosophy. I am always doing that which I cannot do in order that I may learn how to do it, and I believe in sharing knowledge.
|
|
12
|
-
|
|
13
|
-
I think it's essential always to keep professional and surround yourself with good people, work hard, and be nice to everyone. You have to perform at a consistently higher level than others. That's the mark of a true professional.
|
|
14
|
-
|
|
15
|
-
For more information, please visit my blog at [https://bobbyiliev.com](https://bobbyiliev.com), follow me on Twitter [@bobbyiliev_](https://twitter.com/bobbyiliev_) and [YouTube](https://www.youtube.com/channel/UCQWmdHTeAO0UvaNqve9udRw).
|
|
16
|
-
|
|
17
|
-
## Sponsors
|
|
18
|
-
|
|
19
|
-
This book is made possible thanks to these fantastic companies!
|
|
20
|
-
|
|
21
|
-
### Materialize
|
|
22
|
-
|
|
23
|
-
The Streaming Database for Real-time Analytics.
|
|
24
|
-
|
|
25
|
-
[Materialize](https://materialize.com/) is a reactive database that delivers incremental view updates. Materialize helps developers easily build with streaming data using standard SQL.
|
|
26
|
-
|
|
27
|
-
### DigitalOcean
|
|
28
|
-
|
|
29
|
-
DigitalOcean is a cloud services platform delivering the simplicity developers love and businesses trust to run production applications at scale.
|
|
30
|
-
|
|
31
|
-
It provides highly available, secure, and scalable compute, storage, and networking solutions that help developers build great software faster.
|
|
32
|
-
|
|
33
|
-
Founded in 2012 with offices in New York and Cambridge, MA, DigitalOcean offers transparent and affordable pricing, an elegant user interface, and one of the largest libraries of open source resources available.
|
|
34
|
-
|
|
35
|
-
For more information, please visit [https://www.digitalocean.com](https://www.digitalocean.com) or follow [@digitalocean](https://twitter.com/digitalocean) on Twitter.
|
|
36
|
-
|
|
37
|
-
If you are new to DigitalOcean, you can get a free $100 credit and spin up your own servers via this referral link here:
|
|
38
|
-
|
|
39
|
-
[Free $100 Credit For DigitalOcean](https://m.do.co/c/2a9bba940f39)
|
|
40
|
-
|
|
41
|
-
### DevDojo
|
|
42
|
-
|
|
43
|
-
The DevDojo is a resource to learn all things web development and web design. Learn on your lunch break or wake up and enjoy a cup of coffee with us to learn something new.
|
|
44
|
-
|
|
45
|
-
Join this developer community, and we can all learn together, build together, and grow together.
|
|
46
|
-
|
|
47
|
-
[Join DevDojo](https://devdojo.com?ref=bobbyiliev)
|
|
48
|
-
|
|
49
|
-
For more information, please visit [https://www.devdojo.com](https://www.devdojo.com?ref=bobbyiliev) or follow [@thedevdojo](https://twitter.com/thedevdojo) on Twitter.
|
|
50
|
-
|
|
51
|
-
## Ebook PDF Generation Tool
|
|
52
|
-
|
|
53
|
-
This ebook was generated by [Ibis](https://github.com/themsaid/ibis/) developed by [Mohamed Said](https://github.com/themsaid).
|
|
54
|
-
|
|
55
|
-
Ibis is a PHP tool that helps you write eBooks in markdown.
|
|
56
|
-
|
|
57
|
-
## Book Cover
|
|
58
|
-
|
|
59
|
-
The cover for this ebook was created with [Canva.com](https://www.canva.com/join/determined-cork-learn).
|
|
60
|
-
|
|
61
|
-
If you ever need to create a graphic, poster, invitation, logo, presentation – or anything that looks good — give Canva a go.
|
|
62
|
-
|
|
63
|
-
## License
|
|
64
|
-
|
|
65
|
-
MIT License
|
|
66
|
-
|
|
67
|
-
Copyright (c) 2020 Bobby Iliev
|
|
68
|
-
|
|
69
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
70
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
71
|
-
in the Software without restriction, including without limitation the rights
|
|
72
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
73
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
74
|
-
furnished to do so, subject to the following conditions:
|
|
75
|
-
|
|
76
|
-
The above copyright notice and this permission notice shall be included in all
|
|
77
|
-
copies or substantial portions of the Software.
|
|
78
|
-
|
|
79
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
80
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
81
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
82
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
83
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
84
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
85
|
-
SOFTWARE.
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# Databases
|
|
2
|
-
|
|
3
|
-
Before we dive deep into SQL, let's quickly define what a database is.
|
|
4
|
-
|
|
5
|
-
The definition of databases from Wikipedia is:
|
|
6
|
-
|
|
7
|
-
> A database is an organized collection of data, generally stored and accessed electronically from a computer system.
|
|
8
|
-
|
|
9
|
-
In other words, a database is a collection of data stored and structured in different database tables.
|
|
10
|
-
|
|
11
|
-
## Tables and columns
|
|
12
|
-
|
|
13
|
-
You've most likely worked with spreadsheet systems like Excel or Google Sheets. At the very basic, database tables are quite similar to spreadsheets.
|
|
14
|
-
|
|
15
|
-
Each table has different **columns** which could contain different types of data.
|
|
16
|
-
|
|
17
|
-
For example, if you have a todo list app, you would have a database, and in your database, you would have different tables storing different information like:
|
|
18
|
-
|
|
19
|
-
* Users - In the users table, you would have some data for your users like: `username`, `name`, and `active`, for example.
|
|
20
|
-
* Tasks - The tasks table would store all of the tasks that you are planning to do. The columns of the tasks table would be for example, `task_name`, `status`, `due_date` and `priority`.
|
|
21
|
-
|
|
22
|
-
The Users table will look like this:
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
+----+----------+---------------+--------+
|
|
26
|
-
| id | username | name | active |
|
|
27
|
-
+----+----------+---------------+--------+
|
|
28
|
-
| 1 | bobby | Bobby Iliev | true |
|
|
29
|
-
| 2 | grisi | Greisi I. | true |
|
|
30
|
-
| 3 | devdojo | Dev Dojo | false |
|
|
31
|
-
+----+----------+---------------+--------+
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Rundown of the table structure:
|
|
35
|
-
* We have 4 columns: `id`, `username`, `name` and `active`.
|
|
36
|
-
* We also have 3 entries/users.
|
|
37
|
-
* The `id` column is a unique identifier of each user and is auto-incremented.
|
|
38
|
-
|
|
39
|
-
In the next chapter, we will learn how to install MySQL and create our first database.
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
# MySQL
|
|
2
|
-
|
|
3
|
-
Now that you know what a database, table, and column are, the next thing that you would need to do is install a database service where you would be running your SQL queries on.
|
|
4
|
-
|
|
5
|
-
We will be using MySQL as it is free, open-source, and very widely used.
|
|
6
|
-
|
|
7
|
-
## Installing MySQL
|
|
8
|
-
|
|
9
|
-
Depending on your operating system, to install MySQL run the following commands.
|
|
10
|
-
|
|
11
|
-
### Install MySQL on Ubuntu
|
|
12
|
-
|
|
13
|
-
To install MySQL on a Linux or Ubuntu machine, run the following commands:
|
|
14
|
-
|
|
15
|
-
* First update your `apt` repository:
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
sudo apt update -y
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
* Then install MySQL:
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
sudo apt install mysql-server mysql-client
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
We are installing two packages, one is the actual MySQL server, and the other is the MySQL client, which would allow us to connect to the MySQL server and run our queries.
|
|
28
|
-
|
|
29
|
-
To check if MySQL is running, run the following command:
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
sudo systemctl status mysql.service
|
|
33
|
-
```
|
|
34
|
-
To secure your MySQL server, you could run the following command:
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
sudo mysql_secure_installation
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Then follow the prompt and choose a secure password and save it in a secure place like a password manager.
|
|
41
|
-
|
|
42
|
-
With that, you would have MySQL installed on your Ubuntu server. The above should also work just fine on Debian.
|
|
43
|
-
|
|
44
|
-
### Install MySQL on Mac
|
|
45
|
-
|
|
46
|
-
I would recommend installing MySQL using [Homebrew]():
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
brew install mysql
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
After that, start MySQL:
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
brew services start mysql
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
And finally, secure it:
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
mysql_secure_installation
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
In case that you ever need to stop the MySQL service, you could do so with the following command:
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
brew services stop mysql
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Install MySQL on Windows
|
|
71
|
-
|
|
72
|
-
To install MySQL on Windows, I would recommend following the steps from the official documentation here:
|
|
73
|
-
|
|
74
|
-
[https://dev.mysql.com/doc/refman/8.0/en/windows-installation.html](https://dev.mysql.com/doc/refman/8.0/en/windows-installation.html)
|
|
75
|
-
|
|
76
|
-
## Accessing MySQL via CLI
|
|
77
|
-
|
|
78
|
-
To access MySQL run the `mysql` command followed by your user:
|
|
79
|
-
|
|
80
|
-
```
|
|
81
|
-
mysql -u root -p
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## Creating a database
|
|
85
|
-
|
|
86
|
-
After that, switch to the `demo` database that we created in the previous chapter:
|
|
87
|
-
|
|
88
|
-
```sql
|
|
89
|
-
USE demo;
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
To exit the just type the following:
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
exit;
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Configuring `.my.cnf`
|
|
99
|
-
|
|
100
|
-
By configuring the `~/.my.cnf` file in your user's home directory, MySQL would allow you to log in without prompting you for a password.
|
|
101
|
-
|
|
102
|
-
To make that change, what you need to do is first create a `.my.cnf` file in your user's home directory:
|
|
103
|
-
|
|
104
|
-
```
|
|
105
|
-
touch ~/.my.cnf
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
After that, set secure permissions so that other regular users could not read the file:
|
|
109
|
-
|
|
110
|
-
```
|
|
111
|
-
chmod 600 ~/.my.cnf
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Then using your favourite text editor, open the file:
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
nano ~/.my.cnf
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
And add the following configuration:
|
|
121
|
-
|
|
122
|
-
```
|
|
123
|
-
[client]
|
|
124
|
-
user=YOUR_MYSQL_USERNAME
|
|
125
|
-
password=YOUR_MYSQL_PASSWORD
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Make sure to update your MySQL credentials accordingly, then save the file and exit.
|
|
129
|
-
|
|
130
|
-
After that, if you run just `mysql`, you will be authenticated directly with the credentials that you've specified in the `~/.my.cnf` file without being prompted for a password.
|
|
131
|
-
|
|
132
|
-
## The mysqladmin command
|
|
133
|
-
|
|
134
|
-
As a quick test, you could check all of your open SQL connections by running the following command:
|
|
135
|
-
|
|
136
|
-
```
|
|
137
|
-
mysqladmin proc
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
The `mysqladmin` tool would also use the client details from the `~/.my.cnf` file, and it would list your current MySQL process list.
|
|
141
|
-
|
|
142
|
-
Another cool thing that you could try doing is combining this with the `watch` command and kind of monitor your MySQL connections in almost real-time:
|
|
143
|
-
|
|
144
|
-
```
|
|
145
|
-
watch -n1 mysqladmin proc
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
To stop the `watch` command, just hit `CTRL+C`
|
|
149
|
-
|
|
150
|
-
## GUI clients
|
|
151
|
-
|
|
152
|
-
If you prefer using GUI clients, you could take a look a the following ones and install them locally on your laptop:
|
|
153
|
-
|
|
154
|
-
* [MySQL Workbench](https://www.mysql.com/products/workbench/)
|
|
155
|
-
* [Sequel Pro](https://www.sequelpro.com/)
|
|
156
|
-
* [TablePlus](https://tableplus.com/)
|
|
157
|
-
|
|
158
|
-
This will allow you to connect to your database via a graphical interface rather than the `mysql` command-line tool.
|
|
159
|
-
|
|
160
|
-
If you want to have a production-ready MySQL database, I would recommend giving DigitalOcean a try:
|
|
161
|
-
|
|
162
|
-
[Worry-free managed database hosting](https://www.digitalocean.com/products/managed-databases/)
|