{"dependencies":[{"ETag":"DE78044695486D4FEA3FB82B03420A6F","name":"de78044695486d4fea3fb82b03420a6f.json","size":3649139,"type":"json","url":"https://gw.alipayobjects.com/os/Remax/dc33ff5b-3631-47cb-8533-7ef88c918afc/remax-examples-todo/dependencies/herbox/de78044695486d4fea3fb82b03420a6f.json"}],"sourceCode":{"app.json":"{}\n","index.html":"<html>\n <head>\n <link\n href=\"https://necolas.github.io/normalize.css/8.0.1/normalize.css\"\n rel=\"stylesheet\"\n type=\"text/css\"\n />\n <style>\n *,\n :after,\n :before {\n -webkit-box-sizing: border-box;\n box-sizing: border-box;\n }\n body {\n display: flex;\n justify-content: center;\n align-items: center;\n background: #151515;\n }\n img {\n vertical-align: middle;\n border-style: none;\n }\n .demo-preview-wrapper {\n margin: 0 auto;\n }\n .demo-preview-wrapper .demo-preview-header {\n border-radius: 4px 4px 0 0;\n background: -webkit-gradient(\n linear,\n left top,\n left bottom,\n from(rgba(55, 55, 55, 0.98)),\n to(#545456)\n );\n background: -webkit-linear-gradient(rgba(55, 55, 55, 0.98), #545456);\n background: linear-gradient(rgba(55, 55, 55, 0.98), #545456);\n text-align: center;\n }\n .demo-preview-wrapper .demo-preview-header .demo-preview-statbar {\n height: 20px;\n margin-bottom: 4px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .demo-preview-wrapper .demo-preview-header .url-box {\n width: 350px;\n height: 28px;\n line-height: 28px;\n color: #fff;\n background-color: #a2a2a2;\n margin: 0 auto;\n border-radius: 4px;\n white-space: nowrap;\n }\n .code-box-demo-preview {\n position: relative;\n }\n #loading {\n position: absolute;\n background: #ffffff;\n height: 548px;\n width: 375px;\n top: 0;\n padding: 16px;\n }\n </style>\n </head>\n <body>\n <div>\n <div id=\"aside-demo\" class=\"aside-demo\">\n <div style=\"width: 375px; height: 620px;\">\n <div class=\"demo-preview-wrapper\">\n <div class=\"demo-preview-header\">\n <div class=\"demo-preview-statbar\">\n <img\n width=\"350Px\"\n alt=\"presentation\"\n src=\"https://os.alipayobjects.com/rmsportal/VfVHYcSUxreetec.png\"\n style=\"margin: 0px 2px; line-height: 20px\"\n />\n </div>\n <div style=\"height: 40px;\">\n <div class=\"url-box\">\n https://remaxjs.org\n </div>\n </div>\n </div>\n <section class=\"code-box-demo code-box-demo-preview\">\n <iframe\n id=\"demoFrame\"\n name=\"demoFrame\"\n title=\"antd-mobile\"\n src=\"https://e4801-3000.sse.codesandbox.io/pages/index/index\"\n style=\"width: 375px; height: 548px; border: none;\"\n ></iframe>\n <div id=\"loading\">compiling...</div>\n </section>\n </div>\n </div>\n </div>\n </div>\n <script>\n var frame = document.getElementById(\"demoFrame\");\n frame.onload = function() {\n document.getElementById(\"loading\").style.display = \"none\";\n };\n </script>\n </body>\n</html>\n","index.js":"const express = require(\"express\");\nconst fs = require(\"fs\");\nconst app = express();\n\napp.get(\"/\", function(req, res) {\n res.send(fs.readFileSync(\"./index.html\").toString());\n});\n\napp.listen(8000);\n","mini.project.json":"{\n \"miniprogramRoot\": \"dist/ali\",\n \"scripts\": {\n \"beforeCompile\": \"npm run dev -- ali\",\n \"beforePreview\": \"npm run build -- ali\",\n \"beforeUpload\": \"npm run build -- ali\"\n },\n \"exclude\": [\n \"src/**\",\n \"node_modules\",\n \"node_modules/**\",\n \"babel.config.js\",\n \"package-lock.json\",\n \"package.json\",\n \"remax.config.js\",\n \"app.json\"\n ],\n \"precompileWatch\": {\n \"selfWatch\": true,\n \"restart\": true,\n \"exclude\": [\"dist/**\", \"*.md\"],\n \"ignoreBuiltInExts\": false\n }\n}\n","package.json":"{\n \"name\": \"one\",\n \"version\": \"1.0.0\",\n \"main\": \"index.js\",\n \"author\": \"Caihuanyu <eterlf41@gmail.com>\",\n \"license\": \"MIT\",\n \"scripts\": {\n \"start:remax\": \"remax build -w -t web\",\n \"start:server\": \"node ./index.js\",\n \"start\": \"concurrently \\\"npm run start:remax\\\" \\\"npm run start:server\\\"\",\n \"herbox\": \"herbox pub --id=remax-examples-todo --name=\\\"Remax demo\\\" --preCompiler=remax --prod\"\n },\n \"dependencies\": {\n \"clsx\": \"^1.1.0\",\n \"react\": \"^16.13.1\",\n \"react-dom\": \"^16.13.1\",\n \"remax\": \"2.0.0\"\n },\n \"devDependencies\": {\n \"@types/react\": \"^16.9.23\",\n \"concurrently\": \"^5.2.0\",\n \"cross-env\": \"^7.0.2\",\n \"dotenv\": \"^8.2.0\",\n \"express\": \"^4.17.1\"\n }\n}\n","remax.config.js":"module.exports = {\n output: 'dist/' + process.env.REMAX_PLATFORM,\n one: true,\n};\n","sandbox.config.json":"{\n \"template\": \"node\"\n}\n","src/api/index.ali.ts":"export { chooseImage, navigateTo, navigateBack } from 'remax/ali';\n\nexport const login = () => {};\nexport const getUserInfo = () => {};\n","src/api/index.toutiao.ts":"export {\n chooseImage,\n navigateTo,\n navigateBack,\n login,\n getUserInfo\n} from 'remax/toutiao';\n","src/api/index.ts":"export declare function chooseImage(): void;\nexport declare function getUserInfo(): void;\nexport declare function login(params: any): Promise<any>;\n","src/api/index.web.ts":"export function login() {}\nexport function getUserInfo() {}\nexport const chooseImage = () => {\n alert('Not implement yet.');\n};\n","src/api/index.wechat.ts":"export {\n chooseImage,\n navigateTo,\n navigateBack,\n getUserInfo,\n login\n} from 'remax/wechat';\n","src/app.config.js":"const pages = ['pages/index/index', 'pages/new/index'];\n\nconst title = 'Todo Demo';\n\nmodule.exports.ali = {\n pages,\n window: {\n defaultTitle: title,\n },\n};\n\nmodule.exports.web = {\n pages,\n title,\n};\n","src/app.css":".page {\n display: flex;\n flex-direction: column;\n flex: 1;\n background-color: #323239;\n height: 100vh;\n width: 100%;\n}\n","src/app.tsx":"import * as React from 'react';\nimport './app.css';\n\ninterface Item {\n id: string;\n text: string;\n completed: boolean;\n}\n\ninterface ItemContext {\n items: Item[];\n setItems: (items: Item[]) => void;\n}\n\nexport const TodoContext = React.createContext<ItemContext>({\n items: [],\n setItems: () => {},\n});\n\nconst App = ({ children }: React.PropsWithChildren<{}>) => {\n const [items, setItems] = React.useState([\n { id: '1', text: 'Learning Javascript', completed: true },\n { id: '2', text: 'Learning ES2016', completed: true },\n { id: '3', text: 'Learning Remax', completed: false },\n ]);\n\n return (\n <TodoContext.Provider\n value={{\n items,\n setItems,\n }}\n >\n {children}\n </TodoContext.Provider>\n );\n};\n\nexport default App;\n","src/components/AddButton/index.css":".add-button {\n display: inline-block;\n background: none;\n color: #fff;\n border: none;\n width: 300px;\n}\n\n.add-icon {\n font-size: 52px;\n color: #00ffd6;\n margin-right: 10px;\n}\n","src/components/AddButton/index.tsx":"import * as React from 'react';\nimport { Button, Text, TapEvent } from 'remax/one';\nimport './index.css';\n\ninterface Props {\n onTap: (event: TapEvent) => void;\n text: string;\n}\n\nconst AddButton = ({ onTap, text }: React.PropsWithChildren<Props>) => {\n return (\n <Button className=\"add-button\" hoverClassName=\"none\" onTap={onTap}>\n <Text className=\"add-icon\">+</Text>\n <Text>{text}</Text>\n </Button>\n );\n};\n\nexport default AddButton;\n","src/components/Checkbox/index.ali.tsx":"import { Checkbox } from 'remax/ali';\n\nexport default Checkbox;\n","src/components/Checkbox/index.tsx":"import * as React from 'react';\nimport { Context } from '../CheckboxGroup/index.web';\n\ninterface CheckboxProps {\n value: string;\n checked?: boolean;\n className?: string;\n}\n\nconst CheckboxConsumer: React.FC<CheckboxProps> = ({\n checked,\n value,\n className,\n children,\n}) => (\n <Context.Consumer>\n {({ toggle }) => (\n <Checkbox\n checked={checked}\n value={value}\n className={className}\n children={children}\n toggle={toggle}\n />\n )}\n </Context.Consumer>\n);\n\nconst Checkbox: React.FC<\n CheckboxProps & { toggle: (value: any, checked: boolean) => void }\n> = ({ checked, value, className, toggle }) => {\n React.useEffect(() => {\n toggle(value, checked ?? false);\n }, []);\n\n return (\n <input\n type=\"checkbox\"\n checked={checked}\n value={value}\n className={className}\n onChange={() => toggle(value, !checked)}\n />\n );\n};\n\nexport default CheckboxConsumer;\n","src/components/CheckboxGroup/index.ali.tsx":"import { CheckboxGroup } from 'remax/ali';\n\nexport default CheckboxGroup;\n","src/components/CheckboxGroup/index.tsx":"// 此处应该定义同构化类型定义,本例同构化向微信平台对齐\nimport { CheckboxGroupProps } from 'remax/wechat';\n\ndeclare const CheckboxGroup: React.ComponentType<CheckboxGroupProps>;\n\nexport default CheckboxGroup;\n","src/components/CheckboxGroup/index.web.tsx":"import * as React from 'react';\n\ninterface CheckboxGroupProps {\n onChange?: (e: any) => void;\n className?: string;\n}\n\nexport const Context = React.createContext<{\n value: string[];\n toggle: (value: any, checked: boolean) => void;\n}>({\n value: [],\n toggle: () => void 0,\n});\n\nconst CheckboxGroup: React.FC<CheckboxGroupProps> = ({\n onChange,\n className,\n children,\n}: React.PropsWithChildren<CheckboxGroupProps>) => {\n const [value, setValue] = React.useState<string[]>([]);\n\n React.useEffect(() => {\n if (typeof onChange === 'function') {\n onChange({ detail: { value } });\n }\n }, [value]);\n\n function handleToggle(value: any, checked: boolean) {\n setValue((values) => {\n let newValues = values;\n if (checked) {\n newValues = Array.from(new Set([...values, value]));\n } else {\n newValues = values.filter((i) => i !== value);\n }\n\n return newValues;\n });\n }\n\n return (\n <Context.Provider\n value={{\n value,\n toggle: handleToggle,\n }}\n >\n <div className={className}>{children}</div>\n </Context.Provider>\n );\n};\n\nexport default CheckboxGroup;\n","src/components/LoginButton/index.css":".login-button {\n display: inline-block;\n background: none;\n border: none;\n width: auto;\n height: auto;\n\n}\n","src/components/LoginButton/index.tsx":"import * as React from 'react';\nimport { Button } from 'remax/one';\nimport { getUserInfo, login as loginAPI } from '@/api';\nimport './index.css';\n\ninterface Props {\n login: (e: any) => void;\n}\n\nconst LoginButton = ({ login, children }: React.PropsWithChildren<Props>) => {\n const handleTTLogin = async () => {\n const { isLogin } = await loginAPI({ force: true });\n\n if (isLogin) {\n const res = await getUserInfo();\n\n login(res);\n }\n };\n\n return (\n <Button\n className=\"login-button\"\n hoverClassName=\"none\"\n ali-onTap={login}\n web-onTap={login}\n toutiao-bindtap={handleTTLogin}\n wechat-open-type=\"getUserInfo\"\n wechat-bindgetuserinfo={login}\n >\n {children}\n </Button>\n );\n};\n\nexport default LoginButton;\n","src/hooks/useUserInfo/index.ali.ts":"import * as React from 'react';\nimport { getAuthCode, getAuthUserInfo } from 'remax/ali';\n\nexport default function useUserInfo(): [any, () => void] {\n const [userInfo, setUserInfo] = React.useState(null);\n\n async function login() {\n await getAuthCode({\n scopes: ['auth_user'],\n });\n const res: any = await getAuthUserInfo();\n setUserInfo(res);\n }\n\n return [userInfo, login];\n}\n","src/hooks/useUserInfo/index.ts":"import * as React from 'react';\n\nexport default function useUserInfo() {\n const [user, setUser] = React.useState<any>(\n JSON.parse(window.localStorage.getItem('user') || 'null')\n );\n function login() {\n const user = {\n nickName: 'remax visitor',\n avatar: `https://api.adorable.io/avatars/285/remax@${new Date().getTime()}.png`,\n };\n\n window.localStorage.setItem('user', JSON.stringify(user));\n setUser(user);\n }\n\n return [user, login];\n}\n","src/pages/index/index.config.js":"const title = 'New Todo';\n\nmodule.exports.web = {\n title,\n};\n\nmodule.exports.alipay = {\n defaultTitle: title,\n};\n","src/pages/index/index.css":".user {\n display: flex;\n flex-shrink: 0;\n padding: 30px;\n color: #fff;\n flex-direction: column;\n align-items: center;\n}\n\n.login-tip {\n display: inline-block;\n font-size: 20px;\n color: #999;\n}\n\n.avatar {\n width: 130px;\n height: 130px;\n border-radius: 50%;\n background-color: #fff;\n align-self: center;\n}\n\n.nickname {\n padding-top: 40px;\n text-align: center;\n font-size: 40px;\n font-weight: 100;\n}\n\n.todo-items {\n flex-grow: 1;\n font-size: 34px;\n padding: 50px 120px;\n color: #0effd6;\n overflow: auto;\n}\n\n.todo-items-group {\n display: flex;\n flex-direction: column;\n}\n\n.todo-item {\n position: relative;\n margin-bottom: 50px;\n padding-left: 80px;\n line-height: 70px;\n height: 80px;\n box-sizing: border-box;\n border: 2px solid rgb(14, 255, 214);\n border-radius: 100px;\n overflow: hidden;\n text-overflow: ellipsis;\n transition: border 0.2s;\n}\n\n.todo-item:last-child {\n margin-bottom: 0;\n}\n\n.todo-item::before {\n content: '';\n position: absolute;\n left: 12px;\n margin-right: 20px;\n width: 45px;\n height: 45px;\n background-color: rgba(14, 222, 255, 0.3);\n border-radius: 50%;\n top: 50%;\n transform: translateY(-50%);\n\n transition: background-color 0.2s;\n}\n\n.todo-item::after {\n content: '';\n position: absolute;\n left: 29px;\n width: 8px;\n height: 18px;\n top: 50%;\n transform: translateY(-60%) rotate(38deg);\n border: 4px solid #fff;\n border-width: 0 4px 4px 0;\n opacity: 0;\n\n transition: opacity 0.2s;\n}\n\n.todo-item-checkbox {\n display: none;\n}\n\n.checked .todo-item-text {\n text-decoration: line-through;\n color: #1aa0b8;\n}\n\n.checked.todo-item {\n border: 2px solid rgba(14, 222, 255, 0.2);\n}\n\n.checked.todo-item::before {\n background-color: rgba(14, 222, 255, 0.2);\n}\n\n.checked.todo-item::after {\n opacity: 1;\n}\n\n.todo-footer {\n flex-shrink: 0;\n padding: 20px 0 100px;\n font-size: 48px;\n font-weight: 200;\n text-align: center;\n}\n","src/pages/index/index.tsx":"import * as React from 'react';\nimport { View, Image, Label, Text, navigateTo } from 'remax/one';\nimport clsx from 'clsx';\nimport useUserInfo from '@/hooks/useUserInfo';\nimport AddButton from '@/components/AddButton';\nimport LoginButton from '@/components/LoginButton';\nimport Checkbox from '@/components/Checkbox';\nimport CheckboxGroup from '@/components/CheckboxGroup';\nimport { TodoContext } from '@/app';\nimport './index.css';\n\nexport default () => {\n const [user, login] = useUserInfo();\n const todo = React.useContext(TodoContext);\n\n const handleAdd = () => {\n navigateTo({ url: '../new/index' });\n };\n\n const handleComplete = (event: any) => {\n const checkedItems = event.detail.value;\n const items = todo.items.map((item) => ({\n ...item,\n completed: !!checkedItems.find((id: string) => item.id === id),\n }));\n\n todo.setItems(items);\n };\n\n return (\n <View className=\"page\">\n <View className=\"user\">\n <LoginButton login={login}>\n <Image className=\"avatar\" src={user ? user.avatar : 'https://gw.alipayobjects.com/mdn/rms_b5fcc5/afts/img/A*6ECQQKDLLykAAAAAAAAAAABkARQnAQ'} />\n </LoginButton>\n <View className=\"nickname\">\n {user ? user.nickName + \"'s\" : 'My'} Todo List\n {!user && <Text className=\"login-tip\">(Tap to login ↑)</Text>}\n </View>\n </View>\n\n <View className=\"todo-items\">\n <CheckboxGroup className=\"todo-items-group\" onChange={handleComplete}>\n {todo.items.map((item) => (\n <Label\n key={item.id}\n className={clsx('todo-item', {\n checked: item.completed,\n })}\n >\n <Checkbox\n className=\"todo-item-checkbox\"\n value={item.id}\n checked={item.completed}\n />\n <Text className=\"todo-item-text\">{item.text}</Text>\n </Label>\n ))}\n </CheckboxGroup>\n </View>\n\n <View className=\"todo-footer\">\n <AddButton text=\"Add Todo\" onTap={handleAdd} />\n </View>\n </View>\n );\n};\n","src/pages/new/index.config.js":"const title = 'New Todo';\n\nmodule.exports = {\n navigationBarTitleText: title,\n};\n","src/pages/new/index.css":".add-todo {\n padding: 40px;\n flex-grow: 1;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.add-todo-input {\n display: block;\n font-size: 50px;\n font-weight: 100;\n padding: 5px 5px;\n background: none;\n border: none;\n border-bottom: 1px solid #dfdfdf;\n color: #0effd6;\n width: 100%;\n}\n\n.todo-footer {\n padding: 20px 0 100px;\n font-size: 48px;\n font-weight: 200;\n text-align: center;\n}\n","src/pages/new/index.tsx":"import * as React from 'react';\nimport { View, Input, navigateBack } from 'remax/one';\nimport AddButton from '@/components/AddButton';\nimport { TodoContext } from '@/app';\nimport './index.css';\n\nexport default () => {\n const todo = React.useContext(TodoContext);\n const [text, setText] = React.useState('');\n\n const handleAdd = () => {\n const items = todo.items.concat([\n {\n id: Date.now().toString(),\n text,\n completed: false,\n },\n ]);\n\n todo.setItems(items);\n\n navigateBack();\n };\n\n return (\n <View className=\"page\">\n <View className=\"add-todo\">\n <Input\n className=\"add-todo-input\"\n placeholder=\"What needs to be done?\"\n onInput={(e) => {\n setText(e.target.value);\n\n return e.target.value;\n }}\n maxLength={140}\n value={text}\n />\n </View>\n\n <View className=\"todo-footer\">\n <AddButton text=\"Add Todo\" onTap={handleAdd} />\n </View>\n </View>\n );\n};\n","tsconfig.json":"{\n \"compilerOptions\": {\n \"target\": \"ESNext\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"node\",\n \"strict\": true,\n \"esModuleInterop\": true,\n \"jsx\": \"preserve\",\n \"rootDir\": \"src\",\n \"baseUrl\": \"./\",\n \"paths\": {\n \"@/*\": [\"./src/*\"]\n },\n \"lib\": [\"DOM\"]\n },\n \"include\": [\"src/**/*\", \"typings/**/*\"]\n}\n","typings/index.d.ts":"declare module '*.png';\n"},"dist":[{"ETag":"16A3B0A8CAEE657C0C6285300868A8D7","name":"16a3b0a8caee657c0c6285300868a8d7.json","size":616555,"type":"json","url":"https://gw.alipayobjects.com/os/Remax/11c2d952-afc2-4d7b-93f3-28c48fe003e0/remax-examples-todo/dist/herbox/16a3b0a8caee657c0c6285300868a8d7.json"}],"name":"Remax demo","preCompiler":"remax","buildVersion":"0.72.7","remaxVersion":"2.0.3","component2":false,"css2":false}