Compare commits
1 Commits
main
...
f3508de4eb
| Author | SHA1 | Date | |
|---|---|---|---|
|
f3508de4eb
|
@@ -3,7 +3,6 @@
|
|||||||
/.github
|
/.github
|
||||||
/bundle
|
/bundle
|
||||||
/node_modules
|
/node_modules
|
||||||
/scripts
|
|
||||||
/target
|
/target
|
||||||
|
|
||||||
/.dockerignore
|
/.dockerignore
|
||||||
|
|||||||
6
.github/workflows/rust-check.yaml
vendored
6
.github/workflows/rust-check.yaml
vendored
@@ -34,9 +34,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: .env symlink creation
|
- name: .env symlink creation
|
||||||
run: ln -s .env.dev .env
|
run: ln -s .env.example .env
|
||||||
- name: Tailwind CSS output creation
|
- name: npm build
|
||||||
run: touch assets/tailwind.css
|
run: npm install && npm run build
|
||||||
- name: rustfmt check
|
- name: rustfmt check
|
||||||
run: cargo fmt --all --check
|
run: cargo fmt --all --check
|
||||||
- name: Clippy check
|
- name: Clippy check
|
||||||
|
|||||||
19
Dioxus.toml
19
Dioxus.toml
@@ -2,5 +2,20 @@
|
|||||||
|
|
||||||
[web.app]
|
[web.app]
|
||||||
|
|
||||||
# HTML title tag content.
|
# HTML title tag content
|
||||||
title = "Todo Baggins"
|
title = "todo_baggins"
|
||||||
|
|
||||||
|
# include `assets` in web platform
|
||||||
|
[web.resource]
|
||||||
|
|
||||||
|
# Additional CSS style files
|
||||||
|
style = []
|
||||||
|
|
||||||
|
# Additional JavaScript files
|
||||||
|
script = []
|
||||||
|
|
||||||
|
[web.resource.dev]
|
||||||
|
|
||||||
|
# Javascript code file
|
||||||
|
# serve: [dev-server] only
|
||||||
|
script = []
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
---
|
|
||||||
services:
|
|
||||||
app:
|
|
||||||
build:
|
|
||||||
target: builder_android
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
FROM rust:1.92.0-bookworm@sha256:9676d0547a259997add8f5924eb6b959c589ed39055338e23b99aba7958d6d31
|
FROM rust:1.92.0-bookworm@sha256:9676d0547a259997add8f5924eb6b959c589ed39055338e23b99aba7958d6d31
|
||||||
|
|
||||||
RUN useradd -m -u 1000 -s /bin/bash app_user \
|
RUN useradd -m -u 1000 -s /bin/bash app_user
|
||||||
&& rustup target add wasm32-unknown-unknown
|
|
||||||
|
RUN rustup target add wasm32-unknown-unknown
|
||||||
|
|
||||||
USER app_user
|
USER app_user
|
||||||
|
|
||||||
RUN cargo install --git https://github.com/diesel-rs/diesel --rev 2e85ba060d3d70ea605ea58a79b8a435749a7adc --locked diesel_cli \
|
RUN cargo install --locked dioxus-cli --version 0.7.2 \
|
||||||
&& cargo install --git https://github.com/DioxusLabs/dioxus --rev 8f8b58ea80ba0ec8057807bcd58fb609f7a5f2b1 --locked dioxus-cli
|
&& cargo install --locked diesel_cli --version 2.3.4
|
||||||
|
|
||||||
COPY --chown=app_user . /srv/app
|
COPY --chown=app_user . /srv/app
|
||||||
WORKDIR /srv/app
|
WORKDIR /srv/app
|
||||||
|
|||||||
@@ -1,13 +1,4 @@
|
|||||||
FROM rust:1.92.0-bookworm@sha256:9676d0547a259997add8f5924eb6b959c589ed39055338e23b99aba7958d6d31 AS builder_base
|
FROM rust:1.92.0-bookworm@sha256:9676d0547a259997add8f5924eb6b959c589ed39055338e23b99aba7958d6d31 AS builder
|
||||||
|
|
||||||
RUN cargo install --git https://github.com/diesel-rs/diesel --rev 2e85ba060d3d70ea605ea58a79b8a435749a7adc --locked diesel_cli \
|
|
||||||
&& cargo install --git https://github.com/DioxusLabs/dioxus --rev 8f8b58ea80ba0ec8057807bcd58fb609f7a5f2b1 --locked dioxus-cli --features disable-telemetry
|
|
||||||
|
|
||||||
COPY . /srv/app
|
|
||||||
WORKDIR /srv/app
|
|
||||||
|
|
||||||
|
|
||||||
FROM builder_base AS builder_android
|
|
||||||
|
|
||||||
ARG ANDROID_NDK_VERSION=26.2.11394342
|
ARG ANDROID_NDK_VERSION=26.2.11394342
|
||||||
ARG ANDROID_COMMAND_LINE_TOOLS_VERSION=13114758
|
ARG ANDROID_COMMAND_LINE_TOOLS_VERSION=13114758
|
||||||
@@ -18,12 +9,13 @@ ARG ANDROID_BUNDLETOOL_VERSION=1.18.3
|
|||||||
ARG ANDROID_BUNDLETOOL_SHA256=a099cfa1543f55593bc2ed16a70a7c67fe54b1747bb7301f37fdfd6d91028e29
|
ARG ANDROID_BUNDLETOOL_SHA256=a099cfa1543f55593bc2ed16a70a7c67fe54b1747bb7301f37fdfd6d91028e29
|
||||||
ENV ANDROID_SDK_ROOT=/opt/android-sdk
|
ENV ANDROID_SDK_ROOT=/opt/android-sdk
|
||||||
|
|
||||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
openjdk-17-jdk-headless=17.0.17+10-1~deb12u1 \
|
openjdk-17-jdk-headless=17.0.17+10-1~deb12u1 \
|
||||||
|
&& curl -fsSL -o /tmp/cmdline-tools.zip "https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_COMMAND_LINE_TOOLS_VERSION}_latest.zip" \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& cargo install --git https://github.com/diesel-rs/diesel --rev 2e85ba060d3d70ea605ea58a79b8a435749a7adc diesel_cli \
|
||||||
|
&& cargo install --git https://github.com/DioxusLabs/dioxus --rev 8f8b58ea80ba0ec8057807bcd58fb609f7a5f2b1 dioxus-cli --features disable-telemetry \
|
||||||
&& rustup target add aarch64-linux-android \
|
&& rustup target add aarch64-linux-android \
|
||||||
&& mkdir -p "$ANDROID_SDK_ROOT/cmdline-tools" \
|
&& mkdir -p "$ANDROID_SDK_ROOT/cmdline-tools" \
|
||||||
&& curl -fsSL -o /tmp/cmdline-tools.zip "https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_COMMAND_LINE_TOOLS_VERSION}_latest.zip" \
|
&& curl -fsSL -o /tmp/cmdline-tools.zip "https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_COMMAND_LINE_TOOLS_VERSION}_latest.zip" \
|
||||||
@@ -31,33 +23,32 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
&& export PATH="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools:$PATH" \
|
&& export PATH="$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools:$PATH" \
|
||||||
&& mv "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools" "$ANDROID_SDK_ROOT/cmdline-tools/latest" \
|
&& mv "$ANDROID_SDK_ROOT/cmdline-tools/cmdline-tools" "$ANDROID_SDK_ROOT/cmdline-tools/latest" \
|
||||||
&& rm /tmp/cmdline-tools.zip \
|
&& rm /tmp/cmdline-tools.zip \
|
||||||
# `yes` can exit with 141, which is okay, so the `test` is added to ignore it.
|
&& yes | sdkmanager --sdk_root="$ANDROID_SDK_ROOT" --licenses > /dev/null \
|
||||||
&& yes | sdkmanager --sdk_root="$ANDROID_SDK_ROOT" --licenses > /dev/null; test "${PIPESTATUS[1]}" -eq 0 \
|
|
||||||
&& sdkmanager --sdk_root="$ANDROID_SDK_ROOT" "platform-tools" "platforms;android-$ANDROID_VERSION" "build-tools;$ANDROID_BUILD_TOOLS_VERSION" "ndk;$ANDROID_NDK_VERSION" \
|
&& sdkmanager --sdk_root="$ANDROID_SDK_ROOT" "platform-tools" "platforms;android-$ANDROID_VERSION" "build-tools;$ANDROID_BUILD_TOOLS_VERSION" "ndk;$ANDROID_NDK_VERSION" \
|
||||||
&& curl -fsSL -o /tmp/bundletool-all.jar "https://github.com/google/bundletool/releases/download/$ANDROID_BUNDLETOOL_VERSION/bundletool-all-${ANDROID_BUNDLETOOL_VERSION}.jar" \
|
&& curl -fsSL -o /tmp/bundletool-all.jar "https://github.com/google/bundletool/releases/download/$ANDROID_BUNDLETOOL_VERSION/bundletool-all-${ANDROID_BUNDLETOOL_VERSION}.jar" \
|
||||||
&& echo "$ANDROID_BUNDLETOOL_SHA256 /tmp/bundletool-all.jar" | sha256sum -c - \
|
&& echo "$ANDROID_BUNDLETOOL_SHA256 /tmp/bundletool-all.jar" | sha256sum -c - \
|
||||||
&& keytool -genkeypair -noprompt -keystore /tmp/android_keystore.jks -alias key -keyalg RSA -keysize 2048 -validity 3660 -dname "CN=" -storepass 123456 -keypass 123456 \
|
&& keytool -genkeypair -noprompt -keystore /tmp/android_keystore.jks -alias key -keyalg RSA -keysize 2048 -validity 3660 -dname "CN=" -storepass 123456 -keypass 123456
|
||||||
&& export ANDROID_HOME="$ANDROID_SDK_ROOT" \
|
|
||||||
|
COPY . /srv/app
|
||||||
|
WORKDIR /srv/app
|
||||||
|
|
||||||
|
RUN export ANDROID_HOME="$ANDROID_SDK_ROOT" \
|
||||||
&& export ANDROID_NDK_HOME="$ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION" \
|
&& export ANDROID_NDK_HOME="$ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION" \
|
||||||
|
&& dx bundle --release \
|
||||||
&& dx bundle --platform android --target aarch64-linux-android --release \
|
&& dx bundle --platform android --target aarch64-linux-android --release \
|
||||||
&& java -jar /tmp/bundletool-all.jar build-apks --bundle=/srv/app/target/dx/todo_baggins/release/android/app/app/build/outputs/bundle/release/TodoBaggins-aarch64-linux-android.aab --output=/tmp/todo_baggins.apks --mode=universal --ks=/tmp/android_keystore.jks --ks-key-alias=key --ks-pass=pass:123456 \
|
&& java -jar /tmp/bundletool-all.jar build-apks --bundle=/srv/app/target/dx/todo_baggins/release/android/app/app/build/outputs/bundle/release/TodoBaggins-aarch64-linux-android.aab --output=/tmp/todo_baggins.apks --mode=universal --ks=/tmp/android_keystore.jks --ks-key-alias=key --ks-pass=pass:123456 \
|
||||||
&& mkdir -p /srv/app/bundle \
|
&& mkdir -p /srv/app/bundle/android \
|
||||||
&& unzip -qp /tmp/todo_baggins.apks universal.apk > /srv/app/bundle/todo_baggins.apk
|
&& unzip -qp /tmp/todo_baggins.apks universal.apk > /srv/app/bundle/android/todo_baggins.apk
|
||||||
|
|
||||||
|
FROM debian:bookworm@sha256:b877a1a3fdf02469440f1768cf69c9771338a875b7add5e80c45b756c92ac20a AS runner
|
||||||
FROM builder_base AS builder_web
|
|
||||||
|
|
||||||
RUN dx bundle --release
|
|
||||||
|
|
||||||
|
|
||||||
FROM debian:bookworm@sha256:b877a1a3fdf02469440f1768cf69c9771338a875b7add5e80c45b756c92ac20a AS runner_web
|
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends libpq5=15.10-0+deb12u1 \
|
&& apt-get install -y --no-install-recommends libpq5=15.10-0+deb12u1 \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY --from=builder_web /srv/app/target/dx/todo_baggins/release/web /srv/app/web
|
COPY --from=builder /srv/app/target/dx/todo_baggins/release/web /srv/app/web
|
||||||
|
COPY --from=builder /srv/app/bundle/android /srv/app/android
|
||||||
|
|
||||||
RUN chown -R 1000:1000 /srv/app/web
|
RUN chown -R 1000:1000 /srv/app/web
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,4 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
echo "Warning: This script needs to stop any currently running Docker compose stacks. Stopping them now..."
|
mkdir -p ../bundle \
|
||||||
docker compose down
|
&& docker compose -f docker-compose-prod.yaml cp app:/srv/app/android bundle
|
||||||
|
|
||||||
mkdir -p bundle/android bundle/temp \
|
|
||||||
&& docker compose -f docker-compose-prod.yaml -f docker-compose-android-bundle.yaml up --build --no-start --no-deps app \
|
|
||||||
&& docker compose -f docker-compose-prod.yaml -f docker-compose-android-bundle.yaml cp app:/srv/app/bundle bundle/temp \
|
|
||||||
&& mv bundle/temp/bundle/* bundle/android \
|
|
||||||
&& rm -r bundle/temp
|
|
||||||
|
|
||||||
echo "Warning: If a running Docker compose stack has been stopped by this script, you may want to bring it up again now."
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ pub(crate) fn CategoryCalendarTaskList() -> Element {
|
|||||||
date: today_date,
|
date: today_date,
|
||||||
reoccurrence: None,
|
reoccurrence: None,
|
||||||
time: None,
|
time: None,
|
||||||
})?;
|
})?();
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ pub(crate) fn CategoryTodayTaskList() -> Element {
|
|||||||
date: today_date,
|
date: today_date,
|
||||||
reoccurrence: None,
|
reoccurrence: None,
|
||||||
time: None,
|
time: None,
|
||||||
})?;
|
})?();
|
||||||
let today_tasks = calendar_tasks
|
let today_tasks = calendar_tasks
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|task| {
|
.filter(|task| {
|
||||||
@@ -40,7 +40,7 @@ pub(crate) fn CategoryTodayTaskList() -> Element {
|
|||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<TaskWithSubtasks>>();
|
.collect::<Vec<TaskWithSubtasks>>();
|
||||||
let long_term_tasks = use_tasks_with_subtasks_in_category(Category::LongTerm)?;
|
let long_term_tasks = use_tasks_with_subtasks_in_category(Category::LongTerm)?();
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
div {
|
div {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use dioxus::prelude::*;
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub(crate) fn ProjectList() -> Element {
|
pub(crate) fn ProjectList() -> Element {
|
||||||
let projects = use_projects()?;
|
let projects = use_projects()?();
|
||||||
let mut project_being_edited = use_context::<Signal<Option<Project>>>();
|
let mut project_being_edited = use_context::<Signal<Option<Project>>>();
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use dioxus_i18n::t;
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub(crate) fn ProjectSelect(initial_selected_id: Option<i32>) -> Element {
|
pub(crate) fn ProjectSelect(initial_selected_id: Option<i32>) -> Element {
|
||||||
let projects = use_projects()?;
|
let projects = use_projects()?();
|
||||||
rsx! {
|
rsx! {
|
||||||
select {
|
select {
|
||||||
name: "project_id",
|
name: "project_id",
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use dioxus::prelude::*;
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub(crate) fn SubtasksForm(task: Task) -> Element {
|
pub(crate) fn SubtasksForm(task: Task) -> Element {
|
||||||
let subtasks = use_subtasks_of_task(task.id)?;
|
let subtasks = use_subtasks_of_task(task.id)?();
|
||||||
let mut new_title = use_signal(String::new);
|
let mut new_title = use_signal(String::new);
|
||||||
rsx! {
|
rsx! {
|
||||||
form {
|
form {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::components::task_list_item::TaskListItem;
|
use crate::components::task_list_item::TaskListItem;
|
||||||
use crate::models::category::Category;
|
use crate::models::category::Category;
|
||||||
use crate::models::task::{Task, TaskWithSubtasks};
|
use crate::models::task::{Task, TaskWithSubtasks};
|
||||||
use crate::server::tasks::complete_task;
|
|
||||||
use dioxus::core_macro::rsx;
|
use dioxus::core_macro::rsx;
|
||||||
use dioxus::dioxus_core::Element;
|
use dioxus::dioxus_core::Element;
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
@@ -49,9 +48,6 @@ pub(crate) fn TaskList(tasks: Vec<TaskWithSubtasks>, class: Option<&'static str>
|
|||||||
move |event: Event<MouseData>| {
|
move |event: Event<MouseData>| {
|
||||||
// To prevent editing the task.
|
// To prevent editing the task.
|
||||||
event.stop_propagation();
|
event.stop_propagation();
|
||||||
async move {
|
|
||||||
let _ = complete_task(task.task.id).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,17 +13,6 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(clippy::result_large_err)]
|
|
||||||
fn sort_loader_result<T: Ord + Clone>(
|
|
||||||
result: Result<Loader<Vec<T>>, Loading>,
|
|
||||||
) -> Result<Vec<T>, Loading> {
|
|
||||||
result.map(|loader| {
|
|
||||||
let mut items_sorted = loader();
|
|
||||||
items_sorted.sort();
|
|
||||||
items_sorted
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
fn use_loader_with_update_subscription<F, T, E>(
|
fn use_loader_with_update_subscription<F, T, E>(
|
||||||
mut future: impl FnMut() -> F + 'static,
|
mut future: impl FnMut() -> F + 'static,
|
||||||
@@ -51,23 +40,22 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
pub(crate) fn use_projects() -> Result<Vec<Project>, Loading> {
|
pub(crate) fn use_projects() -> Result<Loader<Vec<Project>>, Loading> {
|
||||||
let result = use_loader_with_update_subscription(get_projects);
|
use_loader_with_update_subscription(get_projects).inspect(|projects| projects().sort())
|
||||||
sort_loader_result(result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
pub(crate) fn use_tasks_with_subtasks_in_category(
|
pub(crate) fn use_tasks_with_subtasks_in_category(
|
||||||
filtered_category: Category,
|
filtered_category: Category,
|
||||||
) -> Result<Vec<TaskWithSubtasks>, Loading> {
|
) -> Result<Loader<Vec<TaskWithSubtasks>>, Loading> {
|
||||||
let result = use_loader_with_update_subscription(move || {
|
use_loader_with_update_subscription(move || {
|
||||||
get_tasks_with_subtasks_in_category(filtered_category.clone())
|
get_tasks_with_subtasks_in_category(filtered_category.clone())
|
||||||
});
|
})
|
||||||
sort_loader_result(result)
|
.inspect(|tasks| tasks().sort())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
pub(crate) fn use_subtasks_of_task(task_id: i32) -> Result<Vec<Subtask>, Loading> {
|
pub(crate) fn use_subtasks_of_task(task_id: i32) -> Result<Loader<Vec<Subtask>>, Loading> {
|
||||||
let result = use_loader_with_update_subscription(move || get_subtasks_of_task(task_id));
|
use_loader_with_update_subscription(move || get_subtasks_of_task(task_id))
|
||||||
sort_loader_result(result)
|
.inspect(|subtasks| subtasks().sort())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,15 +46,8 @@ mod server_only {
|
|||||||
let mut disconnected_client_ids = HashSet::new();
|
let mut disconnected_client_ids = HashSet::new();
|
||||||
let subscribed_clients = SUBSCRIBED_CLIENTS.read().await;
|
let subscribed_clients = SUBSCRIBED_CLIENTS.read().await;
|
||||||
for (id, client) in subscribed_clients.iter() {
|
for (id, client) in subscribed_clients.iter() {
|
||||||
if client
|
if let Err(_) = client.websocket.lock().await.send(UpdateEvent).await {
|
||||||
.websocket
|
disconnected_client_ids.insert(id.clone());
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.send(UpdateEvent)
|
|
||||||
.await
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
disconnected_client_ids.insert(*id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop(subscribed_clients);
|
drop(subscribed_clients);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use dioxus::prelude::*;
|
|||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub(crate) fn CategoryPage(category: Category) -> Element {
|
pub(crate) fn CategoryPage(category: Category) -> Element {
|
||||||
let tasks = use_tasks_with_subtasks_in_category(category)?;
|
let tasks = use_tasks_with_subtasks_in_category(category)?();
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
TaskList {
|
TaskList {
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
/* stylelint-disable-next-line import-notation */
|
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
|||||||
Reference in New Issue
Block a user