From fc84d8c479c87f35ce41246c189c0f0e0d2d2a2d071702349e3f87ead27307e7 Mon Sep 17 00:00:00 2001 From: Techognito Date: Wed, 6 Aug 2025 10:17:09 +0200 Subject: [PATCH] GarageApp and wisher projects added GarageApp set up with translation with i18n, this required changes to routes in src/index.tsx --- bun.lock | 36 +++ package.json | 8 +- src/App.tsx | 2 + src/GarageApp/App.tsx | 28 +++ src/GarageApp/frontend.tsx | 27 ++ src/GarageApp/i18n.js | 22 ++ src/GarageApp/index.html | 13 + .../locales/en/.translation.json.swp | Bin 0 -> 16384 bytes src/GarageApp/locales/en/translation.json | 231 ++++++++++++++++++ src/GarageApp/locales/index.tsx | 6 + src/GarageApp/logo.svg | 1 + src/GarageApp/react.svg | 8 + src/index.tsx | 17 ++ src/wisher/.list.tsx.swp | Bin 0 -> 12288 bytes src/wisher/index.html | 13 + src/wisher/list.tsx | 61 +++++ src/wisher/list.txt | 57 +++++ 17 files changed, 529 insertions(+), 1 deletion(-) create mode 100644 src/GarageApp/App.tsx create mode 100644 src/GarageApp/frontend.tsx create mode 100644 src/GarageApp/i18n.js create mode 100644 src/GarageApp/index.html create mode 100644 src/GarageApp/locales/en/.translation.json.swp create mode 100644 src/GarageApp/locales/en/translation.json create mode 100644 src/GarageApp/locales/index.tsx create mode 100644 src/GarageApp/logo.svg create mode 100644 src/GarageApp/react.svg create mode 100644 src/wisher/.list.tsx.swp create mode 100644 src/wisher/index.html create mode 100644 src/wisher/list.tsx create mode 100644 src/wisher/list.txt diff --git a/bun.lock b/bun.lock index 309165a3..47adca7d 100644 --- a/bun.lock +++ b/bun.lock @@ -4,8 +4,14 @@ "": { "name": "bun-react-template", "dependencies": { + "i18next": "^25.3.2", + "i18next-browser-languagedetector": "^8.2.0", + "i18next-fs-backend": "^2.6.0", + "i18next-http-backend": "^3.0.2", + "node": "^22.18.0", "react": "^19", "react-dom": "^19", + "react-i18next": "^15.6.1", }, "devDependencies": { "@types/bun": "latest", @@ -15,6 +21,8 @@ }, }, "packages": { + "@babel/runtime": ["@babel/runtime@7.28.2", "", {}, "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA=="], + "@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="], "@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="], @@ -25,14 +33,42 @@ "bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="], + "cross-fetch": ["cross-fetch@4.0.0", "", { "dependencies": { "node-fetch": "^2.6.12" } }, "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g=="], + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "html-parse-stringify": ["html-parse-stringify@3.0.1", "", { "dependencies": { "void-elements": "3.1.0" } }, "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg=="], + + "i18next": ["i18next@25.3.2", "", { "dependencies": { "@babel/runtime": "^7.27.6" }, "peerDependencies": { "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-JSnbZDxRVbphc5jiptxr3o2zocy5dEqpVm9qCGdJwRNO+9saUJS0/u4LnM/13C23fUEWxAylPqKU/NpMV/IjqA=="], + + "i18next-browser-languagedetector": ["i18next-browser-languagedetector@8.2.0", "", { "dependencies": { "@babel/runtime": "^7.23.2" } }, "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g=="], + + "i18next-fs-backend": ["i18next-fs-backend@2.6.0", "", {}, "sha512-3ZlhNoF9yxnM8pa8bWp5120/Ob6t4lVl1l/tbLmkml/ei3ud8IWySCHt2lrY5xWRlSU5D9IV2sm5bEbGuTqwTw=="], + + "i18next-http-backend": ["i18next-http-backend@3.0.2", "", { "dependencies": { "cross-fetch": "4.0.0" } }, "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g=="], + + "node": ["node@22.18.0", "", { "dependencies": { "node-bin-setup": "^1.0.0" }, "bin": { "node": "bin/node" } }, "sha512-3njku3qUgOVps16gg1+y1L9AseQoZFUZmd2ASA3+K/pryQLoiEoHkjQ6UmVSysW2EkvdILBKsUYM9RpBKJ47+w=="], + + "node-bin-setup": ["node-bin-setup@1.1.4", "", {}, "sha512-vWNHOne0ZUavArqPP5LJta50+S8R261Fr5SvGul37HbEDcowvLjwdvd0ZeSr0r2lTSrPxl6okq9QUw8BFGiAxA=="], + + "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="], "react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="], + "react-i18next": ["react-i18next@15.6.1", "", { "dependencies": { "@babel/runtime": "^7.27.6", "html-parse-stringify": "^3.0.1" }, "peerDependencies": { "i18next": ">= 23.2.3", "react": ">= 16.8.0", "typescript": "^5" }, "optionalPeers": ["typescript"] }, "sha512-uGrzSsOUUe2sDBG/+FJq2J1MM+Y4368/QW8OLEKSFvnDflHBbZhSd1u3UkW0Z06rMhZmnB/AQrhCpYfE5/5XNg=="], + "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], + "tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], + "undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "void-elements": ["void-elements@3.1.0", "", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="], + + "webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + + "whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], } } diff --git a/package.json b/package.json index 2e70afd4..2976794f 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,14 @@ "start": "NODE_ENV=production bun src/index.tsx" }, "dependencies": { + "i18next": "^25.3.2", + "i18next-browser-languagedetector": "^8.2.0", + "i18next-fs-backend": "^2.6.0", + "i18next-http-backend": "^3.0.2", + "node": "^22.18.0", "react": "^19", - "react-dom": "^19" + "react-dom": "^19", + "react-i18next": "^15.6.1" }, "devDependencies": { "@types/react": "^19", diff --git a/src/App.tsx b/src/App.tsx index 88042912..860470ca 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,6 @@ import { APITester } from "./APITester"; import "./index.css"; +import { List } from "./wisher/list"; import logo from "./logo.svg"; import reactLogo from "./react.svg"; @@ -17,6 +18,7 @@ export function App() { Edit src/App.tsx and save to test HMR

+ ); } diff --git a/src/GarageApp/App.tsx b/src/GarageApp/App.tsx new file mode 100644 index 00000000..b70ed1f0 --- /dev/null +++ b/src/GarageApp/App.tsx @@ -0,0 +1,28 @@ +import { APITester } from "../APITester"; +import "../index.css"; +import { List } from "../wisher/list"; +import { useTranslation, withTranslation, Trans } from 'react-i18next'; + +import logo from "./logo.svg"; +import reactLogo from "./react.svg"; + +export function App() { + const { t, i18n } = useTranslation(); + return ( +
+
+ Bun Logo + React Logo +
+ +

Bun + React | GarageApp

+

+ Edit src/App.tsx and save to test HMR +

+

{t ('statistics')}

+

{t ('yourvehicles')}

+
+ ); +} + +export default App; diff --git a/src/GarageApp/frontend.tsx b/src/GarageApp/frontend.tsx new file mode 100644 index 00000000..cd03d02d --- /dev/null +++ b/src/GarageApp/frontend.tsx @@ -0,0 +1,27 @@ +/** + * This file is the entry point for the React app, it sets up the root + * element and renders the App component to the DOM. + * + * It is included in `src/index.html`. + */ + +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { App } from "./App.tsx"; +import './i18n'; + +const elem = document.getElementById("root")!; +const app = ( + + + +); + +if (import.meta.hot) { + // With hot module reloading, `import.meta.hot.data` is persisted. + const root = (import.meta.hot.data.root ??= createRoot(elem)); + root.render(app); +} else { + // The hot module reloading API is not available in production. + createRoot(elem).render(app); +} diff --git a/src/GarageApp/i18n.js b/src/GarageApp/i18n.js new file mode 100644 index 00000000..d0ca8cbd --- /dev/null +++ b/src/GarageApp/i18n.js @@ -0,0 +1,22 @@ +import i18n from 'i18next'; +import Backend from 'i18next-http-backend'; +// import Backend from 'i18next-fs-backend' +import LanguageDetector from 'i18next-browser-languagedetector'; +import { initReactI18next } from 'react-i18next'; + + +i18n + .use(Backend) + .use(LanguageDetector) + .use(initReactI18next) + .init({ + fallbackLng: 'en', + debug: true, + backend: { + loadPath: '/GarageApp/locales/{{lng}}/{{ns}}.json' + }, + lng: 'en', + ns: ['translation'] + + }); +export default i18n diff --git a/src/GarageApp/index.html b/src/GarageApp/index.html new file mode 100644 index 00000000..4ba79393 --- /dev/null +++ b/src/GarageApp/index.html @@ -0,0 +1,13 @@ + + + + + + + Bun + React + + +
+ + + diff --git a/src/GarageApp/locales/en/.translation.json.swp b/src/GarageApp/locales/en/.translation.json.swp new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..399f8112e59b8d23298fcfb0e919cad6e8b52e692396a64e08086bb76a8101c1 GIT binary patch literal 16384 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 literal 0 HcmV?d00001 diff --git a/src/GarageApp/locales/en/translation.json b/src/GarageApp/locales/en/translation.json new file mode 100644 index 00000000..db92dcbf --- /dev/null +++ b/src/GarageApp/locales/en/translation.json @@ -0,0 +1,231 @@ +{ + "quickentry": "No Quick Entries | Quick Entry | Quick Entries", + "statistics": "Statistics", + "thisweek": "This week", + "thismonth": "This month", + "pastxdays": "Past one day | Past {count} days", + "pastxmonths": "Past one month | Past {count} months", + "thisyear": "This year", + "alltime": "All Time", + "noattachments": "No Attachments so far", + "attachments": "Attachments", + "choosefile": "Choose File", + "addattachment": "Add Attachment", + "sharedwith": "Shared with", + "share": "Share", + "you": "You", + "addfillup": "Add Fillup", + "createfillup": "Create Fillup", + "deletefillup": "Delete this fillup", + "addexpense": "Add Expense", + "createexpense": "Create Expense", + "deleteexpense": "Delete this expense", + "nofillups": "No Fillups so far", + "transfervehicle": "Transfer Vehicle", + "settingssaved": "Settings saved successfully", + "yoursettings": "Your Settings", + "settings": "Settings", + "changepassword": "Change password", + "oldpassword": "Old password", + "newpassword": "New password", + "repeatnewpassword": "Repeat New Password", + "passworddontmatch": "Password values don't match", + "save": "Save", + "supportthedeveloper": "Support the developer", + "buyhimabeer": "Buy him a beer!", + "featurerequest": "Feature Request", + "foundabug": "Found a bug", + "currentversion": "Current Version", + "moreinfo": "More Info", + "currency": "Currency", + "distanceunit": "Distance Unit", + "dateformat": "Date Format", + "createnow": "Create Now", + "yourvehicles": "Your Vehicles", + "menu": { + "quickentries": "Quick Entries", + "logout": "Log out", + "import": "Import", + "home": "Home", + "settings": "Settings", + "admin": "Admin", + "sitesettings": "Site Settings", + "users": "Users", + "login": "Log in" + }, + "enterusername": "Enter your username", + "enterpassword": "Enter your password", + "email": "Email", + "password": "Password", + "login": "log in", + "totalexpenses": "Total Expenses", + "fillupcost": "Fillup Costs", + "otherexpenses": "Other Expenses", + "addvehicle": "Add Vehicle", + "editvehicle": "Edit Vehicle", + "deletevehicle": "Delete Vehicle", + "sharevehicle": "Share vehicle", + "makeowner": "Make Owner", + "lastfillup": "Last Fillup", + "quickentrydesc": "Take a pic of the invoice or the fuel pump display to make an entry later.", + "quickentrycreatedsuccessfully": "Quick Entry Created Successfully", + "uploadfile": "Upload File", + "uploadphoto": "Upload Photo", + "details": "Details", + "odometer": "Odometer", + "language": "Language", + "date": "Date", + "pastfillups": "Past Fillups", + "fuelsubtype": "Fuel Subtype", + "fueltype": "Fuel Type", + "quantity": "Quantity", + "gasstation": "Gas Station", + "fuel": { + "petrol": "Petrol", + "diesel": "Diesel", + "cng": "CNG", + "lpg": "LPG", + "electric": "Electric", + "ethanol": "Ethanol" + }, + "unit": { + "long": { + "litre": "Litre", + "gallon": "Gallon", + "kilowatthour": "Kilowatt Hour", + "kilogram": "Kilogram", + "usgallon": "US Gallon", + "minutes": "Minutes", + "kilometers": "Kilometers", + "miles": "Miles" + }, + "short": { + "litre": "Lt", + "gallon": "Gal", + "kilowatthour": "KwH", + "kilogram": "Kg", + "usgallon": "US Gal", + "minutes": "Mins", + "kilometers": "Km", + "miles": "Mi" + } + }, + "avgfillupqty": "Avg Fillup Qty", + "avgfillupexpense": "Avg Fillup Expense", + "avgfuelcost": "Avg Fuel Cost", + "per": "{0} per {1}", + "price": "Price", + "total": "Total", + "fulltank": "Tank Full", + "partialfillup": "Partial Fillup", + "getafulltank": "Did you get a full tank?", + "tankpartialfull": "Which do you track?", + "by": "By", + "expenses": "Expenses", + "expensetype": "Expense Type", + "noexpenses": "No Expenses so far", + "download": "Download", + "title": "Title", + "name": "Name", + "delete": "Delete", + "importdata": "Import data into Hammond", + "importdatadesc": "Choose from the following options to import data into Hammond", + "import": "Import", + "importcsv": "If you have been using {name} to store your vehicle data, export the CSV file from {name} and click here to import.", + "importgeneric": "Generic Fillups Import", + "importgenericdesc": "Fillups CSV import.", + "choosecsv": "Choose CSV", + "choosephoto": "Choose Photo", + "importsuccessfull": "Data Imported Successfully", + "importerror": "There was some issue with importing the file. Please check the error message", + "importfrom": "Import from {0}", + "stepstoimport": "Steps to import data from {name}", + "choosecsvimport": "Choose the {name} CSV and press the import button.", + "choosedatafile": "Choose the CSV file and then press the import button.", + "dontimportagain": "Make sure that you do not import the file again because that will create repeat entries.", + "checkpointsimportcsv": "Once you have checked all these points, just import the CSV below.", + "importhintunits": "Similiarly, make sure that the Fuel Unit and Fuel Type are correctly set in the Vehicle.", + "importhintcurrdist": "Make sure that the Currency and Distance Unit are set correctly in Hammond. Import will not autodetect Currency from the file but use the one set for the user.", + "importhintnickname": "Make sure that the Vehicle nickname in Hammond is exactly the same as the name on Fuelly CSV or the import will not work.", + "importhintvehiclecreated": "Make sure that you have already created the vehicles in Hammond platform.", + "importhintcreatecsv": "Export your data from {name} in the CSV format. Steps to do that can be found", + "importgenerichintdata": "Data must be in CSV format.", + "here": "here", + "unprocessedquickentries": "You have one quick entry to be processed. | You have {0} quick entries pending to be processed.", + "show": "Show", + "loginerror": "There was an error logging in to your account. {msg}", + "showunprocessed": "Show unprocessed only", + "unprocessed": "unprocessed", + "sitesettingdesc": "Update site level settings. These will be used as default values for new users.", + "settingdesc": "These will be used as default values whenever you create a new fillup or expense.", + "areyousure": "Are you sure you want to do this?", + "adduser": "Add User", + "usercreatedsuccessfully": "User Created Successfully", + "userdisabledsuccessfully": "User disabled successfully", + "userenabledsuccessfully": "User enabled successfully", + "role": "Role", + "created": "Created", + "createnewuser": "Create New User", + "cancel": "Cancel", + "novehicles": "It seems you have not yet created a vehicle in the system. Start by creating an entry for one of the vehicles you want to track.", + "processed": "Mark Processed", + "notfound": "Not Found", + "timeout": "The page timed out while loading. Are you sure you're still connected to\nthe Internet?", + "clicktoselect": "Click to select...", + "expenseby": "Expense by", + "selectvehicle": "Select a vehicle", + "expensedate": "Expense Date", + "totalamountpaid": "Total Amount Paid", + "fillmoredetails": "Fill more details", + "markquickentryprocessed": "Mark selected Quick Entry as processed", + "referquickentry": "Refer quick entry", + "deletequickentry": "This will delete this Quick Entry. This step cannot be reversed. Are you sure?", + "fuelunit": "Fuel Unit", + "fillingstation": "Filling Station Name", + "comments": "Comments", + "missfillupbefore": "Did you miss the fillup entry before this one?", + "missedfillup": "Missed Fillup", + "fillupdate": "Fillup Date", + "fillupsavedsuccessfully": "Fillup Saved Successfully", + "expensesavedsuccessfully": "Expense Saved Successfully", + "vehiclesavedsuccessfully": "Vehicle Saved Successfully", + "settingssavedsuccessfully": "Settings saved successfully", + "back": "Back", + "nickname": "Nickname", + "registration": "Registration", + "createvehicle": "Create Vehicle", + "make": "Make / Company", + "model": "Model", + "yearmanufacture": "Year of Manufacture", + "enginesize": "Engine Size (in cc)", + "mysqlconnstr": "Mysql Connection String", + "testconn": "Test Connection", + "migrate": "Migrate", + "init": { + "migrateclarkson": "Migrate from Clarkson", + "migrateclarksondesc": "If you have an existing Clarkson deployment and you want to migrate your data from that, press the following button.", + "freshinstall": "Fresh Install", + "freshinstalldesc": "If you want a fresh install of Hammond, press the following button.", + "clarkson": { + "desc": "

You need to make sure that this deployment of Hammond can access the MySQL database used by Clarkson.

If that is not directly possible, you can make a copy of that database somewhere accessible from this instance.

Once that is done, enter the connection string to the MySQL instance in the following format.

All the users imported from Clarkson will have their username as their email in Clarkson database and pasword set tohammond

user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local

", + "success": "We have successfully migrated the data from Clarkson. You will be redirected to the login screen shortly where you can login using your existing email and password : hammond" + }, + "fresh": { + "setupadminuser": "Setup Admin Users", + "yourpassword": "Your Password", + "youremail": "Your Email", + "yourname": "Your Name", + "success": "You have been registered successfully. You will be redirected to the login screen shortly where you can login and start using the system." + } + }, + "roles": { + "ADMIN": "ADMIN", + "USER": "USER" + }, + "profile": "Profile", + "processedon": "Processed on", + "enable": "Enable", + "disable": "Disable", + "confirm": "Go Ahead", + "labelforfile": "Label for this file" +} diff --git a/src/GarageApp/locales/index.tsx b/src/GarageApp/locales/index.tsx new file mode 100644 index 00000000..f3a44e40 --- /dev/null +++ b/src/GarageApp/locales/index.tsx @@ -0,0 +1,6 @@ +export const LANGUAGES = [ + { label: "Spanish", code: "es" }, + { label: "English", code: "en" }, + { label: "Italian", code: "it" }, +]; + diff --git a/src/GarageApp/logo.svg b/src/GarageApp/logo.svg new file mode 100644 index 00000000..8c52aa71 --- /dev/null +++ b/src/GarageApp/logo.svg @@ -0,0 +1 @@ +Bun Logo \ No newline at end of file diff --git a/src/GarageApp/react.svg b/src/GarageApp/react.svg new file mode 100644 index 00000000..6d43f95f --- /dev/null +++ b/src/GarageApp/react.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/index.tsx b/src/index.tsx index 3cedebda..50281b23 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,11 +1,28 @@ import { serve } from "bun"; import index from "./index.html"; +import wisher from "./wisher/index.html" +import GarageApp from "./GarageApp/index.html" +import locales from "./GarageApp/locales/index" const server = serve({ routes: { // Serve index.html for all unmatched routes. "/*": index, + "/wisher": wisher, + "/wisher/*": wisher, + + "/GarageApp": GarageApp, + "/GarageApp/*": GarageApp, + "/GarageApp/locales/:lng/translation.json": async req => { + const lng = req.params.lng; + const ns = req.params.ns; + const path = `src/GarageApp/locales/${lng}/translation.json` + console.log(`${lng}, ${ns}`); + console.log(process.cwd()); + return new Response(Bun.file(path)) + }, + "/api/hello": { async GET(req) { return Response.json({ diff --git a/src/wisher/.list.tsx.swp b/src/wisher/.list.tsx.swp new file mode 100644 index 0000000000000000000000000000000000000000000000000000000000000000..7c0a9df1be614afd25c6bfde30141803383be601284170cd377670a45a9f6a34 GIT binary patch literal 12288 zcmeHN&x;&I6t0bEoM<#Ch{v}RFf(DcdpCiw?)Hu-F5aj2H2&7a<1~FM>Dm;C~=!K+paG2Jz~_uX?(7=l8BT8L5JAs;m0FSMPoGUiS=B z+skimzDh4TD-7)%W2*I0=k1SwJhfPRgo&LrR669b60x~GtL-hVUS3{aYKcIme3lUA z-yJsSzQTPO`;p87_liS-*cFjXx+2zYD!8wgl87I)Q<=qqt5V_9yTw@F^gGEuaA`06(8)?0euYz=7w0 zdrva<9dHM@4Qv8efER%0f%{J|_7m_8@EPzSumYS0emle1*T5a%CE)K0V_yKbfCg~? zamGFeLSPm6{WN3W0`CKF0S({`@CV|%2mAos1wH_JKm=?9dHfII{#lnT1C{~Hz<-ee zLhCd0Y1+}18P(TWrQ*3kxZA{qnejT8n$!!m=qe{k!&vvpb1`S+AVz+~mD=K6u~GG9 zAgWDfw1(TjT!RhImDiq|MUxuk-Fki0yK=tlJ)Aq6t$ifLQyuz|I9}AK6w#O3$Mv2o z=R`0~`($2^YrfnTYvief$IW~<9MMf8c_74X-WGk&&F`>rt$AbbB;*YncreGO`mA`w z(}M?c+jw+6S6}N@sX9MHhTS*U|0-rrMkDFX(_qOQbexjo2&QKo@IFW4EQlYX)&!ES|VVE>8*Fw?>xaP-*pM>~g zT~l?F%sZ%rc(ND=)5ej!TG2c2C>hu4^^ss(!Z2LzXq~7v*A236_rQU$=1C~_IbKV` z!LGR&y1OfG`JPhMBQu#2S6eON>l$_{cd>G~gkew9jrW`?zSrkD-?3+}eRu=mvQRy090&u*C-?w>^kdL$R mTD&eLgiH=s2WRC2u;53bc_y!yqP@c~8s=(11NDdXAp8%4J(9Zs literal 0 HcmV?d00001 diff --git a/src/wisher/index.html b/src/wisher/index.html new file mode 100644 index 00000000..7940e274 --- /dev/null +++ b/src/wisher/index.html @@ -0,0 +1,13 @@ + + + + + + + Wisher with Bun + React + + +
+ + + diff --git a/src/wisher/list.tsx b/src/wisher/list.tsx new file mode 100644 index 00000000..ccedad9b --- /dev/null +++ b/src/wisher/list.tsx @@ -0,0 +1,61 @@ +import { useState, useEffect } from "react"; +import createRoot from "react-dom/client"; + +export function List() { + const [error, setError] = useState(null); + const [isLoaded, setIsLoaded] = useState(false); + const [items, setItems] = useState([]); + + useEffect(() => { + fetch("https://dummy.restapiexample.com/api/v1/employees") + .then((res) => res.json()) + .then( + (result) => { + setIsLoaded(true); + setItems(result.data); + console.log(result); + }, + // Note: it's important to handle errors here + // instead of a catch() block so that we don't swallow + // exceptions from actual bugs in components. + (error) => { + setIsLoaded(true); + setError(error); + } + ); + }, []); + if (error) { + return <>{error.message}; + } else if (!isLoaded) { + return <>loading...; + } else { + return ( + /* here we map over the element and display each item as a card */ +
+
    + {items.map((item) => ( +
  • +
    +
    +

    {item.employee_name}

    +
      +
    1. + Salary:{" "} + {item.employee_salary} +
    2. +
    3. + Age: {item.employee_age} +
    4. +
    +
    +
    +
  • + ))} +
+
, +
+

{items.print}

+
+ ); + } + } diff --git a/src/wisher/list.txt b/src/wisher/list.txt new file mode 100644 index 00000000..5695d22f --- /dev/null +++ b/src/wisher/list.txt @@ -0,0 +1,57 @@ +import { useState, useEffect } from "react"; +import createRoot from "react-dom/client"; + +export function List() { + const [error, setError] = useState(null); + const [isLoaded, setIsLoaded] = useState(false); + const [items, setItems] = useState([]); + + useEffect(() => { + fetch("https://dummy.restapiexample.com/api/v1/employees") + .then((res) => res.json()) + .then( + (result) => { + setIsLoaded(true); + setItems(result); + }, + // Note: it's important to handle errors here + // instead of a catch() block so that we don't swallow + // exceptions from actual bugs in components. + (error) => { + setIsLoaded(true); + setError(error); + } + ); + }, []); + if (error) { + return <>{error.message}; + } else if (!isLoaded) { + return <>loading...; + } else { + return ( + /* here we map over the element and display each item as a card */ +
+
    + {items.map((item) => ( +
  • +
    +
    +

    {item.emplyee_name}

    +
      +
    1. + Salary:{" "} + {item.employee_salary} +
    2. +
    3. + Age: {item.employee_age} +
    4. +
    +
    +
    +
  • + ))} +
+
+ ); + } + }