app.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import { useState } from 'react'
  2. import copy from 'copy-to-clipboard'
  3. import { CheckIcon, DocumentDuplicateIcon } from '@heroicons/react/24/outline'
  4. import Store from 'electron-store'
  5. import { getCurrentWindow } from '@electron/remote'
  6. import { install } from './install'
  7. import OllamaIcon from './ollama.svg'
  8. const store = new Store()
  9. enum Step {
  10. WELCOME = 0,
  11. CLI,
  12. FINISH,
  13. }
  14. export default function () {
  15. const [step, setStep] = useState<Step>(Step.WELCOME)
  16. const [commandCopied, setCommandCopied] = useState<boolean>(false)
  17. const command = 'ollama run llama2'
  18. return (
  19. <div className='drag'>
  20. <div className='mx-auto flex min-h-screen w-full flex-col justify-between bg-white px-4 pt-16'>
  21. {step === Step.WELCOME && (
  22. <>
  23. <div className='mx-auto text-center'>
  24. <h1 className='mb-6 mt-4 text-2xl tracking-tight text-gray-900'>Welcome to Ollama</h1>
  25. <p className='mx-auto w-[65%] text-sm text-gray-400'>
  26. Let's get you up and running with your own large language models.
  27. </p>
  28. <button
  29. onClick={() => setStep(Step.CLI)}
  30. className='no-drag rounded-dm mx-auto my-8 w-[40%] rounded-md bg-black px-4 py-2 text-sm text-white hover:brightness-110'
  31. >
  32. Next
  33. </button>
  34. </div>
  35. <div className='mx-auto'>
  36. <OllamaIcon />
  37. </div>
  38. </>
  39. )}
  40. {step === Step.CLI && (
  41. <>
  42. <div className='mx-auto flex flex-col space-y-28 text-center'>
  43. <h1 className='mt-4 text-2xl tracking-tight text-gray-900'>Install the command line</h1>
  44. <pre className='mx-auto text-4xl text-gray-400'>&gt; ollama</pre>
  45. <div className='mx-auto'>
  46. <button
  47. onClick={async () => {
  48. await install()
  49. getCurrentWindow().show()
  50. getCurrentWindow().focus()
  51. setStep(Step.FINISH)
  52. }}
  53. className='no-drag rounded-dm mx-auto w-[60%] rounded-md bg-black px-4 py-2 text-sm text-white hover:brightness-110'
  54. >
  55. Install
  56. </button>
  57. <p className='mx-auto my-4 w-[70%] text-xs text-gray-400'>
  58. You will be prompted for administrator access
  59. </p>
  60. </div>
  61. </div>
  62. </>
  63. )}
  64. {step === Step.FINISH && (
  65. <>
  66. <div className='mx-auto flex flex-col space-y-20 text-center'>
  67. <h1 className='mt-4 text-2xl tracking-tight text-gray-900'>Run your first model</h1>
  68. <div className='flex flex-col'>
  69. <div className='group relative flex items-center'>
  70. <pre className='language-none text-2xs w-full rounded-md bg-gray-100 px-4 py-3 text-start leading-normal'>
  71. {command}
  72. </pre>
  73. <button
  74. className={`no-drag absolute right-[5px] px-2 py-2 ${
  75. commandCopied
  76. ? 'text-gray-900 opacity-100 hover:cursor-auto'
  77. : 'text-gray-200 opacity-50 hover:cursor-pointer'
  78. } hover:font-bold hover:text-gray-900 group-hover:opacity-100`}
  79. onClick={() => {
  80. copy(command)
  81. setCommandCopied(true)
  82. setTimeout(() => setCommandCopied(false), 3000)
  83. }}
  84. >
  85. {commandCopied ? (
  86. <CheckIcon className='h-4 w-4 font-bold text-gray-500' />
  87. ) : (
  88. <DocumentDuplicateIcon className='h-4 w-4 text-gray-500' />
  89. )}
  90. </button>
  91. </div>
  92. <p className='mx-auto my-4 w-[70%] text-xs text-gray-400'>
  93. Run this command in your favorite terminal.
  94. </p>
  95. </div>
  96. <button
  97. onClick={() => {
  98. store.set('first-time-run', true)
  99. window.close()
  100. }}
  101. className='no-drag rounded-dm mx-auto w-[60%] rounded-md bg-black px-4 py-2 text-sm text-white hover:brightness-110'
  102. >
  103. Finish
  104. </button>
  105. </div>
  106. </>
  107. )}
  108. </div>
  109. </div>
  110. )
  111. }