Compare commits
2 Commits
c73c99bf48
...
3f4440ec2f
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f4440ec2f | |||
| e7969c8050 |
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -224,7 +224,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bard"
|
name = "bard"
|
||||||
version = "0.0.23"
|
version = "0.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"tavern",
|
"tavern",
|
||||||
@ -263,7 +263,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blog_test"
|
name = "blog_test"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"axum-server",
|
"axum-server",
|
||||||
@ -1941,7 +1941,7 @@ checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "loreweaver"
|
name = "loreweaver"
|
||||||
version = "0.1.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"tavern",
|
"tavern",
|
||||||
@ -3104,7 +3104,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tavern"
|
name = "tavern"
|
||||||
version = "0.2.9"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"pulldown-cmark",
|
"pulldown-cmark",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bard"
|
name = "bard"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "Dioxus components that will display a Tavern blogging system Blog."
|
description = "Dioxus components that will display a Tavern blogging system Blog."
|
||||||
repository = "/CyberMages/tavern"
|
repository = "/CyberMages/tavern"
|
||||||
|
|||||||
@ -1,3 +1,16 @@
|
|||||||
|
.visually_hidden
|
||||||
|
{
|
||||||
|
position: absolute !important;
|
||||||
|
width: 1px !important;
|
||||||
|
height: 1px !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: -1px !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
clip: rect(0, 0, 0, 0) !important;
|
||||||
|
border: 0 !important;
|
||||||
|
white-space: nowrap !important;
|
||||||
|
}
|
||||||
|
|
||||||
.blog_style
|
.blog_style
|
||||||
{
|
{
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -17,3 +30,165 @@
|
|||||||
container-type: inline-size;
|
container-type: inline-size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.blog_list
|
||||||
|
{
|
||||||
|
order: 5;
|
||||||
|
|
||||||
|
.blog_title
|
||||||
|
{
|
||||||
|
margin-top: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_item
|
||||||
|
{
|
||||||
|
margin-bottom: 30px;
|
||||||
|
|
||||||
|
h2
|
||||||
|
{
|
||||||
|
margin: 0px;
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
p
|
||||||
|
{
|
||||||
|
margin: 5px 0px 0px 0px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.blog_post
|
||||||
|
{
|
||||||
|
order: 5;
|
||||||
|
|
||||||
|
h1
|
||||||
|
{
|
||||||
|
margin: 0px;
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
h4
|
||||||
|
{
|
||||||
|
margin-top: 10px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li
|
||||||
|
{
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p
|
||||||
|
{
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.embeded_video
|
||||||
|
{
|
||||||
|
margin-top: 50px;
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
iframe
|
||||||
|
{
|
||||||
|
box-shadow: 0 0 80px var(--accent-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Tags will have a class of "tag_{tag_name}" that allows specific
|
||||||
|
* customization.
|
||||||
|
*
|
||||||
|
* .tag_easy
|
||||||
|
* {
|
||||||
|
* background-color: #248721;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
.blog_tag
|
||||||
|
{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.tag_list
|
||||||
|
{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.blog_nav
|
||||||
|
{
|
||||||
|
order: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: 70px;
|
||||||
|
margin-right: 70px;
|
||||||
|
|
||||||
|
fieldset
|
||||||
|
{
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
min-inline-size: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
legend
|
||||||
|
{
|
||||||
|
min-width: 120px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag_list
|
||||||
|
{
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container site (max-width: 1230px)
|
||||||
|
{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag_list
|
||||||
|
{
|
||||||
|
list-style: none;
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
|
||||||
|
.tag_item
|
||||||
|
{
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
|
||||||
|
a
|
||||||
|
{
|
||||||
|
display: block;
|
||||||
|
padding: 0px 4px;
|
||||||
|
text-decoration: none;
|
||||||
|
border: 2px solid var(--text-color);
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
color: var(--text-color);
|
||||||
|
transition: 0.1s ease-in;
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
{
|
||||||
|
color: var(--accent-color);
|
||||||
|
border: 2px solid var(--accent-color);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,230 +0,0 @@
|
|||||||
.blog_style
|
|
||||||
{
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: var(--bg-color);
|
|
||||||
padding: 50px 0px;
|
|
||||||
justify-content: center;
|
|
||||||
container-name: site;
|
|
||||||
container-type: inline-size;
|
|
||||||
|
|
||||||
.page_content
|
|
||||||
{
|
|
||||||
display: flex;
|
|
||||||
width: 67%;
|
|
||||||
container-name: page;
|
|
||||||
container-type: inline-size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.blog_nav
|
|
||||||
{
|
|
||||||
width: 15%;
|
|
||||||
padding: 0px 20px;
|
|
||||||
|
|
||||||
h3
|
|
||||||
{
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul
|
|
||||||
{
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
li
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@container site (max-width: 1230px)
|
|
||||||
{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.social
|
|
||||||
{
|
|
||||||
/* Hide .social until the font is loaded */
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 15px;
|
|
||||||
margin: 25px 0;
|
|
||||||
font-family: cm_social;
|
|
||||||
|
|
||||||
a
|
|
||||||
{
|
|
||||||
color: var(--text-color);
|
|
||||||
font-size: 46px;
|
|
||||||
text-decoration: none;
|
|
||||||
background: transparent;
|
|
||||||
width: 65px;
|
|
||||||
height: 65px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
justify-content: center;
|
|
||||||
transition: 0.4s ease;
|
|
||||||
border: 4px solid var(--text-color);
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
border: 4px solid var(--accent-color);
|
|
||||||
transform: translateY(-7px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.blog_item_area
|
|
||||||
{
|
|
||||||
.blog_list
|
|
||||||
{
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
.blog_item
|
|
||||||
{
|
|
||||||
margin-bottom: 50px;
|
|
||||||
|
|
||||||
h1
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
h4
|
|
||||||
{
|
|
||||||
margin: 10px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.blog_article
|
|
||||||
{
|
|
||||||
h1
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
h4
|
|
||||||
{
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p
|
|
||||||
{
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embeded_video
|
|
||||||
{
|
|
||||||
margin-top: 50px;
|
|
||||||
display: flex;
|
|
||||||
align-content: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
iframe
|
|
||||||
{
|
|
||||||
box-shadow: 0 0 80px var(--accent-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.tag_style
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
.tag_list
|
|
||||||
{
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
.tag_item
|
|
||||||
{
|
|
||||||
display: inline-block;
|
|
||||||
margin: 5px 5px 0px 0px;
|
|
||||||
|
|
||||||
a
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
padding: 0px 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
border: 2px solid var(--text-color);
|
|
||||||
border-radius: 5px;
|
|
||||||
|
|
||||||
color: var(--text-color);
|
|
||||||
transition: 0.1s ease-in;
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
border: 2px solid var(--accent-color);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.easy
|
|
||||||
{
|
|
||||||
background-color: #248721;
|
|
||||||
}
|
|
||||||
|
|
||||||
.medium
|
|
||||||
{
|
|
||||||
background-color: #d6a318;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hard
|
|
||||||
{
|
|
||||||
background-color: #d92121;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.social
|
|
||||||
{
|
|
||||||
background: transparent;
|
|
||||||
font-family: cm_social;
|
|
||||||
margin: 15px 0px;
|
|
||||||
|
|
||||||
a
|
|
||||||
{
|
|
||||||
color: var(--text-color);
|
|
||||||
font-size: 30px;
|
|
||||||
text-decoration: none;
|
|
||||||
background: transparent;
|
|
||||||
width: 45px;
|
|
||||||
height: 45px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
justify-content: center;
|
|
||||||
transition: 0.4s ease;
|
|
||||||
border: 4px solid var(--text-color);
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
border: 4px solid var(--accent-color);
|
|
||||||
transform: translateY(-7px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
.blog_list_style
|
|
||||||
{
|
|
||||||
.blog_list
|
|
||||||
{
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
.blog_item
|
|
||||||
{
|
|
||||||
margin-bottom: 50px;
|
|
||||||
|
|
||||||
h1
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
h4
|
|
||||||
{
|
|
||||||
margin: 10px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,117 +0,0 @@
|
|||||||
.blog_style
|
|
||||||
{
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: var(--bg-color);
|
|
||||||
padding: 50px 0px;
|
|
||||||
justify-content: center;
|
|
||||||
container-name: site;
|
|
||||||
container-type: inline-size;
|
|
||||||
|
|
||||||
.page_content
|
|
||||||
{
|
|
||||||
display: flex;
|
|
||||||
width: 67%;
|
|
||||||
container-name: page;
|
|
||||||
container-type: inline-size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.blog_nav_style
|
|
||||||
{
|
|
||||||
width: 15%;
|
|
||||||
padding: 0px 20px;
|
|
||||||
order: 5;
|
|
||||||
|
|
||||||
h3
|
|
||||||
{
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul
|
|
||||||
{
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
li
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@container site (max-width: 1230px)
|
|
||||||
{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.social
|
|
||||||
{
|
|
||||||
/* Hide .social until the font is loaded */
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 15px;
|
|
||||||
margin: 25px 0;
|
|
||||||
font-family: cm_social;
|
|
||||||
|
|
||||||
a
|
|
||||||
{
|
|
||||||
color: var(--text-color);
|
|
||||||
font-size: 22px;
|
|
||||||
text-decoration: none;
|
|
||||||
background: transparent;
|
|
||||||
width: 35px;
|
|
||||||
height: 35px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
justify-content: center;
|
|
||||||
transition: 0.4s ease;
|
|
||||||
border: 4px solid var(--text-color);
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
border: 4px solid var(--accent-color);
|
|
||||||
transform: translateY(-7px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag_style
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
.tag_list
|
|
||||||
{
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: column;
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
.tag_item
|
|
||||||
{
|
|
||||||
display: inline-block;
|
|
||||||
margin: 5px 5px 0px 0px;
|
|
||||||
|
|
||||||
a
|
|
||||||
{
|
|
||||||
display: inline-flex;
|
|
||||||
padding: 0px 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
border: 2px solid var(--text-color);
|
|
||||||
border-radius: 5px;
|
|
||||||
|
|
||||||
color: var(--text-color);
|
|
||||||
transition: 0.1s ease-in;
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
border: 2px solid var(--accent-color);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,119 +0,0 @@
|
|||||||
.blog_post_style
|
|
||||||
{
|
|
||||||
order: 1;
|
|
||||||
|
|
||||||
h1
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
h4
|
|
||||||
{
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
p
|
|
||||||
{
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embeded_video
|
|
||||||
{
|
|
||||||
margin-top: 50px;
|
|
||||||
display: flex;
|
|
||||||
align-content: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
iframe
|
|
||||||
{
|
|
||||||
box-shadow: 0 0 80px var(--accent-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.tag_style
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
.tag_list
|
|
||||||
{
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
.tag_item
|
|
||||||
{
|
|
||||||
display: inline-block;
|
|
||||||
margin: 5px 5px 0px 0px;
|
|
||||||
|
|
||||||
a
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
padding: 0px 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
border: 2px solid var(--text-color);
|
|
||||||
border-radius: 5px;
|
|
||||||
|
|
||||||
color: var(--text-color);
|
|
||||||
transition: 0.1s ease-in;
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
border: 2px solid var(--accent-color);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.easy
|
|
||||||
{
|
|
||||||
background-color: #248721;
|
|
||||||
}
|
|
||||||
|
|
||||||
.medium
|
|
||||||
{
|
|
||||||
background-color: #d6a318;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hard
|
|
||||||
{
|
|
||||||
background-color: #d92121;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.social
|
|
||||||
{
|
|
||||||
background: transparent;
|
|
||||||
font-family: cm_social;
|
|
||||||
margin: 15px 0px;
|
|
||||||
|
|
||||||
a
|
|
||||||
{
|
|
||||||
color: var(--text-color);
|
|
||||||
font-size: 30px;
|
|
||||||
text-decoration: none;
|
|
||||||
background: transparent;
|
|
||||||
width: 45px;
|
|
||||||
height: 45px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
justify-content: center;
|
|
||||||
transition: 0.4s ease;
|
|
||||||
border: 4px solid var(--text-color);
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
border: 4px solid var(--accent-color);
|
|
||||||
transform: translateY(-7px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
.blog_tag_style
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
.tag_list
|
|
||||||
{
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
.tag_item
|
|
||||||
{
|
|
||||||
display: inline-block;
|
|
||||||
margin: 5px 5px 0px 0px;
|
|
||||||
|
|
||||||
a
|
|
||||||
{
|
|
||||||
display: block;
|
|
||||||
padding: 0px 4px;
|
|
||||||
text-decoration: none;
|
|
||||||
border: 2px solid var(--text-color);
|
|
||||||
border-radius: 5px;
|
|
||||||
|
|
||||||
color: var(--text-color);
|
|
||||||
transition: 0.1s ease-in;
|
|
||||||
|
|
||||||
&:hover
|
|
||||||
{
|
|
||||||
color: var(--accent-color);
|
|
||||||
border: 2px solid var(--accent-color);
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.none
|
|
||||||
{
|
|
||||||
background-color: var(--bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.easy
|
|
||||||
{
|
|
||||||
background-color: #248721;
|
|
||||||
}
|
|
||||||
|
|
||||||
.medium
|
|
||||||
{
|
|
||||||
background-color: #d6a318;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hard
|
|
||||||
{
|
|
||||||
background-color: #d92121;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -30,18 +30,20 @@ pub fn BlogItem(title: String, slug: String, author: String, summary: String,
|
|||||||
tags: Vec<String>)
|
tags: Vec<String>)
|
||||||
-> Element
|
-> Element
|
||||||
{
|
{
|
||||||
println!("Blog Item: {title} -- [{tags:?}]");
|
|
||||||
rsx!
|
rsx!
|
||||||
{
|
{
|
||||||
li
|
article
|
||||||
{
|
{
|
||||||
key: "{slug}",
|
|
||||||
class: "blog_item",
|
class: "blog_item",
|
||||||
|
|
||||||
Link
|
h2
|
||||||
{
|
{
|
||||||
to: Page::Post { slug: slug.clone() },
|
Link
|
||||||
h1 { "{title}" }
|
{
|
||||||
|
to: Page::Post { slug: slug.clone() },
|
||||||
|
|
||||||
|
"{title}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TagList
|
TagList
|
||||||
@ -55,7 +57,7 @@ pub fn BlogItem(title: String, slug: String, author: String, summary: String,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 { "Author: {author}" }
|
p { b { "Author: {author}" } }
|
||||||
|
|
||||||
p { "{summary}" }
|
p { "{summary}" }
|
||||||
}
|
}
|
||||||
@ -66,8 +68,10 @@ pub fn BlogItem(title: String, slug: String, author: String, summary: String,
|
|||||||
#[component]
|
#[component]
|
||||||
pub fn BlogList(tags: Signal<HashSet<String>>, children: Element) -> Element
|
pub fn BlogList(tags: Signal<HashSet<String>>, children: Element) -> Element
|
||||||
{
|
{
|
||||||
let list = use_server_future(move || {
|
let list = use_server_future(move ||
|
||||||
let categories = tags().iter().cloned().collect();
|
{
|
||||||
|
let t = tags();
|
||||||
|
let categories = t.iter().cloned().collect();
|
||||||
|
|
||||||
async move { get_blog_list(categories).await }
|
async move { get_blog_list(categories).await }
|
||||||
})?;
|
})?;
|
||||||
@ -76,41 +80,40 @@ pub fn BlogList(tags: Signal<HashSet<String>>, children: Element) -> Element
|
|||||||
{
|
{
|
||||||
section
|
section
|
||||||
{
|
{
|
||||||
class: "blog_list_style",
|
class: "blog_list",
|
||||||
ul
|
|
||||||
{
|
|
||||||
class: "blog_list",
|
|
||||||
|
|
||||||
if let Some(Ok(lores)) = &*list.read()
|
h1 { class: "blog_title", "Runes & Ramblings" }
|
||||||
|
|
||||||
|
if let Some(Ok(lores)) = &*list.read()
|
||||||
|
{
|
||||||
|
for lore in lores
|
||||||
{
|
{
|
||||||
for lore in lores
|
BlogItem
|
||||||
{
|
{
|
||||||
BlogItem
|
title: lore.title.clone(),
|
||||||
{
|
slug: lore.slug.clone(),
|
||||||
title: lore.title.clone(),
|
author: lore.author.clone(),
|
||||||
slug: lore.slug.clone(),
|
summary: lore.summary.clone(),
|
||||||
author: lore.author.clone(),
|
tags: lore.tags.clone()
|
||||||
summary: lore.summary.clone(),
|
|
||||||
tags: lore.tags.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if let Some(Err(e)) = &*list.read()
|
|
||||||
{
|
|
||||||
p { "Unable to show post header." }
|
|
||||||
p { "{e}" }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p { "Loading..." }
|
|
||||||
}
|
|
||||||
|
|
||||||
{children}
|
|
||||||
}
|
}
|
||||||
|
else if let Some(Err(e)) = &*list.read()
|
||||||
|
{
|
||||||
|
p { "Unable to show post header." }
|
||||||
|
p { "{e}" }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p { "Loading..." }
|
||||||
|
}
|
||||||
|
|
||||||
|
{children}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn ToggleTag(tag: String, toggled_tags: Signal<HashSet<String>>) -> Element
|
pub fn ToggleTag(tag: String, toggled_tags: Signal<HashSet<String>>) -> Element
|
||||||
{
|
{
|
||||||
@ -130,65 +133,151 @@ pub fn ToggleTag(tag: String, toggled_tags: Signal<HashSet<String>>) -> Element
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
span { "{tag}" }
|
"{tag}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Using use_resource instead of use_server_future for URL-dependent tag selection
|
||||||
|
//
|
||||||
|
// While use_server_future should theoretically be reactive when reading signals in the
|
||||||
|
// closure (per Dioxus docs), in practice it doesn't reliably re-run when the url_tag
|
||||||
|
// signal changes, especially during direct URL navigation (typing URLs in browser).
|
||||||
|
//
|
||||||
|
// use_resource provides more reliable reactivity for this use case because:
|
||||||
|
// 1. It explicitly depends on url_tag and consistently re-runs when it changes
|
||||||
|
// 2. It handles both async data fetching AND selection logic in a single atomic operation
|
||||||
|
// 3. It works consistently across all navigation methods (links, direct URLs, etc.)
|
||||||
|
// 4. It avoids timing coordination issues between separate hooks
|
||||||
|
//
|
||||||
|
// This approach combines fetching available tags from the server with determining
|
||||||
|
// which tags should be selected based on the current URL, returning both pieces
|
||||||
|
// of data together for clean state management.
|
||||||
#[component]
|
#[component]
|
||||||
pub fn TagSelector(show_all: Signal<bool>, toggled_tags: Signal<HashSet<String>>) -> Element
|
pub fn TagSelector(url_tag: ReadOnlySignal<String>,
|
||||||
|
toggled_tags: Signal<HashSet<String>>) -> Element
|
||||||
{
|
{
|
||||||
let toggle_all: bool = show_all();
|
// Use use_resource to handle both fetching tags AND initializing selection
|
||||||
|
let tags_and_selection = use_resource(move ||
|
||||||
println!("Tag Selector toggled tags: {:?}", toggled_tags());
|
|
||||||
let tags_future = use_server_future(move || async move { get_tags().await })?;
|
|
||||||
|
|
||||||
use_effect(move ||
|
|
||||||
{
|
{
|
||||||
if let Some(Ok(tags)) = &*tags_future.read()
|
let current_url = url_tag();
|
||||||
|
|
||||||
|
async move
|
||||||
{
|
{
|
||||||
if toggle_all
|
match get_tags().await
|
||||||
{
|
{
|
||||||
for tag in tags
|
Ok(available_tags) =>
|
||||||
{
|
{
|
||||||
toggled_tags.write().insert(tag.clone());
|
// Determine what should be selected based on URL
|
||||||
|
let should_show_all = current_url.is_empty() || current_url == "all";
|
||||||
|
|
||||||
|
let selected_tags: HashSet<String> = if should_show_all
|
||||||
|
{
|
||||||
|
available_tags.iter().cloned().collect()
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let url_categories = convert_categories(¤t_url);
|
||||||
|
|
||||||
|
let filtered: HashSet<String> = url_categories.into_iter()
|
||||||
|
.filter(|tag| available_tags.contains(tag))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
filtered
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((available_tags, selected_tags))
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(e) =>
|
||||||
|
{
|
||||||
|
eprintln!("RESOURCE - Error: {}", e);
|
||||||
|
Err(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Separate effect to update toggled_tags when resource completes
|
||||||
|
// This separates reading the resource from writing to toggled_tags
|
||||||
|
use_effect(move ||
|
||||||
|
{
|
||||||
|
if let Some(Ok((_, selected_tags))) = &*tags_and_selection.read()
|
||||||
|
{
|
||||||
|
toggled_tags.set(selected_tags.clone());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
rsx!
|
rsx!
|
||||||
{
|
{
|
||||||
section
|
section
|
||||||
{
|
{
|
||||||
class: "blog_nav_style",
|
class: "blog_nav",
|
||||||
div
|
|
||||||
|
h2 { class: "visually_hidden", "Filters and Navigation" }
|
||||||
|
|
||||||
|
fieldset
|
||||||
{
|
{
|
||||||
class: "tag_style",
|
class: "tag_style",
|
||||||
h2 { "Categories" }
|
|
||||||
|
legend { "Category Filter" }
|
||||||
|
|
||||||
ul
|
ul
|
||||||
{
|
{
|
||||||
class: "tag_list",
|
class: "tag_list",
|
||||||
|
|
||||||
if let Some(Ok(tags)) = tags_future()
|
match &*tags_and_selection.read()
|
||||||
{
|
{
|
||||||
for tag in tags
|
Some(Ok((available_tags, _))) =>
|
||||||
{
|
{
|
||||||
li
|
rsx!
|
||||||
{
|
{
|
||||||
key: "selector-{tag}",
|
for tag in available_tags
|
||||||
class: "tag_item",
|
|
||||||
|
|
||||||
ToggleTag
|
|
||||||
{
|
{
|
||||||
tag: &tag,
|
li
|
||||||
toggled_tags: toggled_tags
|
{
|
||||||
|
key: "selector-{tag}",
|
||||||
|
class: "tag_item",
|
||||||
|
|
||||||
|
ToggleTag
|
||||||
|
{
|
||||||
|
tag: tag.clone(),
|
||||||
|
toggled_tags: toggled_tags
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some(Err(_)) =>
|
||||||
|
{
|
||||||
|
rsx!
|
||||||
|
{
|
||||||
|
li { "Error loading tags" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None =>
|
||||||
|
{
|
||||||
|
rsx!
|
||||||
|
{
|
||||||
|
li { "Loading tags..." }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn convert_categories(categories: &str) -> HashSet<String>
|
||||||
|
{
|
||||||
|
categories
|
||||||
|
.split('+')
|
||||||
|
.filter(|s| !s.is_empty() && *s != "all")
|
||||||
|
.map(str::to_string)
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|||||||
@ -30,10 +30,13 @@ pub fn PostHeaderAuthor(adventurer: Adventurer) -> Element
|
|||||||
{
|
{
|
||||||
rsx!
|
rsx!
|
||||||
{
|
{
|
||||||
h4
|
p
|
||||||
{
|
{
|
||||||
"Author: ",
|
b
|
||||||
a { href: "{adventurer.legend.profile}", "{adventurer.name} @{adventurer.handle}" }
|
{
|
||||||
|
"Author: ",
|
||||||
|
a { href: "{adventurer.legend.profile}", "{adventurer.name} @{adventurer.handle}" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,7 +102,7 @@ pub fn BlogPost(slug: Signal<String>, children: Element) -> Element
|
|||||||
{
|
{
|
||||||
article
|
article
|
||||||
{
|
{
|
||||||
class: "blog_post_style",
|
class: "blog_post",
|
||||||
|
|
||||||
if let Some(Ok(tale)) = (post_future.value())()
|
if let Some(Ok(tale)) = (post_future.value())()
|
||||||
{
|
{
|
||||||
@ -137,42 +140,36 @@ pub fn TagNav() -> Element
|
|||||||
{
|
{
|
||||||
section
|
section
|
||||||
{
|
{
|
||||||
class: "blog_nav_style",
|
class: "blog_nav",
|
||||||
div
|
|
||||||
|
fieldset
|
||||||
{
|
{
|
||||||
class: "tag_style",
|
class: "tag_list",
|
||||||
h2 { "Categories" }
|
|
||||||
ul
|
legend { "Category Filter" }
|
||||||
|
|
||||||
|
if let Some(Ok(categories)) = &*tags.read()
|
||||||
{
|
{
|
||||||
class: "tag_list",
|
for tag in categories
|
||||||
if let Some(Ok(categories)) = &*tags.read()
|
|
||||||
{
|
{
|
||||||
for tag in categories
|
Link
|
||||||
{
|
|
||||||
li
|
|
||||||
{
|
{
|
||||||
key: "{tag}",
|
class: "tag_item tag_{tag}",
|
||||||
class: "tag_item",
|
|
||||||
Link
|
|
||||||
{
|
|
||||||
to: Page::Blog { tag: tag.clone() },
|
|
||||||
|
|
||||||
"{tag}"
|
to: Page::Blog { tag: tag.clone() },
|
||||||
}
|
|
||||||
|
|
||||||
//a { href: "/blog/{tag}", "{tag}" }
|
"{tag}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if let Some(Err(e)) = &*tags.read()
|
else if let Some(Err(e)) = &*tags.read()
|
||||||
{
|
{
|
||||||
p { "Unable to show desired post." }
|
p { "Unable to load tags." }
|
||||||
p { "{e}" }
|
p { "{e}" }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p { "Loading..." }
|
p { "Loading..." }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,15 +37,10 @@ pub fn TagList(children: Element) -> Element
|
|||||||
{
|
{
|
||||||
rsx!
|
rsx!
|
||||||
{
|
{
|
||||||
h5
|
ul
|
||||||
{
|
{
|
||||||
class: "blog_tag_style",
|
class: "blog_tag tag_list",
|
||||||
|
{children}
|
||||||
ul
|
|
||||||
{
|
|
||||||
class: "tag_list",
|
|
||||||
{children}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,34 +7,12 @@ use crate::page::Page;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn convert_categories(categories: &str) -> HashSet<String>
|
|
||||||
{
|
|
||||||
categories
|
|
||||||
.split('+')
|
|
||||||
.filter(|s| !s.is_empty() && *s != "all")
|
|
||||||
.map(str::to_string)
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Blog page
|
/// Blog page
|
||||||
#[component]
|
#[component]
|
||||||
pub fn Blog(tag: ReadOnlySignal<String>) -> Element
|
pub fn Blog(tag: ReadOnlySignal<String>) -> Element
|
||||||
{
|
{
|
||||||
let mut show_all: Signal<bool> =
|
|
||||||
use_signal(|| tag().is_empty() || tag() == "all");
|
|
||||||
|
|
||||||
let mut categories: Signal<HashSet<String>> =
|
let mut categories: Signal<HashSet<String>> =
|
||||||
use_signal(|| convert_categories(&tag()));
|
use_signal(|| HashSet::new());
|
||||||
|
|
||||||
use_effect(move ||
|
|
||||||
{
|
|
||||||
let new_tags = convert_categories(&tag());
|
|
||||||
categories.set(new_tags);
|
|
||||||
});
|
|
||||||
|
|
||||||
println!("Blog Categories: {:?}", categories());
|
|
||||||
|
|
||||||
rsx!
|
rsx!
|
||||||
{
|
{
|
||||||
@ -47,13 +25,13 @@ pub fn Blog(tag: ReadOnlySignal<String>) -> Element
|
|||||||
|
|
||||||
BlogList
|
BlogList
|
||||||
{
|
{
|
||||||
tags: categories.clone()
|
tags: categories
|
||||||
}
|
}
|
||||||
|
|
||||||
TagSelector
|
TagSelector
|
||||||
{
|
{
|
||||||
show_all: show_all.clone(),
|
url_tag: tag,
|
||||||
toggled_tags: categories.clone()
|
toggled_tags: categories
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user