diff --git a/website/blog/2024-07-10-building-productivity-tools-with-marimo/2024-07-10-building-productivity-tools-with-marimo.md b/website/blog/2024-07-10-building-productivity-tools-with-marimo/2024-07-10-building-productivity-tools-with-marimo.md new file mode 100644 index 0000000..bf769eb --- /dev/null +++ b/website/blog/2024-07-10-building-productivity-tools-with-marimo/2024-07-10-building-productivity-tools-with-marimo.md @@ -0,0 +1,71 @@ +--- +slug: "2024-07-10-building-productivity-tools-with-marimo" +title: "Building Productivity Tools with marimo" +summary: "Discover how marimo, an open-source Python reactive notebook, can revolutionize your workflow. This post describes the journey in creating three powerful productivity tools: a Working Day Calculator, a Holiday Announcement Parser, and an Automatic Release Scheduler." +authors: [Oreo] +tags: [Python] +--- + +```mdx-code-block +import ReactPlayer from 'react-player'; +``` + +Have you ever dreamed of creating custom tools to simplify your work life? In recent weeks, I've been exploring the capabilities of [marimo](https://marimo.io), an innovative open-source Python reactive notebook. This powerful tool has enabled me to create three applications that have significantly streamlined my work planning process. In this post, I'm excited to share my journey with marimo and showcase the tools I've developed. + +:::info quote + +marimo is an open-source reactive notebook for Python — reproducible, git-friendly, executable as a script, and shareable as an app. + +—— [marimo](https://marimo.io) + +::: + + + +## Showcasing the tools + +Let's dive into the tools I built using marimo: + +- [**Working Day Calculator**](https://tool.oreo.life/workcalc/): parses official holiday announcements from the General Office of the State Council and generates data for annual public holidays and compensatory working days in China. + + + +- [**Holiday Announcement Parser**](https://tool.oreo.life/holiparse/): calculates dates before or after a specified number of working days, taking into account official public holidays and compensatory working days in China. + + + +- **Automatic Release Scheduler**: streamlines the product release process by automatically scheduling tasks based on a given release date. + + + +## From idea to implementation + +The journey of creating these tools was an organic process, driven by real-world needs and continuous improvement: + +1. It all began with the **Automatic Release Scheduler**. Manually calculating working days in China, especially around public holidays, was a significant pain point. I wanted a tool that could take a product release date and automatically schedule tasks, accounting for these complexities. +2. During this process, I realized that calculating a date a certain number of working days before or after a given date was a fundamental need applicable to various scenarios. This led to the creation of the **Working Day Calculator** as a standalone tool. +3. Initially, I planned to manually configure annual holidays and compensatory workdays through the UI. However, I soon realized that keeping this information up-to-date would be tedious. This realization sparked the development of the **Holiday Announcement Parser**, which automatically extracts this data from official government notifications. +4. For the parser, I initially considered using an AI model but found it occasionally omitted holidays. I then explored regex but encountered limitations with capturing multiple repeated groups. +5. Finally, I refactored the **Automatic Release Scheduler** to leverage the code from the **Working Day Calculator**, showcasing the power of code reusability in marimo. + +## My Experience with marimo + +Here are some key takeaways from my time with marimo: + +- **Version control friendly**: marimo stores notebooks as `.py` files, making them git-friendly and easy to version control. +- **Visualized dependencies**: marimo provides helpful visualizations of variables and dependencies, making code optimization and understanding a smoother process. +- **Code reusability**: marimo enables you to reuse code defined in one notebook across other notebooks or Python files. This came in handy when I refactored the Automatic Release Scheduler using the Working Day Calculator's code. +- **Data analysis capabilities**: marimo offers `marimo.ui.table` for data analysis. You can filter. But it's not a UI for display. To display a list of lists as a table, it would need to be converted to a list of dict. +- **WebAssembly support**: marimo notebooks can be run in the browser using WebAssembly. For deployment, however, Docker is currently required, which might present a hurdle for beginners. Thankfully, [Marimo Cloud](https://docs.marimo.io/guides/deploying/deploying_marimo_cloud.html) is in beta and might provide a simplified deployment process. + +## Beyond the code: the importance of user experience + +While the development process itself took around 15 hours, a significant amount of time was dedicated to crafting a user-friendly interface. Finding the right combination and arrangement of UI elements was crucial for a positive user experience. Inspiration for the UI layout came from the designs generated by [Claude 3.5](https://www.anthropic.com/news/claude-3-5-sonnet). + +## Conclusion + +I hope this blog post has given you a taste of the possibilities marimo offers for building innovative tools. If you're a Python developer looking to streamline your workflow or create custom applications, marimo is definitely worth exploring! + +By leveraging marimo, I was able to create three interconnected tools that have significantly improved my work planning process. The journey from identifying a need to developing a solution was not only rewarding but also a great learning experience in terms of tool development and user interface design. + +Whether you're looking to solve a specific problem in your workflow or just want to explore new ways of working with Python, I encourage you to give marimo a try. diff --git a/website/blog/tags.yml b/website/blog/tags.yml index ab1af4b..e684b60 100644 --- a/website/blog/tags.yml +++ b/website/blog/tags.yml @@ -61,7 +61,7 @@ Technical Writing: TiDB Cloud: label: 'TiDB Cloud' description: 'Blog posts related to TiDB Cloud' - permalink: /tiDB-cloud + permalink: /tidb-cloud Tips & Tricks: label: 'Tips & Tricks' diff --git a/website/i18n/en/docusaurus-plugin-content-blog/tags.yml b/website/i18n/en/docusaurus-plugin-content-blog/tags.yml index ab1af4b..e684b60 100644 --- a/website/i18n/en/docusaurus-plugin-content-blog/tags.yml +++ b/website/i18n/en/docusaurus-plugin-content-blog/tags.yml @@ -61,7 +61,7 @@ Technical Writing: TiDB Cloud: label: 'TiDB Cloud' description: 'Blog posts related to TiDB Cloud' - permalink: /tiDB-cloud + permalink: /tidb-cloud Tips & Tricks: label: 'Tips & Tricks' diff --git a/website/package.json b/website/package.json index 7ef3519..e776377 100644 --- a/website/package.json +++ b/website/package.json @@ -22,7 +22,8 @@ "clsx": "^1.2.1", "prism-react-renderer": "^2.1.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "react-player": "^2.16.0" }, "devDependencies": { "@docusaurus/module-type-aliases": "^3.4.0", diff --git a/website/static/img/autosched-demo.mp4 b/website/static/img/autosched-demo.mp4 new file mode 100644 index 0000000..1688789 Binary files /dev/null and b/website/static/img/autosched-demo.mp4 differ diff --git a/website/static/img/holiparse-demo.mp4 b/website/static/img/holiparse-demo.mp4 new file mode 100644 index 0000000..c3021c8 Binary files /dev/null and b/website/static/img/holiparse-demo.mp4 differ diff --git a/website/static/img/workcalc-demo.mp4 b/website/static/img/workcalc-demo.mp4 new file mode 100644 index 0000000..e1bc3b8 Binary files /dev/null and b/website/static/img/workcalc-demo.mp4 differ diff --git a/website/yarn.lock b/website/yarn.lock index 86a8c2a..80e6ced 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -4440,7 +4440,7 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deepmerge@^4.2.2, deepmerge@^4.3.1: +deepmerge@^4.0.0, deepmerge@^4.2.2, deepmerge@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== @@ -6116,6 +6116,11 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +load-script@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/load-script/-/load-script-1.0.0.tgz#0491939e0bee5643ee494a7e3da3d2bac70c6ca4" + integrity sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA== + loader-runner@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" @@ -6488,6 +6493,11 @@ memfs@^3.1.2, memfs@^3.4.3: dependencies: fs-monkey "^1.0.4" +memoize-one@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -7920,7 +7930,7 @@ react-error-overlay@^6.0.11: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== -react-fast-compare@^3.2.0: +react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== @@ -7960,6 +7970,17 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1: dependencies: "@types/react" "*" +react-player@^2.16.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/react-player/-/react-player-2.16.0.tgz#89070700b03f5a5ded9f0b3165d4717390796481" + integrity sha512-mAIPHfioD7yxO0GNYVFD1303QFtI3lyyQZLY229UEAp/a10cSW+hPcakg0Keq8uWJxT2OiT/4Gt+Lc9bD6bJmQ== + dependencies: + deepmerge "^4.0.0" + load-script "^1.0.0" + memoize-one "^5.1.1" + prop-types "^15.7.2" + react-fast-compare "^3.0.1" + react-router-config@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-5.1.1.tgz#0f4263d1a80c6b2dc7b9c1902c9526478194a988"